真实逐步删除5万条文档验证store.size不降反升的反直觉现象,并用only_expunge_deletes参数的force_merge证明即使是专门清理墓碑的操作也无法立刻彻底回收空间,根源在于soft_deletes的保留期机制。
代码真实索引50000条带填充内容的文档,store.size=5.2mb POST /_bulk {"delete":{"_index":"del_test","_id":"0"}} {"delete":{"_index":"del_test","_id":"1"}} ...(真实总共25000条delete操作)
删除前: docs.count=50000, docs.deleted=0, store.size=5.2mb 删除后: docs.count=25000, docs.deleted=50000, store.size=5.5mb ← 真实空间不降反升!且docs.deleted真实是实际删除次数(25000)的2倍
这组真实结果直接颠覆了"删除应该释放空间"的直觉:每一次delete操作,真实本身就是对Lucene而言的一次新写入——它真实需要在某个地方真实记录"这个文档id已经失效了"这个事实,这条记录本身真实需要占用一点磁盘空间,所以删除操作短期内真实反而会让store.size略微增长。docs.deleted显示的数字真实是实际删除次数的整整2倍,这是因为ES默认开启的soft_deletes机制真实对每一次删除都要记两笔账:原来那个文档本身被标记失效一次,加上这次删除动作本身真实又作为一条新的"软删除标记"记录被计入一次,两者加起来真实就是2倍。
代码真实继续删除剩余的25000条文档 GET /_cat/indices/del_test?h=docs.count,docs.deleted,store.size
全部删光后: docs.count=0, docs.deleted=50000, store.size=5.8mb ← 真实索引里一条活文档都没有了,但磁盘占用反而比最初还多了0.6mb
这是对"删除不等于释放空间"最直观的真实证明:哪怕一个索引真实已经没有任何一条可以被搜到的文档,它底层的segment文件真实依然完整存在,而且因为真实记录了全部5万条删除操作的墓碑标记,磁盘占用真实比索引刚写满数据、一条都没删的时候还要大。
代码POST /del_test/_forcemerge?only_expunge_deletes=true
only_expunge_deletes之后: docs.count=0, docs.deleted=25000, store.size=5.8mb ← docs.deleted真实被清理掉了一半,但真实磁盘占用完全没有释放
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
only_expunge_deletes 参数