关于ElasticSearch的Update By Query的那些著名的坑

探讨Elasticsearch中UpdateByQuery功能的四个主要问题:非事务性执行、超时异常、版本冲突及脚本执行频率限制,提供解决策略。

提起es的Update By Query很多人一定也不陌生,它对应的就是关系型数据库的update set ... where...语句,这对应一般的存储引擎而言算是最基本的功能,但它的坑确不少,多到让你使用起来很奔溃,比如批量更新时非事务模式执行(允许部分成功部分失败)、大批量操作会超时、频繁更新会报错(版本冲突)、脚本执行太频繁时又会触发断路器等。

1. 非事务模式执行

在前面update_by_query相关文章也大概讲过,所有更新和查询失败都会导致_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次,what?具体可参与官方script-compilation-circuit-breaker,怎么滴也得配置个十几万次吧

总结,使用Update By Query要重点关注上面的4个问题,特别是涉及到大批量的修改,特别要关注监控信息(GET _tasks?detailed=true&actions=*byquery),个人建议要限流,比如:可通过前置mongodb(定时定量去更新)或者更新失败后记录到新的index中后续定时定量去补偿。

Elasticsearch的`update_by_query`是通过查询条件进行文档更新操作的功能,以下为使用方法及相关注意事项: ### 使用方法 #### PHP代码示例 ```php $params = [ 'index' => 'my_index', 'body' => [ 'query' => [ 'bool' => [ 'must' => [ 'range' => [ 'age' => [ 'gt' => '20', 'lt' => '40' ] ] ] ] ], 'script' => [ 'inline' => "ctx._source.name=\"青年人\"; ctx._source.age=30" ] ] ]; $client = Elasticsearch\ClientBuilder::create()->setHosts(['127.0.0.1:9200'])->build(); $res = $client->updateByQuery($params); ``` 此代码通过查询条件筛选出年龄在20到40之间的文档,并将这些文档的`name`字段更新为“青年人”,`age`字段更新为30 [^1]。 #### Java代码示例(ElasticSearch 6.X版本) ```java UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client); updateByQuery.source("source_index").abortOnVersionConflict(false); BulkByScrollResponse response = updateByQuery.get(); ``` 此代码的作用是更新索引`source_index`中的每个文档,而无需更改源,允许拾取新属性或另一个在线映射更改 [^2]。 #### 原生请求示例 ```json POST /your-index/_update_by_query { "script": { "source": "ctx._source.new_field = 'updated value'" }, "query": { "match": { "your_field": "your_value" } } } ``` 此请求会在`your-index`索引中,筛选出`your_field`字段值为`your_value`的文档,并将这些文档添加一个新字段`new_field`,其值为`updated value` [^4]。 ### 注意事项 - **版本要求**:根据查询条件进行文档更新的API是在Elasticsearch 2.3+以上版本添加的 [^1]。 - **配置要求**:在Elasticsearch配置文件`elasticsearch.yml`中需加入如下配置项: ```yaml script.inline: on script.indexed: on ```
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值