首页/数据/NoSQL 速查/_delete_by_query 按条件批量删除
Elasticsearch89 条

_delete_by_query 按条件批量删除

delete_by_query 按查询删除文档并保留索引结构,同样支持切片并行与冲突策略;删除量极大时会留下大量墓碑段,需要配合 force merge 或等待合并。

NoSQL 速查数据更新于 2026-10-13

delete_by_query 做什么

delete_by_query 按查询条件删除文档,同时保留索引结构与 mapping,适合删除「部分数据」而不是整个索引。它同样支持切片并行与冲突处理策略,返回删除数量、版本冲突与批次统计。删除量极大时索引里会留下大量墓碑段,要等合并才能回收空间。

基本信息

接口POST /<index>/_delete_by_query
常用参数conflicts=proceed、slices=auto、wait_for_completion=false
返回计数deleted、version_conflicts、batches、failures
空间回收删除只做标记,磁盘要等段合并后才真正释放
替代方案按时间切索引后直接删整个索引更省资源

典型使用场景

  • 清理超过保留期的数据,但索引还要继续写入
  • 按业务条件删除错误数据,例如误导入的批次
  • 删除命中敏感词或不合规内容的文档
  • 收缩数据量:把临时测试数据从生产索引里剔除
  • 先用 _count 预估范围,再做小批量删除以降低单次压力

常用写法

常用写法
# 删除 90 天前的数据
POST /logs-2024/_delete_by_query?conflicts=proceed
{ "query": { "range": { "@timestamp": { "lt": "now-90d" } } } }

# 先核对命中数量,避免误删
GET /logs-2024/_count
{ "query": { "range": { "@timestamp": { "lt": "now-90d" } } } }

# 大批量删除改为异步执行
POST /logs-2024/_delete_by_query?wait_for_completion=false&slices=auto
{ "query": { "term": { "batch": "bad-2026-10-13" } } }

# 删除后回收空间:对只读索引做段合并
POST /logs-2024/_forcemerge?only_expunge_deletes=true

返回计数读法

计数含义异常信号
deleted成功删除的文档数与 _count 预估差距大说明条件不稳定
version_conflicts版本冲突次数使用跳过策略时要核对是否符合预期
batches执行批次数量批次数极大说明单批太小、整体耗时长
failures失败明细数组非空时逐条看原因再重跑
定期清理历史数据优先用 ILM 的 delete 阶段,或按时间切索引后直接删整个索引;逐条删除需要重写段,资源开销比删索引大得多。
删除任务同样按快照推进,执行期间新写入且符合条件的数据不会被删;周期清理任务要么接受这种漏删,要么在下一轮调度时重新执行一次同条件删除。

易错点

  • 查询条件写错时无法回滚,执行前必须先用 _count 核对命中数量,必要时先在小范围索引上验证
  • 删除文档不会立刻释放磁盘,空间要等段合并才回收,急着扩容前先确认实际释放情况
  • 在持续写入的索引上做大范围删除会显著放大段合并压力,应错峰执行并配合监控
  • 把 delete_by_query 当成按时间清理的首选:按天或按月切索引后直接删索引几乎零成本,逐条删除反而更慢更耗 IO

数据来源与参考

  • Elasticsearch Guide: Delete By Query API
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌