Elasticsearch 删除、更改文档的过程?

参考回答

Elasticsearch 中,删除和更改文档不是直接修改原有文档,而是采用一种逻辑上的标记和重建机制。具体过程如下:

  1. 删除文档
    删除操作并不会立即将文档从磁盘中移除,而是给文档打上一个“删除标记”(deleted flag)。然后在段(segment)合并时,真正从磁盘上移除这些被标记为删除的文档。

  2. 更改文档
    Elasticsearch 并不支持直接修改文档内容。更改文档的过程实际上是“删除旧文档+添加新文档”的组合。具体步骤如下:

    • 打上旧文档的删除标记。
    • 将修改后的文档作为一个新文档写入索引。
  3. 背后的实现
    这些操作基于 Lucene 的索引机制。Lucene 是不可变的,因此这种逻辑标记和段合并的机制优化了性能。


详细讲解与拓展

为什么删除和更改文档要采用“标记”方式?

  • Lucene 的不可变性
    Elasticsearch 的底层是基于 Lucene 的,而 Lucene 的段(segment)是不可变的。一旦一个段创建后,不能直接修改其中的数据。因此删除或更新文档时,采用标记的方式是更高效的解决方案。

  • 性能优化
    频繁删除或更新文档时,如果每次都立即修改磁盘内容,会导致性能开销巨大。通过打标记的方式,可以将这些操作批量处理,在后续的段合并中一次性清理。

删除文档的过程

  1. 用户发出删除请求。
  2. Elasticsearch 给文档打上“删除标记”。
  3. 被删除文档的数据仍然存在磁盘上,但对用户不可见。
  4. 在段合并(segment merge)过程中,删除标记的文档才会被真正清理。

段合并
段合并是 Elasticsearch 的一项后台任务,会将多个小段合并为一个大段,同时清理掉被标记为删除的文档。段合并的优点是减少段的数量,提升查询效率。

更改文档的过程

  1. 用户发出更改请求。
  2. Elasticsearch 给旧文档打上“删除标记”。
  3. Elasticsearch 将新文档作为一个独立的文档写入索引中。
  4. 查询时,只有新文档会被用户看到,旧文档在段合并中会被清理。

举例说明:

假设有一个索引 products,其中有一篇文档如下:

{
  "_id": "1",
  "name": "Laptop",
  "price": 1000
}
删除文档:

当你执行:

DELETE /products/_doc/1
  • 文档并未从磁盘立即移除,而是被标记为删除。
  • 用户再查询时不会看到该文档。
  • 段合并时,该文档才会被物理移除。
更改文档:

当你执行:

POST /products/_update/1
{
  "doc": {
    "price": 900
  }
}

实际上是两步:
1. 旧文档被标记为删除。
2. 新文档被写入,内容如下:

“`json
{
"_id": "1",
"name": "Laptop",
"price": 900
}
“`

拓展:为何如此设计?

  • 写操作优先:Elasticsearch 优化写入性能,将删除/更改变成写操作(写入新文档),而不是修改已有文档。
  • 段合并是异步的:段合并的异步设计保证了用户操作时的低延迟,同时让清理工作在后台完成。

注意点

  • 删除和更改频繁时,段合并的开销会增加,可能会影响性能。
  • 可以通过调整 merge.policy 参数优化段合并行为,减少资源消耗。

总结

在 Elasticsearch 中,删除和更改文档并不是直接修改原文档,而是通过“删除标记”和“新增文档”完成。这种机制利用了 Lucene 的不可变性特点,确保了性能和效率。段合并是删除和更改的重要组成部分,可以通过调整配置优化其行为。理解这一过程,有助于更高效地设计和使用 Elasticsearch。

发表评论

后才能评论