ES的Update By Query对应的就是关系型数据库的update set ... where...语句;
ES的Update By Query可能存在的坑:比如批量更新时非事务模式执行(允许部分成功部分失败)、大批量操作会超时、频繁更新会报错(版本冲突)、脚本执行太频繁时又会触发断路器等。
1. 非事务模式执行
所有更新和查询失败都会导致update_by_query中止,并在响应失败时返回。已执行的更新仍然存在。(该过程不会回滚,只会中止)
使用时候不建议太大数据的修改;
建议增加补偿机制,将失败的请求记录下来,定时补偿;
2. java.io.IOException: listener timeout
默认是30000ms,(修改超时时间并非真正的解决方案)
3. VersionConflictEngineException
es是准实时的,默认refresh_interval: "1s"(默认值,可修改)
update_by_query在索引启动时获取索引的快照,这意味着如果文档在生成快照的时间和处理索引请求之间发生更改,则会出现版本冲突。===》1s内多次修改同一个document就会发生,你通过设置version_conflicts=false(会忽略错误),但并未解决问题,还有2种方式解决该问题:
- retries,一直重试,UpdateByQueryRequestBuilder中默认为11次,可见对es是有一定的压力的
- refresh=true,一直去刷盘,当然可以解决准实时的问题,但磁盘消耗是很多的
4. IllegalArgumentException: failed to execute script
Too many dynamic script compilations within, max: [75/5m],script修改语句只能接受5分钟内75次,具体可参与官方script-compilation-circuit-breaker,这个值太小了
总结:使用Update By Query要重点关注上面的4个问题,特别是涉及到大批量的修改,特别要关注监控信息(GET _tasks?detailed=true&actions=*byquery)
建议要限流,比如:可通过前置mongodb(定时定量去更新)或者更新失败后记录到新的index中后续定时定量去补偿。