該文章同步發佈於:我的部落格
也歡迎關注我的 Facebook 以及 Instagram 接收軟體相關的資訊!
我們現在已經學會怎麼 index, update, delete document 了。
今天要介紹的是 bulk API,可以把所有的動作濃縮到一個請求的 payload 之中,是一個非常實用的 API。
首先,這個 API 需要的 payload 格式是 NDJSON,全名:Newline Delimited JSON,是一個把多個 JSON 物件串接在一起的格式。
看起來會像這樣:
{ "name": "Alice", "age": 25 }
{ "name": "Bob", "age": 30 }
{ "name": "Charlie", "age": 35 }
實際上每一行的結尾都包含 \n
的換行符號,只是如果用編輯器撰寫的話,直接按 Enter 就可以了。
使用 cURL 之類的工具時,HTTP Header 的 Content-Type 記得放 application/x-ndjson
一定要用 application/x-ndjson 嗎?
不,其實你用 application/json 也是可以被接受的,但就不是正確的方式。
直接進到 Dev Tools 內,指向 POST /_bulk
的 API:
我總共填入了 4 行的 JSON 物件,一行行來解析一下。
第一行,我使用了 index 這個動作以及 _id
這樣的 metadata,第二行則是第一行這個動作要處理的內容。
所以第一行加上第二行的意思就是,我要 index 一個選手,名字叫做 Ohtani, Power 99, Speed 80,第三行加上第四行也是以此類推。
等等,那 index 和 create 差在哪?
create 如果目標的 _id
已經存在,就會出現錯誤,而 index 則會取代原本存在的 document。
同樣的請求,我們再送一次看看:
看到了嗎?錯誤的原因:
[2]: version conflict, document already exists (current version [1])
而原先第一次的 created
也變成 updated
了,這是因為第一個動作是採用 index 的緣故。
接著我們來試試看 update 以及 delete 的操作:
有注意到什麼不一樣的地方嗎?
首先,我們把 endpoint 換成 /players/_bulk
,當我們確定 payload 中的所有資料都是在針對同一個 index 操作時,就可以直接在 endpoint 中指定,也就可以少寫 "_index": "player" 的值。
第二個,update 的動作中,要使用 doc
當作 key 讓 Elasticsearch ( 以下簡稱 ES ) 知道我們要更新 document 內的某個欄位;還記得老朋友 script
嗎?這邊也可以使用,忘記的話去看 這篇。
至於 delete 就沒什麼好說的,不需要額外提供資訊,刪掉就可以了。
和 上一篇文章 中 update_by_query 的方式一樣,每一個動作本身並不會影響到其他的動作,也就是說其中一個發生錯誤了,其他的還是會繼續執行,直到最後 ES 會把所有更新的細節回傳給你,接著你再來決定要怎麼做。
而從剛剛的截圖中也能看到 items
裡面包含的物件排序和我們送出請求時是一樣的,這樣使用應用程式處理時,也很方便。
其實從作用就很容易地看出來,主要是在處理大量資料時使用,那什麼時候會需要這樣處理大量資料呢?
應用場景:
_bulk
API 也是很常見的做法。_bulk
API 就能大幅度地提升 index 或是 update 的速度。好處:
_bulk
讓這些事情集中到一起,一次處理,減少很多 ES 自身的消耗,當然關於記憶體的利用也會比單獨更新更好。前兩篇文章都不停地提到 ES 使用 primary term
以及 sequence number
來實作樂觀鎖的機制,那 _bulk
API 呢?支援嗎?
當然,你只要把我們在 這篇文章 中學過的 if_primary_term 以及 if_seq_no 帶入第一行動作的 metadata 就可以囉!
隨手範例:
{ "index": { "_index": "players", "_id": 1, "if_primary_term": 10, "if_seq_no": 4 } }
{ "name": "Ohtani", "power": 99, "speed": 75 }