背景:
我們對es中,我們會對一些數組之類的字段進行存儲,但是要更新里面數組中的某一個值,你必須得整個拉出來,在內存中處理之后再賦值修改,這樣比較消耗內存,而且隨着數據增多,這影響更大,因此特意研究了下怎么通過es去實現
解決方案:
首先想到的就是通過腳本來實現,參考了官網的文檔之后,發現可以行,es腳本文檔地址,鏈接 https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-lang-spec.html
現在kibana上實現,比如我要對tags這個字段更新,腳本如下:
POST /xx_index/_update_by_query { "query": { "term": { "_id": "111" } }, "script": { "lang": "painless", "source": "def tags= ctx._source.tags;def newTag=params.tagInfo; if (tags == null) { ctx._source.tags = [params.tagInfo];} else {tags.removeIf(item->item['tagId']==newTag['tagId']);tags.add(newTag);}", "params": { "tagInfo": { "tagId": 1, "name": "標簽", "des": "說明", "no": 1 } } } }
通過比較tagId,先移除再新增的方式實現更新替換,因為es也支持lambda的語法,實現起來比較方便
接下來可以通過代碼來實現
public void updateTag(String id, Class clz, Tag tag) { if(Objects.isNull(id) || Objects.isNull(encounterTag)){ return; } UpdateRequest updateRequest = new UpdateRequest(); String scriptStr = "def tags= ctx._source.tags;def newTag=params.tagInfo; if (tags == null) { ctx._source.tags = [params.tagInfo];} else {tags.removeIf(item->item['tagId']==newTag['tagId']);tags.add(newTag);}"; Map<String, Object> params = new HashMap<>(); params.put("tagInfo", JSONObject.toJSON(tag)); Script script = new Script( Script.DEFAULT_SCRIPT_TYPE,Script.DEFAULT_SCRIPT_LANG, scriptStr, params); updateRequest.script(script); UpdateQuery updateQuery = new UpdateQueryBuilder().withId(id).withClass(clz).withUpdateRequest(updateRequest).build(); elasticsearchTemplate.update(updateQuery); elasticsearchTemplate.refresh(clz); }
為了更方便使用,又增加了一個可以批量增加的,實現方式類似
腳本如下:
POST /enc_encounter_list/_update_by_query { "query": { "term": { "_id": "11122" } }, "script": { "lang": "painless", "source": "def tags= ctx._source.tags;def newTag=params.tagInfo; if (tags == null) { ctx._source.tags = params.tagInfo;} else {for(def t : newTag){tags.removeIf(item->item['tagId']==t['tagId']);tags.add(t);}}", "params": { "tagInfo": [ { "tagId": 1, "name": "標簽", "des": "說明", "no": 1 }, { "tagId": 2, "name": "標簽2", "des": "說明2", "no": 2 } ] } } }
后端類似,此處就不在贅述了。
es腳本還可以給我們解決更多問題,后續再繼續跟蹤記錄。