[TOC]
## 一、索引文檔
文檔通過 index API 被索引--使數據可以被存儲和搜索。,文檔通過其 _index、 _type 、 _id 唯一確定。可以自己提供一個 _id ,或者也使用 index API 生成一個。
### 1.1、使用自己的 ID
如果文檔有自然的標識符(例如user_account字段或者其他值表示文檔),就可以提供自己的_id,使用這種形式的indexAPI:
```shell
PUT /{index}/{type}/{id}
{
"field": "value",
...
}
```
例如索引叫做 “website” ,類型叫做 “blog” , ID 是 “123” ,那么這個索引請求就像這樣:
```shell
curl -H "Content-Type: application/json" -XPUT localhost:9200/website/blog/123 -d '
{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}'
```
Elasticsearch 的響應:
```json
{
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 1,
"result": "created"
}
```
響應指出請求的索引已經被成功創建,這個索引中包含 _index 、 _type 和 _id 元數據,以及一個新元素: _version 。Elasticsearch中 每個文檔都有版本號,每當文檔變化(包括刪除)都會使 _version 增加。
### 1.2、自增 ID
如果數據沒有自然 ID,可以讓 Elasticsearch 自動生成。請求結構發生了變化: PUT 方法(“在這個 URL 中存儲文檔”,可以認為是更新) 變成了 POST 方法(“在這個類型下存儲文檔”,符合 POST 新增的語義)。
URL 現在只包含 _index 和 _type 兩個字段:
```shell
curl -H "Content-Type: application/json" -XPOST localhost:9200/website/blog -d '
{
"title": "My second blog entry",
"text": "Still trying this out...",
"date": "2014/01/01"
}'
```
響應內容與剛才類似,只有 _id 字段變成了自動生成的值:
```json
{
"_index": "website",
"_type": "blog",
"_id": "zqIzcm0BgOKExS3TRFoX",
"_version": 1,
"result": "created"
}
```
### 1.3、創建一個新文檔
當索引一個文檔,如何確定是完全創建了一個新的還是覆蓋了一個已經存在的呢?
_index 、 _type 、 _id 三者唯一確定一個文檔。所以要想保證文檔是新加入的,最簡單的方式是使用 POST 方法讓 Elasticsearch 自動生成唯一 _id :
```shell
POST /website/blog/
```
如果想使用自定義的 _id ,必須告訴 Elasticsearch 應該在 _index 、 _type 、 _id 三者都不同時才接受請求。為了做到這點有兩種方法:
1. 第一種方法使用 op_type 查詢參數:
```shell
PUT /website/blog/123?op_type=create
```
2. 第二種方法是在 URL 后加 /_create 做為端點:
```shell
PUT /website/blog/123/_create
```
如果成功創建了一個新文檔,Elasticsearch 將返回正常的元數據且響應狀態碼是 201 Created 。
如果包含相同的 _index 、 _type 和 _id 的文檔已經存在,Elasticsearch 將返
回 409 Conflict 響應狀態碼,并提示 `document already exists`。
## 二、檢索文檔
### 2.1、檢索文檔的全部
想要從 Elasticsearch 中獲取文檔,使用同樣的 _index、 _type、 _id,但是 HTTP 方法改為 GET (在任意的查詢字符串中增加 pretty 參數,會讓 Elasticsearch 美化輸出 (pretty-print) JSON 響應以便更加容易閱讀):
```shell
curl -XGET localhost:9200/website/blog/123?pretty
```
響應包含了元數據節點,增加了 _source 字段,它包含了在創建索引時發送給Elasticsearch 的原始文檔:
```json
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"found" : true,
"_source" : {
"title" : "My first blog entry",
"text" : "Just trying this out...",
"date" : "2014/01/01"
}
}
```
### 2.2、檢索文檔的一部分
通常,GET 請求將返回文檔的全部,存儲在 _source 參數中。但是可能感興趣的字段只是title。請求個別字段可以使用 _source 參數。多個字段可以使用逗號分隔:
```shell
curl -i -XGET localhost:9200/website/blog/123?_source=title,text
```
-i 可以顯示請求頭,_source 字段現在只包含請求的字段,過濾了date字段:
```json
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-length: 148
{
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 1,
"found": true,
"_source": {
"text": "Just trying this out...",
"title": "My first blog entry"
}
}
```
或者只想得到 _source 字段而不要其他的元數據,可以這樣請求:
```shell
curl -XGET localhost:9200/website/blog/123/_source?pretty
```
它僅僅返回:
```json
{
"title" : "My first blog entry",
"text" : "Just trying this out...",
"date" : "2014/01/01"
}
```
### 2.3、檢查文檔是否存在
如果想做的只是檢查文檔是否存在,使用 HEAD 方法來代替 GET 。 HEAD 請求不會返回響應體,只有HTTP頭:
```shell
curl --head http://localhost:9200/website/blog/123
```
Elasticsearch 將會返回 200 OK 狀態如果文檔存在:
```json
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-length: 188
```
### 2.4、檢索多個文檔
檢索多個文檔依舊非常快。合并多個請求可以避免每個請求單獨的網絡開銷。如果需要從 Elasticsearch 中檢索多個文檔,相對于一個一個的檢索,更快的方式是在一個請求中使用 multi-get 或者 mget API。
mgetAPI 參數是一個 docs 數組,數組的每個節點定義一個文檔的 _index、 _type、 _id 元數據。如果只想檢索一個或幾個確定的字段,也可以定義一個 _source 參數:
```shell
curl -H "Content-Type: application/json" -XPOST localhost:9200/_mget?pretty -d '
{
"docs": [
{
"_index": "website",
"_type": "blog",
"_id": 1
},
{
"_index": "website",
"_type": "blog",
"_id": 2,
"_source": "views"
}
]
}'
```
響應體也包含一個 docs 數組,每個文檔還包含一個響應,它們按照請求定義的順序排列。
```json
{
"docs" : [
{
"_index" : "website",
"_type" : "blog",
"_id" : "1",
"found" : false
},
{
"_index" : "website",
"_type" : "blog",
"_id" : "2",
"_version" : 3,
"found" : true,
"_source" : {
"views" : 3
}
}
]
}
```
如果想檢索的文檔在同一個 `_index`中(甚至在同一個 `_type` 中),就可以在 URL 中定義一個默認的 `/_index` 或者 `/_index/_type` :
```shell
curl -H "Content-Type: application/json" -XPOST localhost:9200/website/blog/_mget?pretty -d '
{
"docs": [
{
"_id": 1
},
{
"_type": "pageviews", "_id": 1
}
]
}'
```
如果所有文檔具有相同 _index 和 _type,可以通過簡單的 ids 數組來代替完整的 docs 數組:
```shell
curl -H "Content-Type: application/json" -XPOST localhost:9200/website/blog/_mget?pretty -d '
{
"ids": ["2", "1"]
}'
```
## 三、更新文檔
### 3.1、整體文檔更新
文檔在 Elasticsearch 中是不可變的--不能修改他們。如果需要更新已存在的文檔,可以重建索引(reindex),或者替換掉它。
```shell
curl -H "Content-Type: application/json" -XPUT localhost:9200/website/blog/123?pretty -d '
{
"title": "My first blog entry",
"text": "I am starting to get the hang of this...",
"date": "2014/01/02"
}'
```
在響應中,可以看到 Elasticsearch 把 _version 增加了:
```json
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 2,
"result" : "updated"
}
```
在內部,Elasticsearch 已經標記舊文檔為刪除并添加了一個完整的新文檔。舊版本文檔不會立即消失,但也不能去訪問它。Elasticsearch 會在繼續索引更多數據時清理被刪除的文檔。
### 3.2、指定版本更新文檔
Elasticsearch 是分布式的。當文檔被創建、更新或刪除,文檔的新版本會被復制到集群的其它節點。Elasticsearch 即是同步的又是異步的,意思是這些復制請求都是平行發送的,并無序(out of sequence)的到達目的地。這就需要一種方法確保老版本的文檔永遠不會覆蓋新的版本。
執行 index 、 get 、 delete 請求時,每個文檔都有一個 _version 號碼,這個號碼在文檔被改變時加一。Elasticsearch 使用這個 _version 保證所有修改都被正確排序。當一個舊版本出現在新版本之后,它會被簡單的忽略。
利用 _version 的這一優點確保數據不會因為修改沖突而丟失。可以指定文檔的 version 來做想要的更改。如果那個版本號不是現在的,請求就失敗了。
創建一個新的博文:
```shell
curl -H "Content-Type: application/json" -XPUT localhost:9200/website/blog/1/_create -d '
{
"title": "My first blog entry",
"text": "Just trying this out..."
}'
```
首先檢索文檔:
```shell
curl -XGET localhost:9200/website/blog/1?pretty
```
響應體包含相同的 _version 是 1:
```json
{
"_index" : "website",
"_type" : "blog",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : {
"title" : "My first blog entry",
"text" : "Just trying this out..."
}
}
```
現在,當通過重新索引文檔保存修改時,這樣指定了 version 參數,只希望文檔的_version 是 1 時更新才生效:
```shell
curl -H "Content-Type: application/json" -XPUT localhost:9200/website/blog/1?version=1 -d '
{
"title": "My first blog entry",
"text": "Starting to get the hang of this..."
}'
```
請求成功,響應體_version 已經增加到 2 :
```json
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 2,
"result": "updated"
}
```
如果重新運行相同的索引請求,依舊指定 version=1,Elasticsearch 將返回 409
Conflict 狀態的 HTTP 響應。
### 3.3、文檔局部更新
通過檢索,修改,然后重建整文檔的索引方法來更新文檔。
使用 update API,可以使用一個請求來實現局部更新,用于添加新字段或者更新已有字段。
文檔是不可變的--它們不能被更改,只能被替換。 update API 必須遵循相同的規則。表面看來,似乎是局部更新了文檔的位置,內部卻是像之前說的一樣簡單使用update API 處理相同的檢索-修改-重建索引流程,也減少了其他進程可能導致沖突的修改。
最簡單的 update 請求表單接受一個局部文檔參數 doc ,它會合并到現有文檔中--對象合并在一起,存在的標量字段被覆蓋,新字段被添加。
可以使用以下請求為博客添加一個 tags 字段和一個 views 字段:
```shell
curl -H "Content-Type: application/json" -XPOST localhost:9200/website/blog/1/_update?pretty -d '
{
"doc": {
"tags": [
"testing"
],
"views": 0
}
}'
```
如果請求成功,將看到類似 index 請求的響應結果:
```json
{
"_index" : "website",
"_type" : "blog",
"_id" : "1",
"_version" : 3,
"result" : "updated"
```
檢索文檔文檔顯示被更新的 _source 字段:
```json
{
"_index" : "website",
"_type" : "blog",
"_id" : "1",
"_version" : 3,
"found" : true,
"_source" : {
"title" : "My first blog entry",
"text" : "Starting to get the hang of this...",
"views" : 0,
"tags" : [
"testing"
]
}
}
```
### 3.4、使用腳本局部更新
當 API 不能滿足要求時,Elasticsearch 允許使用腳本實現自己的邏輯。
默認的腳本語言是 Groovy,一個快速且功能豐富的腳本語言,語法類似于Javascript。
腳本能夠使用 update API 改變 `_source` 字段的內容,它在腳本內部以 `ctx._source` 表示。
可以使用腳本增加博客的 views 數量:
```shell
curl -H "Content-Type: application/json" -XPOST localhost:9200/website/blog/1/_update?pretty -d '
{
"script": "ctx._source.views+=1"
}'
```
還可以使用腳本增加一個新標簽到 tags 數組中:
```json
curl -H "Content-Type: application/json" -XPOST localhost:9200/website/blog/1/_update?pretty -d '
{
"script": {
"source": "ctx._source.tags.add(params.new_tag)",
"params": {
"new_tag": "search"
}
}
}'
```
### 3.5、更新可能不存在的文檔
要在 Elasticsearch 中存儲瀏覽量計數器。每當有用戶訪問頁面,增加這個頁面的瀏覽量。但如果這是個新頁面,并不確定這個計數器存在與否,當試圖更新一個
不存在的文檔,更新將失敗。
可以使用 upsert 參數定義文檔來使其不存在時被創建。
```shell
curl -H "Content-Type: application/json" -XPOST localhost:9200/website/blog/2/_update?pretty -d '
{
"script": "ctx._source.views+=1",
"upsert": {
"views": 1
}
}'
```
第一次執行這個請求, upsert 值被索引為一個新文檔,初始化 views 字段為 1,接下來文檔已經存在,所以 script 被更新代替,增加 views 數量。
對于多用戶的局部更新,兩個進程都要增加頁面瀏覽量,增加的順序可以不關心,如果沖突發生,可以重新嘗試更新既可。
可以通過 retry_on_conflict 參數設置重試次數來自動完成,這樣 update 操作將會在發生錯誤前重試--這個值默認為0。
```shell
curl -H "Content-Type: application/json" -XPOST localhost:9200/website/blog/2/_update?retry_on_conflict=5 -d '
{
"script": "ctx._source.views+=1",
"upsert": {
"views": 0
}
}'
```
### 3.6、更新時的批量操作
就像 mget 允許一次性檢索多個文檔一樣, bulk API允許使用單一請求來實現多個文檔的 create、 index、 update 或 delete。這對索引類似于日志活動這樣的數據流非常有用,它們可以以成百上千的數據為一個批次按序進行索引。
bulk 請求體如下,它有一點不同尋常:
```json
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
...
```
這種格式類似于用 "\n" 符號連接起來的一行一行的 JSON 文檔流(stream)。
兩個重要的點需要注意:
這種格式類似于用 "\n" 符號連接起來的一行一行的 JSON 文檔流(stream)。
兩個重要的點需要注意:
- 每行必須以 "\n" 符號結尾,包括最后一行。這些都是作為每行有效的分離而做的標記。
- 每一行的數據不能包含未被轉義的換行符,它們會干擾分析--這意味著 JSON 不能被美化打印。
#### 3.6.1、action/metadata
這一行定義了文檔行為(what action)發生在哪個文檔(which document)之上。
行為(action)必須是以下幾種:
- create:當文檔不存在時創建
- index:創建新文檔或替換已有文檔
- update:局部更新文檔
- delete:刪除一個文檔
在索引、創建、更新或刪除時必須指定文檔的`_index、 _type、 _id`這些元數據(metadata)。
例如刪除請求看起來像這樣:
```json
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
```
#### 3.6.2、請求體(request body)
由文檔的 `_source` 組成--文檔所包含的一些字段以及其值。
- 它被 index 和 create 操作所必須,這是有道理的:必須提供文檔用來索引
- 這些還被 update 操作所必需,而且請求體的組成應該與 update API( doc, upsert, script 等等)一致
- 刪除操作不需要請求體(request body)
```json
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "My first blog post" }
```
#### 3.6.3、bulk 請求
為了將這些放在一起,bulk 請求表單是這樣的:
```json
curl -H "Content-Type: application/json" -XPOST localhost:9200/_bulk?pretty -d '
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "My first blog post" }
{ "index": { "_index": "website", "_type": "blog" }}
{ "title": "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 5}}
{ "doc" : {"title" : "My updated blog post"}}
'
```
Elasticsearch 響應包含一個 items 數組,它羅列了每一個請求的結果,結果的順序與我們請求的順序相同:
```json
{
"took" : 1069,
"errors" : false,
"items" : [
{
"delete" : {
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"result" : "not_found",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 404
}
},
{
"create" : {
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 2,
"result" : "created",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1,
"status" : 201
}
},
{
"index" : {
"_index" : "website",
"_type" : "blog",
"_id" : "_--jcm0Bsjr6Q3VWz7kw",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 201
}
},
{
"update" : {
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 3,
"result" : "updated",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1,
"status" : 200
}
}
]
}
```
每個子請求都被獨立的執行,所以一個子請求的錯誤并不影響其它請求。如果任何一個請求失敗,頂層的 error 標記將被設置為 true,然后錯誤的細節將在相應的請求中被報告。
這些說明 bulk 請求不是原子操作--它們不能實現事務。每個請求操作時分開的,所以每個請求的成功與否不干擾其它操作。
為每個文檔指定相同的元數據是多余的。就像 mget API,bulk 請求也可以在 URL 中使用 `/_index` 或 `/_index/_type` :
```shell
POST /website/_bulk
{ "index": { "_type": "log" }}
{ "event": "User logged in" }
```
依舊可以覆蓋元數據行的 `_index` 和 `_type` ,在沒有覆蓋時它會使用 URL 中的值作為默認值:
```json
POST /website/log/_bulk
{ "index": {}}
{ "event": "User logged in" }
{ "index": { "_type": "blog" }}
{ "title": "Overriding the default type" }
```
## 四、刪除文檔
刪除文檔的語法模式與之前基本一致,只不過要使用 DELETE 方法:
```shell
curl -XDELETE localhost:9200/website/blog/123
```
如果文檔被找到,Elasticsearch 將返回 200 OK 狀態碼和以下響應體。注意 _version 數字已經增加了:
```json
{
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 3,
"result": "deleted"
```
作者:w1992wishes
鏈接:https://www.jianshu.com/p/dfc29826f793
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
- 簡介
- 更新說明
- 其他作品
- 第一部分 Java框架基礎
- 第一章 Java基礎
- 多線程實戰
- 嘗試一下Guava帶返回值的多線程處理類ListenableFuture
- LocalDate和Date有什么區別
- JAVA8接口增強實踐
- 第二章 Spring框架基礎
- MVC究竟是個啥?
- @ApiImplicitParam
- 七種方式,教你在SpringBoot初始化時搞點事情!
- Spring事務狀態
- maven
- Mybatis小總結
- mybatis-plus的使用
- 第三章 SpringSecurity實戰
- 基于SpringSecurity+jwt的用戶認證
- spring-security-oauth2
- 第四章 數據庫
- mysql
- mysql授權
- mysql數據庫三個關鍵性能指標--TPS\QPS\IOPS
- 梳理一下那些年Mysql的弱語法可能會踩的坑
- 關于Mysql的“字符串”數值的轉換和使用
- 憑這一文咱把事務講透
- Mysql性能優化
- 查詢性能優化
- 不常用的一些語法
- elasticsearch
- elasticsearch文檔操作
- 索引的基本操作
- java操作ElaticSearch
- elasticsearch中的各種查詢
- DB與ES混合應用可能存在的問題及解決方案探索
- 使用es必須要知道的一些知識點:索引篇
- Es中的日期操作
- MongoDB
- 入門篇(了解非關系型數據庫 NoSQL - MongoDB)
- 集群分片 (高級篇)
- 互聯網大廠的建表規范
- 第五章 中間件
- nginx
- nginx動靜分離配置,這個雷你踩過嗎?
- Canal
- Sharding-jdbc
- 水平分庫實踐
- kafka
- 第六章 版本管理
- git
- Not currently on any branch 情況提交版本
- 第七章 IO編程
- 第八章 JVM實戰調優
- jvisualvm
- jstat
- 第二部分 高級項目實戰篇
- 第一章 微信開發實戰
- 第二章 文件處理
- 使用EasyExcel處理導入導出
- 第三章 踩坑指南
- 郵件發送功能
- 第三部分 架構實戰篇
- 第一章 架構實戰原則
- 接口防止重復調用的一種方案
- 第二章 高并發緩存一致性管理辦法
- 第三章 異地多活場景下的數據同步之道
- 第四章 用戶體系
- 集成登錄
- auth-sso的管理
- 第五章 分庫分表場景
- 第六章 秒殺與高并發
- 秒殺場景
- 第七章 業務中臺
- 中臺的使用效果是怎樣的?
- 通用黑白名單方案
- 第八章 領域驅動設計
- 第十一章 微服務實戰
- Nacos多環境管理之道
- logback日志雙寫問題及Springboot項目正確的啟動方式
- 第四部分 優雅的代碼
- java中的鏈式編程
- 面向對象
- 開發原則
- Stream操作案例分享
- 注重性能的代碼
- 第五部分 談談成長
- 新手入門指北
- 不可不知的調試技巧
- 構建自己的知識體系
- 我是如何做筆記的
- 有效的提問
- 謹防思維定勢
- 學會與上級溝通
- 想清楚再去做
- 碎片化學習
- 第六部分 思維導圖(付費)
- 技術基礎篇
- 技術框架篇
- 數據存儲篇
- 項目實戰篇
- 第七部分 吾愛開源
- 7-1 麻雀聊天
- 項目啟動
- 前端登錄無請求問題解決
- websocket測試
- 7-2 ocp微服務框架
- evm框架集成
- 項目構建與集成
- zentao-center
- 二次開發:初始框架的搭建
- 二次開發:增加細分菜單、權限到應用
- 7-3 書棧網
- 項目啟動
- 源碼分析
- 我的書架
- 文章發布機制
- IM
- 第八章 團隊管理篇
- 大廠是怎么運作的
- 第九章 碼山有道
- 簡歷內推
- 聯系我內推
- 第十章 學點前端
- Vue