【问题标题】:Get the latest document version and aggregate the results获取最新的文档版本并汇总结果
【发布时间】:2017-08-26 10:13:50
【问题描述】:

我的索引包含很多文档,每个文档都有几个版本,例如:

{"doc_id": 13,
"version": 1,
"text": "bar"}

{"doc_id": 13,
"version": 2,
"text": "bar"}

{"doc_id": 13,
"version": 3,
"text": "bar"}

{"doc_id": 14,
"version": 1,
"text": "foo"}

{"doc_id": 14,
"version": 2,
"text": "bar"}

我想获取每个文档的最新版本,并使用 terms 聚合来聚合它们(最新版本)。
我尝试使用top hits 来检索最新版本:

{"size" :0,
"aggs" : {
    "doc_id_groups" : {
        "terms" : {
            "field" : "doc_id",
            "size" : "0"
        },
        "aggs" : {
            "docs" : {
                "top_hits" : {
                    "size" : 1,
                    "sort" : {
                        "version" : {
                            "order" : "desc"
                        }
                    }
                }
            }
        }
    }
}
}

但我不能进行聚合,因为top hits 不支持子聚合。
我想检索 id 然后聚合它们对于客户端来说是非常繁重的操作。
也许脚本可以帮助?

更新:我忘了提一件事:在聚合文档之前按时间范围过滤,所以我们不知道索引时哪个版本是最新的,只有在搜索时才知道 p>

【问题讨论】:

  • 鉴于上述示例文档,您期望得到什么结果?
  • @jay 我已经编辑了一些例子。我期待这样的事情:"buckets": [ { "key": "bar", "doc_count": 2 }]
  • 您需要一次性完成,还是可以创建二级索引来执行您需要的操作?
  • 您是否真的需要保留文档的旧版本,或者是否可以在新版本出现时将它们移动到另一个索引? (正如您的other question 中所述,索引时间并不重要)
  • @Val 感谢您的关注。可以创建二级索引。也可以将旧版本移动到另一个索引。有一件事我忘了提:在聚合文档之前是按时间范围过滤的,所以我们不知道索引时哪个版本是最新的,只有在搜索时。

标签: elasticsearch nosql


【解决方案1】:

根据chat 中提供的示例和其他详细信息,我认为您无法使用聚合获得所需的结果。但我可以提出一个替代解决方案:

  1. 添加类型为 Boolean 的属性“current” 对于所有最新版本的文档,将设置为 true。如果 插入新版本 - “current”将设置为 false 在旧版本中设置为 true。
  2. 添加将包含多个值的属性“timepoints”。在一天结束时(可以使用任何其他时间段) 当前记录添加当前时间戳(或任何其他 id 期间,例如“09.30.2016”或“Jan”)到“时间点” 数组。

优点

  • 您只需检查时间点是否在“timepoints”数组中即可轻松检索某个时间点的当前记录。

  • 您可以通过一次查询从所有文档中检索所有可用时间点。

  • 您可以按时间点进行聚合,例如统计每个时间点的所有记录。

  • 无需维护多个索引、记录的重复等,算法非常简单。

缺点

  • 不可能在任意时间点获得当前版本,只能获得执行计算时的版本。

  • 如果您过于频繁地运行计算并且您拥有数百万条记录,则“时间点”数组的整体大小可能会显着增加。

解决方法

  • 对于更细粒度的统计信息,每小时运行一次计算。但是每天(或每月或每年)一次从“timepoints”数组中删除一些较早时间段的时间点。最后,您将拥有一组时间点,这些时间点将对应于每年(如果是一年多前)、每个月(如果是一个月前)、每天(如果是一天多前),以及最近一段时间的每小时。当然去除时间点的算法可以根据自己的需要进行改进。

  • 如果您主要使用最新版本的记录 - 将它们存储在单独的索引中,将旧版本存储在另一个索引中。在这种情况下,您甚至不需要“当前”属性,只需遍历当前索引中的所有记录并添加时间戳即可。

如有需要,我可以为您提供上述步骤所需的所有查询。

【讨论】:

  • 很好的解决方案!谢谢!
【解决方案2】:

您应该考虑解决这个客户端问题。我可以想到两种方法来解决它。

  1. 使用滚动 API 浏览所有文档并找到每个文档的最新版本。然后是客户端,由text 聚合。
  2. doc_id 上使用elasticsearch 术语聚合,在version 上使用max aggregation 的子聚合。这将为您提供每个文档 ID 的最新版本。然后创建一个使用第一部分的 doc_id 和版本的布尔 OR 术语过滤器。这个过滤器应该在text 上有一个术语聚合。

无论哪种方式,您都需要做一些客户端工作。我不相信脚本会有所帮助。如果您已经知道每个文档的最新版本号,那么这会容易得多。

【讨论】:

  • 如果我正确理解了您的答案,每个解决方案都需要在客户端存储所有最新版本的 ID,然后再将它们发送到聚合。由于数据量很大,这是不可能的。
  • 你有多少文件?为什么需要保留旧版本的文档?或者,当您添加新版本时,您可以将旧版本移动到不同的索引。另一个想法是在最新版本上设置一个标志,以便您可以按此 isNewest 字段进行过滤,但是您必须索引新版本并更新旧版本 - 进行 2 次重新索引操作。
  • 请在此处查看我们与 Val 的讨论chat.stackoverflow.com/rooms/124396/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-22
  • 2018-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-25
  • 2018-09-27
相关资源
最近更新 更多