做爲一個成熟的框架,Elasticsearch裏面提供了豐富的操做數據的api,本篇咱們就來學習一下在es中更新數據的幾種方式。java
(一)更新文檔json
(1)部分更新:api
java api:多線程
` HashMap<String,Object> data=new HashMap<>(); data.put("name","woshigcs"); data.put("age",25); UpdateRequestBuilder urb= client.prepareUpdate("active2018-03-21", "active", "18"); urb.setDoc(data); urb.execute().actionGet(); System.out.println("update ok......");
注意部分更新功能,前提是索引和該條數據已經存在,不然會拋出對應的異常,只要任何一個不知足,都會更新失敗。併發
curl:app
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{ "doc" : { "name" : "new_name" } }
(2)使用detect_noop框架
java api:curl
` HashMap<String,Object> data=new HashMap<>(); data.put("name","woshigcs"); data.put("age",25); UpdateRequestBuilder urb= client.prepareUpdate("active2018-03-21", "active", "18"); urb.setDoc(data); urb.setDetectNoop(false);//默認是true urb.execute().actionGet(); System.out.println("update ok......");
curl方式:oop
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{ "doc" : { "name" : "new_name" }, "detect_noop": false }'
注意detect_noop的意思:post
默認狀況下detect_noop=true
默認狀況下只有原來的source和新的source存在不一樣的字段狀況下才會重建索引,若是如出一轍是不會觸發重建索引的,若是將detect_noop=false無論內容有沒有變化都會重建索引,這一點能夠經過version的值的變化來發現
更新的文檔,必須提早存在,除非你用upset+script來更新,不然會報document missing異常
(二)script + upset更新方式:
java api
` HashMap<String,Object> params=new HashMap<>(); HashMap<String,Object> data=new HashMap<>(); data.put("name","12345"); params.put("source",data); StringBuffer sb_json = new StringBuffer("ctx._source=source"); Script script = new Script(sb_json.toString(), ScriptService.ScriptType.INLINE, "groovy", params); UpdateRequestBuilder urb= client.prepareUpdate("active2018-03-11", "active", "16"); urb.setScript(script); urb.setUpsert(data); urb.execute().actionGet(); System.out.println("更新完事。。。。。。 ");
curl
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{ "script" : { "inline": "ctx._source.counter += count", "params" : { "count" : 4 } }, "upsert" : { "counter" : 1 } }'
(三):scripted_upsert用法:
官網個的例子沒有跑通,下面這個是按照stackoverflow上面的例子改寫的,能夠經過
在postman裏面已經跑通:
首先是在post請求的url
java api:
` HashMap<String,Object> params=new HashMap<>(); HashMap<String,Object> data=new HashMap<>(); data.put("name","12345"); HashMap<String,Object> newdata=new HashMap<>(); newdata.put("name","789"); params.put("data",data); params.put("newdata",newdata); StringBuffer sb_json = new StringBuffer("if (ctx.op == \"create\") ctx._source=data; else ctx._source=newdata"); Script script = new Script(sb_json.toString(), ScriptService.ScriptType.INLINE, "groovy", params); UpdateRequestBuilder urb= client.prepareUpdate("active2018-03-11", "active", "16"); urb.setScript(script); urb.setScriptedUpsert(true); urb.setUpsert("{}");//必須有這個值,不然會報document missing exception urb.execute().actionGet(); System.out.println("更新完事。。。。。。 ");
curl方式
http://192.168.201.5:9200/active2018-03-11/active/11/_update
而後是下面的body裏面選擇raw然類型是JSON(application/json):
{ "scripted_upsert":true, "script" : { "script":"if (ctx.op == \"create\") ctx._source=data; else ctx._source=newdata ", "params" : { "data":{ "ct":11, "aid":"a22", "tid":"t11" }, "newdata":{ "ct":1000, "aid":"a2qq2", "tid":"qq" } } }, "upsert" : {} }
執行上面的腳本,首先會檢查索引是否存在,若是不存在就會新建一個索引,而後會判斷id等於11這條數據存在不存在,若是不存在就把data裏面的數據做爲第一次的插入數據,若是已經存在就會把原來的數據刪除掉而後把newdata的數據插入進去,能夠理解就是更新。這裏須要注意,若是用的是動態mapping,須要注意數據的類型,動態mapping下兩條數據裏面的同一個字段能夠擁有不一樣的類型,這樣既靈活又帶來了風險,因此對於嚴謹類型的數據推薦使用靜態mapping,嚴格限定字段的類型。
(四)doc_as_upsert方式:
這個方式其實就是前面兩個的簡潔版,意思就是沒有就插入有就覆蓋,注意這是是覆蓋並非把原來的刪除在插入,並且若是是動態mapping還能夠改變字段的類型,但不建議這麼用。
java api:
` HashMap<String,Object> data=new HashMap<>(); data.put("name","234"); data.put("age",123); data.put("address","北京海淀區"); UpdateRequestBuilder urb= client.prepareUpdate("active2018-03-11", "active", "16"); urb.setDoc(data); urb.setDocAsUpsert(true); urb.execute().actionGet();// System.out.println("操做成功......");
curl方式:
http://192.168.201.5:9200/active2018-03-11/active/12/_update { "doc" : { "name" : "6755", "age":12, "address":"北京朝陽" }, "doc_as_upsert" : true }
總結:
上面更新操做es幾種方法,整體來講使用script更新的方式最強大,能夠作一些複雜業務場景的操做,如數值的累增或者操做集合對象元素的追加或者刪除,其餘的幾種方式適合簡單的更新操做。
無論使用那種更新方式,咱們都須要考慮併發問題,經過前面一系列的文章的介紹,咱們知道es裏面的更新,刪除,都是僞操做,尤爲是更新,在es內部的實際處理流程是:
(1)查詢舊的document數據
(2)修改爲最新的數據
(3)而後重建整條document
在這裏的三個階段,若是同時又另一個進程也在修改該條數據,就會發生衝突,es裏面是根據version字段來判斷是否衝突的,在上面的步驟中的第一步查詢舊的數據會獲得version字段,在第三步時候寫的時候會把這個version字段在傳回,這個時候若是發現version不一致就會發生衝忽然後拋出異常,因此你們在使用的時候能夠優先經過設計避免多線程操做,若是實在無法避免則可使用es裏面的提供的version字段來經過樂觀鎖控制併發問題,若是操做是簡單的累加或累減還能夠用更簡單的方法衝突重試來解決併發問題,一句話就是具體場景具體分析,關於es併發問題後面有空能夠單獨再整理一篇文章出來。