1. 准备阶段:确定目标和条件
UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest(ArchivesGlobalConstant.PROFILE_INDEX_NAME);
updateByQueryRequest.setDocTypes(ArchivesGlobalConstant.TYPE_NAME);
updateByQueryRequest.setQuery(QueryBuilders.termsQuery("lib_id", libIds));
- 创建请求对象 :
new UpdateByQueryRequest(...)。- 意义 :告诉 ES,"我要对
PROFILE_INDEX_NAME这个索引执行批量更新操作"。
- 意义 :告诉 ES,"我要对
- 设置类型 :
setDocTypes(...)。- 意义:限定操作的文档类型(虽然新版 ES 逐渐弱化类型,但旧版客户端代码里还需要写)。
- 设置查询条件 :
setQuery(...)。- 意义 :"找谁?" 。使用
termsQuery找出所有lib_id在libIds列表中的文档。这一步和查数据是一模一样的。
- 意义 :"找谁?" 。使用
2. 逻辑阶段:定义修改规则(核心)
Map<String, Object> params = Maps.newHashMap();
params.put("groupId", groupId);
params.put("groupIds", Lists.newArrayList(groupId));
// ... 中间根据 ADD/REMOVE 选择脚本
updateByQueryRequest.setScript(new Script(...));
- 准备参数 :
params。- 意义 :把 Java 里的变量(
groupId)包装成 Map,准备传给 ES。这样做的目的是为了防止字符串拼接错误,也方便 ES 做安全检查。
- 意义 :把 Java 里的变量(
- 定义脚本 :
new Script(...)。- 意义 :"改成什么样?"。这是批量更新的灵魂。
- 逻辑:把刚才的参数、脚本语言(Painless)、以及具体的修改代码(那个长字符串)组装在一起。
- 注意 :这里根据
operateTag判断是执行"添加 ID"还是"删除 ID"的逻辑。
3. 执行阶段:发送指令并处理
updateByQueryRequest.setRefresh(true);
updateByQueryRequest.setConflicts("proceed");
try {
restHighLevelClient.updateByQuery(updateByQueryRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
// 错误处理
}
- 配置选项 :
setRefresh(true):立即生效。更新完马上刷新索引,让数据能立刻被搜索到(如果不设,ES 可能会为了性能稍后才刷新,导致查不到刚改的数据)。setConflicts("proceed"):冲突忽略。如果在更新过程中有其他人在修改同一条数据,不要报错停止,而是继续执行下去。
- 发送请求 :
client.updateByQuery(...)。- 意义:把请求发给 ES。ES 会根据条件找到文档,然后执行脚本里的逻辑,最后保存。