Elasticsearch 中为什么会有大量文档插入后变成 deleted?

共 3828字,需浏览 8分钟

 ·

2021-01-27 08:31

1、从两个实战问题开始....

问题1:elasticsearch-head 插件索引文档数显示结果不一致?

一个:3429 ,一个:5291,什么意思?

问题2:批量写入 ES 数据,大量文档状态变成 deleted,什么原因?

数据库读数据,批量插入到es里,id自定义用的数据库的主键值,批量插入后,没有报错,可是用cerebro看,大量文档的状态是deleted,数据库中的主键值百分百没有重复的,不知道为什么会这样?

问题来源:https://elasticsearch.cn/question/11238

以上两个问题都会涉及文档的删除、更新操作,下面我们先说透两个概念,然后再拆解分析问题就容易的多。

2、文档版本号_version

在 Mysql 中插入一条记录,我们直观显示的是一行记录。而 Elasticsearch 是文档型搜索引擎,我们直观看到的是一条 json 记录。如下图所示:

  • _id 代表的唯一 id;
  • _version 代表的文档的版本号。

这时候,我们通常会有疑问?如果对已有数据执行更新或者删除操作后,版本号如何变化?

看个 demo 一探究竟。

DELETE test

# 执行一次
PUT test/_doc/1
{
    "counter" : 2,
    "tags" : ["blue"]
}

# "_version" : 1,
GET test/_doc/1

# "count" : 1, "deleted" : 0
GET test/_stats

# 再执行一次(更新操作)
#  "_version" : 2(版本号 + 1),
PUT test/_doc/1
{
    "counter" : 3,
    "tags" : ["blue","green"]
}

再次写入文档相当于对原有文档执行更新全更新操作,_version 由 1 变成 2。

此时,我们通过 _stats API 发现:deleted 显示为1。

# "count" : 1, "deleted" : 1
GET test/_stats

如下执行 delete 操作后,看下 version 结果:_version 的版本号 + 1。

DELETE test/_doc/1
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 3,
  "result" : "deleted",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}

此时,我们再通过 _stats API 发现:deleted 显示为 3。

由此,初步得出结论:

  • 更新、删除操作实际是在原来文档的基础上版本号 + 1,且每执行一次,版本号 +1 一次。
  • 同时,原来的老版本的文档标记为:deleted 状态,这里能解释问题 2:只重复写入也会有文档标记为 deleted 状态。

3、文档删除、索引删除、文档更新的本质?

3.1 删除文档的本质

  • 删除文档本质:逻辑删除而非物理删除。

在执行删除文档后,待删除文档不会立即将文档从磁盘中删除,而是将文档标记为已删除状态(版本号 _version + 1,  "result" 标记为:"deleted",)。最直观的反应就是被经常问到的问题“怎么删除文档后,磁盘空间不降

随着不断的索引更多的数据,Elasticsearch 将会在后台清理标记为已删除的文档。

如果想要从磁盘上删除,需要借助段合并来实现,具体实践参考:

POST test/_forcemerge?only_expunge_deletes

段合并中参数:“only_expunge_deletes“ 的含义只清除已标记为 deleted 的文档。

# "count" : 0, "deleted" : 0
GET test/_stats

这里不免引申出一个问题,既然文档越删越多,对于历史的冷数据想批量或者全量删除,有没有更快的方式呢?

有的,借助删除索引来删除该索引下的全部数据。

3.2 索引删除的本质

不同于删除文档,删除索引意味着删除其分片、映射和数据。

索引删除本质:物理删除数据。

不同于文档的删除,索引删除会更直接、快速、暴力。删除索引后,与索引有关的所有数据将从直接从磁盘中删除。

索引删除包含两个步骤:

  • 更新集群;
  • 分片从磁盘删除。

这里要强调的是:如果没有索引快照备份或者其他数据备份存在,已删除的索引不可恢复(这个问题至少被问到 10次 +)。

删除索引操作如下:

DELETE test

3.2 更新文档的本质

更新文档的本质:delete + add。

In Lucene, the core engine of Elasticsearch, inserting or updating a document has thesame cost: in Lucene and Elasticsearch, to update means to replace.

表面上是更新,实际上是:Elasticsearch 将旧文档标记为已删除(deleted),并增加(add)一个全新的文档。同删除文档一样,旧文档不能被访问,但,旧文档不会被立即物理删除,除非手动或者定时执行了段合并操作。

4、再来看开篇两个问题

4.1  docs 文档数不一致怎么来的?

我们直接复现一下,再结合上两节的原理给出结论。直接拿 kibana_电商数据(kibana自带)样例数据作为基础数据。

  • 第一步:原始数据大小:都是4675。

  • 第二步:执行批量删除操作。删除:order_id > 584670 的数据。

POST kibana_sample_data_ecommerce/_delete_by_query
{
  "query":{
    "range":{
      "order_id":{
        "gt": 584670
      }
    }
  }
}

返回结果数:

{
  "took" : 100,
  "timed_out" : false,
  "total" : 1246,
  "deleted" : 1246,
  "batches" : 2,
......
}

也就是说,共删除了:1246 条记录。

  • 第三步:再查看结果:

docs 两个值的变化:原来值是第一步截图值:4675。

  • 4675-1246 = 3429 ,初步看:代表文档数精确值大小。
  • 4675+1246 = 5921,初步看:代表文档原有数量 + deleted 文档数大小。

看一下:_stats 的统计如下:

GET kibana_sample_data_ecommerce/_stats

返回结果:

  "_all" : {
    "primaries" : {
      "docs" : {
        "count" : 3429,
        "deleted" : 2492
      },
  • 第一个值大小就是:count;
  • 第二个值大小就是:count + deleted。

这里:deleted 为什么是:2492 = 1246 的2倍。我理解的是(欢迎就这个问题探讨):

  • 原有待删除文档大小:1246
  • 删除执行后,标记为:deleted, version + 1的文档数:1246。

实际测试验证中,大家会看到 deleted 值会变化:最早:2492, 然后变为:1246 ,最后变为:0。

当然,也可以使用 force_merge 强制段合并实现。

4.2 大量文档的状态是deleted,为什么?

我猜测:同步的时候,有相同 id 的文档数据写入了。也就是说:同一条数据写入了两次或多次,这样在 Elasticsearch 里面会做覆盖处理(本质是更新)。

而如前所述,更新的本质是:原有文档标记为已删除,然后再插入一条文档。

所以,可以尝试手动执行一下 force merge 操作,deleted 文档就没有了。 或者,自然等一段时间,待段合并的时机,deleted 文档就没有了。

5、小结

由一个小问题引发的思考和总结。

参考:

  1. https://t.zsxq.com/zfiIIur 

  2. https://www.elastic.co/cn/blog/lucenes-handling-of-deleted-documents

  3. Elasticsearch 官方文档

  4. Elasticsearch 7.X cookbook 英文版

推荐

  1. 关于 Elasticsearch 段合并,这一篇说透了!
  2. 干货 | 论Elasticsearch数据建模的重要性
  3. 从一个实战问题再谈 Elasticsearch 数据建模
  4. 从实战中来,到实战中去——Elasticsearch 技能更快提升方法论

中国最大的 Elastic 非官方公众号
点击查看“阅读原文”,和全球近1000 位Elastic爱好者一起每日精进 Elastic 技能!
浏览 42
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报