【问题标题】:Elastic Search document modeling for history历史的 Elastic Search 文档建模
【发布时间】:2026-01-05 16:55:01
【问题描述】:

我想在弹性搜索中存储产品 每个产品都有一些字段(描述、数量、价格、名称)。但是每天价格和数量都可能发生变化。

如何将其存储在弹性搜索中,以便我能够搜索任何产品的所有过去价格?

我是否应该有一个当前值字段的文档和另一个将产品文档作为父文档的文档,并且将有一些日常任务将日期和更改的值添加到数组中?

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    不幸的是,在 ElasticSearch 中没有内置的方法来处理版本控制。 built-in versioning 不是为检索以前的版本而设计的。您需要在应用层控制版本控制。

    我们最终选择做的是像这样存储文档的所有旧副本:

    {
      "unversioned_prop1": "prop1",
      "unversioned_prop2": "prop2",
      ...
      "versions": [
        {
          "version": "version_x",
          "version_metadata": { ... }
          "document": {
            "versioned_prop3": "prop3",
            "versioned_prop4": "prop4"
            ...
          }
        },
        { "version": "version_y", "document": { ... versioned props ... } },
        ...
      ]
      "current": { ... current versioned props ... }
    }
    

    未版本化的属性

    在数组之外拥有未版本化的属性很有用,因为您可能希望为文档的所有版本更新某些属性。此外,它还确保搜索权重的行为可预测。

    它的缺点是需要我们在应用层中将一些信息缝合在一起。

    当前版本

    将当前版本拆分为单独的属性允许您使用search filtering 仅返回文档的最新版本。

    版本元数据

    这包括您可能想要搜索的任何版本信息,例如日期。

    搜索

    您可以像搜索子属性一样轻松搜索版本化属性。所以搜索最终看起来像这样:

    ...
    {
      "match": {"versions.document.versioned_prop": "query string"
    }
    

    这将搜索文档的所有版本,如果匹配则返回组合文档。

    更新

    当我们需要创建新版本时,您可以使用partial update 插入新文档并更新当前文档。

    替代方案

    这种方法的主要缺点是您无法根据版本内部的内容轻松过滤掉某些搜索结果 - 您可能希望在应用程序端过滤它们。

    如果您需要文档独立运行,您可能需要独立索引它们。为此,您可以在所有版本中包含“集合 ID”。集合 ID 对文档是唯一的,并且在所有版本之间共享。

    集合 ID 方法最终遇到了太多问题,我们转向上述方法,并取得了更高水平的成功。


    作为旁注,我personally wouldn't recommend 您使用 ElasticSearch 作为重要记录的主要存储。仅当您可以忍受偶尔的数据丢失时才这样做。

    【讨论】:

      【解决方案2】:

      首先,您不应使用新的数量/价格更新现有文档。

      我会建议每当数量/价格发生变化时,插入新文档。会有重复的字段,但您可以在文档中包含给定日期有关该产品的所有信息。

      您还可以检索该产品的所有文档,它会有自己的值(价格)。数据将在此建模中重复,但我不认为这是一个问题。

      【讨论】: