update_by_query 做什么
update_by_query 先按查询条件做一次快照,再对命中的文档逐条执行更新脚本。它默认遇到版本冲突就中止,也可以选择跳过冲突继续。因为每条文档都要重新索引一遍,所以目标索引不能关闭 _source,否则整个操作无法执行。
基本信息
| 接口 | POST /<index>/_update_by_query |
|---|---|
| 常用参数 | conflicts=proceed、slices=auto、refresh=true、wait_for_completion=false |
| 前置条件 | 文档必须保留 _source,脚本基于原始文档重新索引 |
| 返回计数 | updated、version_conflicts、batches、failures、noops |
| 跟踪方式 | 异步执行后用 _tasks 接口查看进度 |
典型使用场景
- 批量修正历史脏数据:给存量文档补字段或统一默认值
- 给老数据补上新版本才有的标记字段
- 按条件重算派生字段,例如把统计口径换成新规则
- 把某个布尔标记批量置为真或假
- 用脚本移除字段,替代不支持字段级删除的写法
常用写法
常用写法
# 按条件批量更新并递增计数
POST /my-index/_update_by_query?conflicts=proceed&slices=auto
{ "query": { "term": { "flag": true } },
"script": { "source": "ctx._source.count += params.inc", "params": { "inc": 1 } } }
# 异步执行,避免请求超时
POST /my-index/_update_by_query?wait_for_completion=false
{ "query": { "term": { "flag": true } },
"script": { "source": "ctx._source.tag = 'v2'" } }
# 跟踪任务进度
GET /_tasks?detailed=true&actions=*byquery
# 执行前先核对命中数量,避免误改范围
GET /my-index/_count
{ "query": { "term": { "flag": true } } }返回计数读法
| 计数 | 含义 | 异常信号 |
|---|---|---|
| updated | 实际完成更新的文档数 | 远小于预期说明查询条件写窄了 |
| version_conflicts | 版本冲突次数 | 使用跳过冲突策略时必须核对 |
| noops | 脚本执行但结果没变化的文档数 | 占比高说明脚本没起作用 |
| failures | 失败明细数组 | 非空时要逐条看原因再重跑 |
操作期间新写入的文档是否被处理取决于快照时刻,长任务跑完后建议再执行一轮同条件校验,确认没有遗留文档。
slices=auto 会按分片数自动切分并行任务,写放大与 CPU 占用随之上升;在写入高峰执行时把 slices 限成较小值(如 2 到 4)比直接 auto 更可控,慢一点但不会把节点打满。