集群特點
- cluster.name 必須一致
- 當有節點加入集群中或者從集群中移除節點時,集群將會重新平均分布所有的數據
- 任意節點都知道任意文檔所處的位置,并且能夠將我們的請求直接轉發到存儲我們所需文檔的節點。 無論我們將請求發送到哪個節點,它都能負責從各個包含我們所需文檔的節點收集回數據,并將最終結果返回給客戶端。
- 主 節點負責管理集群范圍內的所有變更,例如增加、刪除索引,或者增加、刪除節點等
集群健康
GET /_cluster/health
它在 status 字段中展示為 green 、 yellow 或者 red 。
{
"cluster_name": "elasticsearch",
"status": "green",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 0,
"active_shards": 0,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
}
status 字段指示著當前集群在總體上是否工作正常。它的三種顏色含義如下:
- green
所有的主分片和副本分片都正常運行。 - yellow
所有的主分片都正常運行,但不是所有的副本分片都正常運行。 - red
有主分片沒能正常運行。
添加索引
索引實際上是指向一個或者多個物理 分片 的 邏輯命名空間 。
一個 分片 是一個底層的 工作單元 ,它僅保存了全部數據中的一部分,一個分片是一個 Lucene 的實例,以及它本身就是一個完整的搜索引擎。 我們的文檔被存儲和索引到分片內,但是應用程序是直接與索引而不是與分片進行交互。
一個分片可以是 主 分片或者 副本 分片。 索引內任意一個文檔都歸屬于一個主分片,所以主分片的數目決定著索引能夠保存的最大數據量。一個主分片最大能夠存儲 Integer.MAX_VALUE - 128 個文檔
一個副本分片只是一個主分片的拷貝。副本分片作為硬件故障時保護數據不丟失的冗余備份,并為搜索和返回文檔等讀操作提供服務。
在索引建立的時候就已經確定了主分片數,但是副本分片數可以隨時修改。
讓我們在包含一個空節點的集群內創建名為 blogs 的索引。 索引在默認情況下會被分配5個主分片, 但是為了演示目的,我們將分配3個主分片和一份副本(每個主分片擁有一個副本分片)
PUT /blogs
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
添加、刪減機器,分片自動遷移
水平擴容,可增加副本分片。
PUT /blogs/_settings
{
"number_of_replicas" : 2
}
什么是文檔
在大多數應用中,多數實體或對象可以被序列化為包含鍵值對的 JSON 對象。
通常情況下,我們使用的術語 對象 和 文檔 是可以互相替換的。不過,有一個區別: 一個對象僅僅是類似于 hash 、 hashmap 、字典或者關聯數組的 JSON 對象,對象中也可以嵌套其他的對象。 對象可能包含了另外一些對象。在 Elasticsearch 中,術語 文檔 有著特定的含義。它是指最頂層或者根對象, 這個根對象被序列化成 JSON 并存儲到 Elasticsearch 中,指定了唯一 ID。
字段的名字可以是任何合法的字符串,但 不可以 包含英文句號(.)。
文檔元數據
- _index: 文檔在哪存放
- _type: 文檔表示的對象類別
- _id: 文檔唯一標識
_index
一個 索引 應該是因共同的特性被分組到一起的文檔集合。 例如,你可能存儲所有的產品在索引 products 中,而存儲所有銷售的交易到索引 sales 中。 雖然也允許存儲不相關的數據到一個索引中,但這通常看作是一個反模式的做法。
索引名規則:名字必須小寫,不能以下劃線開頭,不能包含逗號
_type
數據可能在索引中只是松散的組合在一起,但是通常明確定義一些數據中的子分區是很有用的。 例如,所有的產品都放在一個索引中,但是你有許多不同的產品類別,比如 "electronics" 、 "kitchen" 和 "lawn-care"。
這些文檔共享一種相同的(或非常相似)的模式:他們有一個標題、描述、產品代碼和價格。他們只是正好屬于“產品”下的一些子類。
Elasticsearch 公開了一個稱為 types (類型)的特性,它允許您在索引中對數據進行邏輯分區。不同 types 的文檔可能有不同的字段,但最好能夠非常相似。 我們將在 類型和映射 中更多的討論關于 types 的一些應用和限制。
一個 _type
命名可以是大寫或者小寫,但是不能以下劃線或者句號開頭,不應該包含逗號, 并且長度限制為256個字符. 我們使用 blog
作為類型名舉例。
_id
ID 是一個字符串,當它和 _index 以及 _type 組合就可以唯一確定 Elasticsearch 中的一個文檔。 當你創建一個新的文檔,要么提供自己的 _id ,要么讓 Elasticsearch 幫你生成。
索引文檔
使用自定義文檔
如果你的文檔有一個自然的標識符 (例如,一個 user_account 字段或其他標識文檔的值),你應該使用如下方式的 index API 并提供你自己 _id :
PUT /{index}/{type}/{id}
{
"field": "value",
...
}
舉個例子,如果我們的索引稱為 website ,類型稱為 blog ,并且選擇 123 作為 ID ,那么索引請求應該是下面這樣:
PUT /website/blog/123
{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}
Elasticsearch 響應體如下所示:
{
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 1,
"created": true
}
該響應表明文檔已經成功創建,該索引包括 _index
、 _type
和 _id
元數據, 以及一個新元素: _version
。
在 Elasticsearch 中每個文檔都有一個版本號。當每次對文檔進行修改時(包括刪除), _version
的值會遞增。 在 處理沖突 中,我們討論了怎樣使用 _version
號碼確保你的應用程序中的一部分修改不會覆蓋另一部分所做的修改。
Autogenerating IDs
如果你的數據沒有自然的 ID, Elasticsearch 可以幫我們自動生成 ID 。 請求的結構調整為: 不再使用 PUT 謂詞(“使用這個 URL 存儲這個文檔”), 而是使用 POST 謂詞(“存儲文檔在這個 URL 命名空間下”)。
現在該 URL 只需包含 _index 和 _type :
POST /website/blog/
{
"title": "My second blog entry",
"text": "Still trying this out...",
"date": "2014/01/01"
}
除了 _id 是 Elasticsearch 自動生成的,響應的其他部分和前面的類似:
{
"_index": "website",
"_type": "blog",
"_id": "AVFgSgVHUP18jI2wRx0w",
"_version": 1,
"created": true
}
取回一個文檔
為了從 Elasticsearch 中檢索出文檔,我們仍然使用相同的 _index , _type , 和 _id ,但是 HTTP 謂詞更改為 GET :
GET /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"
}
}
在請求的查詢串參數中加上 pretty 參數,正如前面的例子中看到的,這將會調用 Elasticsearch 的 pretty-print 功能,該功能 使得 JSON 響應體更加可讀。但是, _source 字段不能被格式化打印出來。相反,我們得到的 _source 字段中的 JSON 串,剛好是和我們傳給它的一樣。
GET 請求的響應體包括 {"found": true} ,這證實了文檔已經被找到。 如果我們請求一個不存在的文檔,我們仍舊會得到一個 JSON 響應體,但是 found 將會是 false 。 此外, HTTP 響應碼將會是 404 Not Found ,而不是 200 OK 。
我們可以通過傳遞 -i 參數給 curl 命令,該參數能夠顯示響應的頭部:
curl -i -XGET http://localhost:9200/website/blog/124?pretty
顯示響應頭部的響應體現在類似這樣:
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=UTF-8
Content-Length: 83
{
"_index" : "website",
"_type" : "blog",
"_id" : "124",
"found" : false
}
返回文檔的一部分
默認情況下, GET 請求會返回整個文檔,這個文檔正如存儲在 _source 字段中的一樣。但是也許你只對其中的 title 字段感興趣。單個字段能用 _source 參數請求得到,多個字段也能使用逗號分隔的列表來指定。
GET /website/blog/123?_source=title,text
該 _source 字段現在包含的只是我們請求的那些字段,并且已經將 date 字段過濾掉了。
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"found" : true,
"_source" : {
"title": "My first blog entry" ,
"text": "Just trying this out..."
}
}
檢查文檔是否存在
如果只想檢查一個文檔是否存在--根本不想關心內容—?那么用 HEAD 方法來代替 GET 方法。 HEAD 請求沒有返回體,只返回一個 HTTP 請求報頭:
curl -i -XHEAD http://localhost:9200/website/blog/123
如果文檔存在, Elasticsearch 將返回一個 200 ok 的狀態碼:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 0
若文檔不存在, Elasticsearch 將返回一個 404 Not Found 的狀態碼
curl -i -XHEAD http://localhost:9200/website/blog/124
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=UTF-8
Content-Length: 0
更新整個文檔
在 Elasticsearch 中文檔是 不可改變 的,不能修改它們.
相反,如果想要更新現有的文檔,需要 重建索引 或者進行替換, 我們可以使用相同的 index
API 進行實現,在 索引文檔 中已經進行了討論。
PUT /website/blog/123
{
"title": "My first blog entry",
"text": "I am starting to get the hang of this...",
"date": "2014/01/02"
}
在響應體中,我們能看到 Elasticsearch 已經增加了 _version 字段值:
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 2,
"created": false
}
created 標志設置成 false ,是因為相同的索引、類型和 ID 的文檔已經存在。
在內部,Elasticsearch 已將舊文檔標記為已刪除,并增加一個全新的文檔。 盡管你不能再對舊版本的文檔進行訪問,但它并不會立即消失。當繼續索引更多的數據,Elasticsearch 會在后臺清理這些已刪除文檔。
創建新文檔
請記住, _index 、 _type 和 _id 的組合可以唯一標識一個文檔。所以,確保創建一個新文檔的最簡單辦法是,使用索引請求的 POST 形式讓 Elasticsearch 自動生成唯一 _id :
POST /website/blog/
{ ... }
然而,如果已經有自己的 _id ,那么我們必須告訴 Elasticsearch ,只有在相同的 _index 、 _type 和 _id 不存在時才接受我們的索引請求。這里有兩種方式,他們做的實際是相同的事情。使用哪種,取決于哪種使用起來更方便。
第一種方法使用 op_type 查詢-字符串參數:
PUT /website/blog/123?op_type=create
{ ... }
第二種方法是在 URL 末端使用 /_create :
PUT /website/blog/123/_create
{ ... }
如果創建新文檔的請求成功執行,Elasticsearch 會返回元數據和一個 201 Created 的 HTTP 響應碼。
另一方面,如果具有相同的 _index 、 _type 和 _id 的文檔已經存在,Elasticsearch 將會返回 409 Conflict 響應碼,以及如下的錯誤信息:
{
"error": {
"root_cause": [
{
"type": "document_already_exists_exception",
"reason": "[blog][123]: document already exists",
"shard": "0",
"index": "website"
}
],
"type": "document_already_exists_exception",
"reason": "[blog][123]: document already exists",
"shard": "0",
"index": "website"
},
"status": 409
}
刪除文檔
刪除文檔的語法和我們所知道的規則相同,只是使用 DELETE 方法:
DELETE /website/blog/123
如果找到該文檔,Elasticsearch 將要返回一個 200 ok 的 HTTP 響應碼,和一個類似以下結構的響應體。注意,字段 _version 值已經增加:
{
"found" : true,
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 3
}
如果文檔沒有找到,我們將得到 404 Not Found 的響應碼和類似這樣的響應體:
{
"found" : false,
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 4
}
即使文檔不存在( Found 是 false ), _version 值仍然會增加。這是 Elasticsearch 內部記錄本的一部分,用來確保這些改變在跨多節點時以正確的順序執行。
正如已經在更新整個文檔中提到的,刪除文檔不會立即將文檔從磁盤中刪除,只是將文檔標記為已刪除狀態。隨著你不斷的索引更多的數據,Elasticsearch 將會在后臺清理標記為已刪除的文檔。
樂觀并發控制
現在,當我們嘗試通過重建文檔的索引來保存修改,我們指定 version 為我們的修改會被應用的版本:
PUT /website/blog/1?version=1
{
"title": "My first blog entry",
"text": "Starting to get the hang of this..."
}
我們想這個在我們索引中的文檔只有現在的 _version 為 1 時,本次更新才能成功。
此請求成功,并且響應體告訴我們 _version 已經遞增到 2 :
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 2
"created": false
}
然而,如果我們重新運行相同的索引請求,仍然指定 version=1 , Elasticsearch 返回 409 Conflict HTTP 響應碼,和一個如下所示的響應體:
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[blog][1]: version conflict, current [2], provided [1]",
"index": "website",
"shard": "3"
}
],
"type": "version_conflict_engine_exception",
"reason": "[blog][1]: version conflict, current [2], provided [1]",
"index": "website",
"shard": "3"
},
"status": 409
}
這告訴我們在 Elasticsearch 中這個文檔的當前 _version 號是 2 ,但我們指定的更新版本號為 1 。
我們現在怎么做取決于我們的應用需求。我們可以告訴用戶說其他人已經修改了文檔,并且在再次保存之前檢查這些修改內容。 或者,在之前的商品 stock_count 場景,我們可以獲取到最新的文檔并嘗試重新應用這些修改。
所有文檔的更新或刪除 API,都可以接受 version 參數,這允許你在代碼中使用樂觀的并發控制,這是一種明智的做法。
通過外部系統使用版本控制
如果你的主數據庫已經有了版本號?—?或一個能作為版本號的字段值比如 timestamp?—?那么你就可以在 Elasticsearch 中通過增加 version_type=external 到查詢字符串的方式重用這些相同的版本號, 版本號必須是大于零的整數, 且小于 9.2E+18?—?一個 Java 中 long 類型的正值。
外部版本號的處理方式和我們之前討論的內部版本號的處理方式有些不同, Elasticsearch 不是檢查當前 _version 和請求中指定的版本號是否相同, 而是檢查當前 _version 是否 小于 指定的版本號。 如果請求成功,外部的版本號作為文檔的新 _version 進行存儲。
例如,要創建一個新的具有外部版本號 5 的博客文章,我們可以按以下方法進行:
PUT /website/blog/2?version=5&version_type=external
{
"title": "My first external blog entry",
"text": "Starting to get the hang of this..."
}
在響應中,我們能看到當前的 _version 版本號是 5 :
{
"_index": "website",
"_type": "blog",
"_id": "2",
"_version": 5,
"created": true
}
現在我們更新這個文檔,指定一個新的 version 號是 10 :
PUT /website/blog/2?version=10&version_type=external
{
"title": "My first external blog entry",
"text": "This is a piece of cake..."
}
請求成功并將當前 _version 設為 10 :
{
"_index": "website",
"_type": "blog",
"_id": "2",
"_version": 10,
"created": false
}
如果你要重新運行此請求時,它將會失敗,并返回像我們之前看到的同樣的沖突錯誤, 因為指定的外部版本號不大于 Elasticsearch 的當前版本號。
文檔的部分更新
- doc
update 請求最簡單的一種形式是接收文檔的一部分作為 doc 的參數, 它只是與現有的文檔進行合并。對象被合并到一起,覆蓋現有的字段,增加新的字段。 例如,我們增加字段 tags 和 views 到我們的博客文章,如下所示:
POST /website/blog/1/_update
{
"doc" : {
"tags" : [ "testing" ],
"views": 0
}
}
如果請求成功,我們看到類似于 index 請求的響應:
{
"_index" : "website",
"_id" : "1",
"_type" : "blog",
"_version" : 3
}
檢索文檔顯示了更新后的 _source 字段:
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 3,
"found": true,
"_source": {
"title": "My first blog entry",
"text": "Starting to get the hang of this...",
"tags": [ "testing" ],
"views": 0
}
}
新的字段已被添加到 _source 中。
- script
腳本可以在 update API中用來改變 _source 的字段內容, 它在更新腳本中稱為 ctx._source
例如,我們可以使用腳本來增加博客文章中 views 的數量:
POST /website/blog/1/_update
{
"script" : "ctx._source.views+=1"
}
我們也可以通過使用腳本給 tags 數組添加一個新的標簽。在這個例子中,我們指定新的標簽作為參數,而不是硬編碼到腳本內部。 這使得 Elasticsearch 可以重用這個腳本,而不是每次我們想添加標簽時都要對新腳本重新編譯:
POST /website/blog/1/_update
{
"script" : "ctx._source.tags+=new_tag",
"params" : {
"new_tag" : "search"
}
}
獲取文檔并顯示最后兩次請求的效果:
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 5,
"found": true,
"_source": {
"title": "My first blog entry",
"text": "Starting to get the hang of this...",
"tags": ["testing", "search"],
"views": 1
}
}
我們甚至可以選擇通過設置 ctx.op 為 delete 來刪除基于其內容的文檔:
POST /website/blog/1/_update
{
"script" : "ctx.op = ctx._source.views == count ? 'delete' : 'none'",
"params" : {
"count": 1
}
}
更新的文檔可能尚不存在
在這樣的情況下,我們可以使用 upsert 參數,指定如果文檔不存在就應該先創建它:
POST /website/pageviews/1/_update
{
"script" : "ctx._source.views+=1",
"upsert": {
"views": 1
}
}
我們第一次運行這個請求時, upsert 值作為新文檔被索引,初始化 views 字段為 1 。 在后續的運行中,由于文檔已經存在, script 更新操作將替代 upsert 進行應用,對 views 計數器進行累加。
更新和沖突
在本節的介紹中,我們說明 檢索 和 重建索引 步驟的間隔越小,變更沖突的機會越小。 但是它并不能完全消除沖突的可能性。 還是有可能在 update 設法重新索引之前,來自另一進程的請求修改了文檔。
為了避免數據丟失, update API 在 檢索 步驟時檢索得到文檔當前的 _version 號,并傳遞版本號到 重建索引 步驟的 index 請求。 如果另一個進程修改了處于檢索和重新索引步驟之間的文檔,那么 _version 號將不匹配,更新請求將會失敗。
對于部分更新的很多使用場景,文檔已經被改變也沒有關系。 例如,如果兩個進程都對頁面訪問量計數器進行遞增操作,它們發生的先后順序其實不太重要; 如果沖突發生了,我們唯一需要做的就是嘗試再次更新。
這可以通過設置參數 retry_on_conflict 來自動完成, 這個參數規定了失敗之前 update 應該重試的次數,它的默認值為 0 。
POST /website/pageviews/1/_update?retry_on_conflict=5
{
"script" : "ctx._source.views+=1",
"upsert": {
"views": 0
}
}
失敗之前重試該更新5次。
在增量操作無關順序的場景,例如遞增計數器等這個方法十分有效,但是在其他情況下變更的順序 是 非常重要的。 類似 index
API , update
API 默認采用 最終寫入生效 的方案,但它也接受一個 version
參數來允許你使用 optimistic concurrency control 指定想要更新文檔的版本。
取回多個文檔
Elasticsearch 的速度已經很快了,但甚至能更快。 將多個請求合并成一個,避免單獨處理每個請求花費的網絡延時和開銷。 如果你需要從 Elasticsearch 檢索很多文檔,那么使用 multi-get 或者 mget API 來將這些檢索請求放在一個請求中,將比逐個文檔請求更快地檢索到全部文檔。
mget API 要求有一個 docs 數組作為參數,每個元素包含需要檢索文檔的元數據, 包括 _index 、 _type 和 _id 。如果你想檢索一個或者多個特定的字段,那么你可以通過 _source 參數來指定這些字段的名字:
GET /_mget
{
"docs" : [
{
"_index" : "website",
"_type" : "blog",
"_id" : 2
},
{
"_index" : "website",
"_type" : "pageviews",
"_id" : 1,
"_source": "views"
}
]
}
該響應體也包含一個 docs
數組, 對于每一個在請求中指定的文檔,這個數組中都包含有一個對應的響應,且順序與請求中的順序相同。 其中的每一個響應都和使用單個 get
request 請求所得到的響應體相同:
{
"docs" : [
{
"_index" : "website",
"_id" : "2",
"_type" : "blog",
"found" : true,
"_source" : {
"text" : "This is a piece of cake...",
"title" : "My first external blog entry"
},
"_version" : 10
},
{
"_index" : "website",
"_id" : "1",
"_type" : "pageviews",
"found" : true,
"_version" : 2,
"_source" : {
"views" : 2
}
}
]
}
如果想檢索的數據都在相同的 _index 中(甚至相同的 _type 中),則可以在 URL 中指定默認的 /_index 或者默認的 /_index/_type 。
你仍然可以通過單獨請求覆蓋這些值:
GET /website/blog/_mget
{
"docs" : [
{ "_id" : 2 },
{ "_type" : "pageviews", "_id" : 1 }
]
}
事實上,如果所有文檔的 _index 和 _type 都是相同的,你可以只傳一個 ids 數組,而不是整個 docs 數組:
GET /website/blog/_mget
{
"ids" : [ "2", "1" ]
}
注意,我們請求的第二個文檔是不存在的。我們指定類型為 blog ,但是文檔 ID 1 的類型是 pageviews ,這個不存在的情況將在響應體中被報告:
{
"docs" : [
{
"_index" : "website",
"_type" : "blog",
"_id" : "2",
"_version" : 10,
"found" : true,
"_source" : {
"title": "My first external blog entry",
"text": "This is a piece of cake..."
}
},
{
"_index" : "website",
"_type" : "blog",
"_id" : "1",
"found" : false
}
]
}
事實上第二個文檔未能找到并不妨礙第一個文檔被檢索到。每個文檔都是單獨檢索和報告的。
即使有某個文檔沒有找到,上述請求的 HTTP 狀態碼仍然是 200 。事實上,即使請求 沒有 找到任何文檔,它的狀態碼依然是 200 --因為 mget 請求本身已經成功執行。 為了確定某個文檔查找是成功或者失敗,你需要檢查 found 標記。
代價較小的批量操作
與 mget 可以使我們一次取回多個文檔同樣的方式, bulk API 允許在單個步驟中進行多次 create 、 index 、 update 或 delete 請求。 如果你需要索引一個數據流比如日志事件,它可以排隊和索引數百或數千批次。
bulk 與其他的請求體格式稍有不同,如下所示:
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
這種格式類似一個有效的單行 JSON 文檔 流 ,它通過換行符(\n
)連接到一起。注意兩個要點:
- 每行一定要以換行符(
\n
)結尾, 包括最后一行 。這些換行符被用作一個標記,可以有效分隔行。 - 這些行不能包含未轉義的換行符,因為他們將會對解析造成干擾。這意味著這個 JSON 不 能使用 pretty 參數打印。
在 為什么是有趣的格式? 中, 我們解釋為什么 bulk
API 使用這種格式。
action/metadata
行指定 哪一個文檔 做 什么操作 。
action
必須是以下選項之一:
- create
如果文檔不存在,那么就創建它。詳情請見 創建新文檔。 - index
創建一個新文檔或者替換一個現有的文檔。詳情請見 索引文檔 和 更新整個文檔。 - update
部分更新一個文檔。詳情請見 文檔的部分更新。 - delete
刪除一個文檔。詳情請見 刪除文檔。
metadata 應該指定被索引、創建、更新或者刪除的文檔的 _index 、 _type 和 _id 。
例如,一個 delete 請求看起來是這樣的:
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
request body 行由文檔的 _source 本身組成—?文檔包含的字段和值。它是 index 和 create 操作所必需的,這是有道理的:你必須提供文檔以索引。
它也是 update 操作所必需的,并且應該包含你傳遞給 update API 的相同請求體: doc 、 upsert 、 script 等等。 刪除操作不需要 request body 行。
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "My first blog post" }
如果不指定 _id ,將會自動生成一個 ID :
{ "index": { "_index": "website", "_type": "blog" }}
{ "title": "My second blog post" }
為了把所有的操作組合在一起,一個完整的 bulk 請求 有以下形式:
POST /_bulk
{ "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" : 3} }
{ "doc" : {"title" : "My updated blog post"} }