本篇主要介紹增量更新(partial update,也叫局部更新)的核心原理,介紹6.3.1版本的Elasticsearch腳本使用實例和增量更新的優點。前端
前文咱們有簡單介紹過增量的語法,簡單回顧一下請求示例:java
POST /music/children/1/_update { "doc": { "length": "76" } }
通常從客戶端到Elasticsearch,完整的應用請求流程基本是這樣的:node
Elasticsearch的document是基於不可變模式設計的,全部的document更新,其實都建立了一個新的document出來,再把老的document標記爲deleted,增量更新也不例外,只是GET全量document數據,整合新的document,替換老的document這三步操做全在一個shard裏完成,毫秒級完成。緩存
增量更新document的步驟:安全
Elasticsearch支持使用腳本實現更爲靈活的邏輯,6.0版本之後,默認支持的腳本是painless,而且再也不支持Groovy,由於Groovy編譯有必定機率會出現內存不釋放,最終致使Full GC的問題。網絡
咱們以英文兒歌的案例爲背景,假設document的數據是這樣:架構
{ "_index": "music", "_type": "children", "_id": "2", "_version": 6, "found": true, "_source": { "name": "wake me, shark me", "content": "don't let me sleep too late, gonna get up brightly early in the morning", "language": "english", "length": "55", "likes": 0 } }
如今有這樣一個需求:每當有人點擊播放一次歌曲時,該document的likes field就自增1,咱們能夠用簡單的腳原本實現:併發
POST /music/children/2/_update { "script" : "ctx._source.likes++" }
執行一次後,再查詢該document,發現likes變成1,每執行一次,likes都自增1,結果符合預期。less
對剛剛那個自增需求作一些改動,支持批量更新播放量,自增的數量由參數傳入,腳本也能夠經過導入的方式,預先編譯存儲在ES中,使用的時候調用便可。異步
POST _scripts/music-likes { "script": { "lang": "painless", "source": "ctx._source.likes += params.new_likes" } }
腳本ID爲music-likes,參數爲new_likes,是能夠在調用時傳入的。
咱們更新時,執行以下請求,就能夠調用剛剛建立的腳本
POST /music/children/2/_update { "script": { "id": "music-likes", "params": { "new_likes": 2 } } }
id即建立腳本時的music-likes,params是固定寫法,裏面的參數爲new_likes,執行後再查看document信息,能夠看到likes field的值按傳入的值進行累加,結果符合預期。
命令:
GET _scripts/music-likes
斜槓後面的參數即腳本ID
命令:
DELETE _scripts/music-likes
斜槓後面的參數即腳本ID
一句話,提升腳本的複用性。
像剛剛的案例,實現的是一個播放計數器的功能,目前這個計數器是與內容存儲在一塊兒,若是計數器單獨存儲,可能會出現新上架的一首歌,但計數器的document可能還不存在,試圖對它作更新操做會報document_missing_exception錯誤,這種場景咱們須要使用upsert語法:
POST /music/children/3/_update { "script" : "ctx._source.likes++", "upsert": { "likes": 0 } }
若是id爲3的記錄不存在,第一次請求時,執行upsert裏面的JSON內容,初始化一個新文檔,ID爲3,likes值爲0;第二次請求時,文檔已經存在,此時作script腳本的更新操做,likes自增。
本篇簡單介紹了增量更新的過程與原理,並與全量替換作了簡單的對比,針對一些簡單的計數場景,引入腳本的實現方式案例,腳本能夠實現很豐富的功能,具體能夠查看官網對Painless的介紹。
專一Java高併發、分佈式架構,更多技術乾貨分享與心得,請關注公衆號:Java架構社區