Elasticsearch用Painless执行update_by_query删除对象属性失效问题
Elasticsearch update_by_query 删除嵌套子属性不生效问题解决方案
根本原因
Painless 脚本中 ctx._source 对应文档的顶层JSON结构,本质是Map对象,remove() 方法仅支持直接删除当前层级的键,传入带.的嵌套路径字符串会被识别为完整的顶层键名,而非解析为嵌套层级:
- 你执行
ctx._source.remove('person.hair_color')时,脚本会尝试删除顶层名为person.hair_color的字段,而非person对象下的hair_color子属性,自然不会生效 - update_by_query 的
updated计数仅代表匹配查询条件、成功执行脚本的文档数量,无论脚本是否实际修改了文档内容都会计数,这就是你看到更新数正常但字段仍存在的原因 - 你之前删除整个
person对象可以生效,是因为person本身就是顶层键,ctx._source.remove('person')的调用逻辑完全符合要求
正确的请求写法
修改脚本逻辑,先取到顶层person对象,再删除其下的hair_color属性,同时增加判空逻辑避免空指针异常:
POST /16cf303e902f4445a560a8e9a5b9ea51/_update_by_query?conflicts=proceed&wait_for_completion=false { "conflicts": "proceed", "query": { "exists": { "field": "person.hair_color" } }, "script": { "lang": "painless", "source": "if (ctx._source.person != null) { ctx._source.person.remove('hair_color'); }" } }
如果删除hair_color后person对象为空,你也可以同步删除空的person对象,脚本修改为:
"source": "if (ctx._source.person != null) { ctx._source.person.remove('hair_color'); if (ctx._source.person.isEmpty()) { ctx._source.remove('person'); } }"
验证说明
任务执行完成后可以随机取几条匹配的文档,执行GET /索引名/_doc/文档id查看字段是否已经被正确删除。
内容的提问来源于stack exchange,提问作者Juha Vehnia
相关产品推荐
相关产品推荐

