Elasticsearch 6.8 Java客户端UpdateRequest如何覆盖而非合并Object类型字段
Elasticsearch 6.8 Object类型字段局部更新覆盖方案
你当前遇到的Object字段合并问题是Elasticsearch局部更新的默认行为:通过updateRequest.doc()提交的局部更新请求,Elasticsearch默认会对Object类型字段做递归深度合并,只会更新传入的键值,保留原有对象中未传入的键,不会直接替换整个对象字段。
要实现emails字段的全量覆盖,无需大量调整现有逻辑,可以使用以下两种低改造成本的方案:
方案1:极简Painless脚本实现(推荐,改造成本极低)
该方案仅需将原构造局部文档的逻辑替换为单句更新脚本,不需要修改业务逻辑,不会带来大量返工:
var updateRequest = new UpdateRequest(); updateRequest.index(...); updateRequest.type(...); updateRequest.id(...); Map<String, List<String>> mapWithEntries = Map.of("Main", List.of("test@test.com")); // 构造参数和脚本,直接覆盖emails字段 Map<String, Object> scriptParams = new HashMap<>(); scriptParams.put("newEmails", mapWithEntries); Script updateScript = new Script( ScriptType.INLINE, "painless", "ctx._source.emails = params.newEmails", scriptParams ); updateRequest.script(updateScript); updateRequest.fetchSource(true); updateRequest.docAsUpsert(false); return updateRequest;
该脚本逻辑固定,完全可以封装为通用的工具方法,批量改造现有更新逻辑的成本极低。
方案2:无脚本全量更新方案
如果完全不想引入脚本,可以先查询目标文档的完整_source,替换emails字段后全量提交更新:
- 先调用
GetRequest查询对应文档的完整内容 - 替换_source中的
emails字段为最新的mapWithEntries - 构造
IndexRequest或带完整doc的UpdateRequest提交更新
注意:该方案需要额外发起一次查询请求,并发更新场景建议搭配版本号乐观锁控制,避免覆盖其他请求的更新内容。
内容的提问来源于stack exchange,提问作者JNS
相关产品推荐
相关产品推荐

