背景:
我们对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脚本还可以给我们解决更多问题,后续再继续跟踪记录。