使用组对聚合进行分区

Partitioning aggregates with groups

我正在尝试对类似于 ElasticSearch 文档中的 the example 的聚合进行分区,但我没有让示例正常工作。

索引中填充了事件类型:

public class Event
{
    public int EventId { get; set; }
    public string SegmentId { get; set; }
    public DateTime Timestamp { get; set; }
}

EventId是唯一的,每个事件都属于特定的SegmentId。每个 SegmentId 都可以与零到多个事件相关联。

问题是: 如何为每个 SegmentId 获取最新的 EventId

我预计唯一细分市场的数量在 1000 万个范围内,而唯一事件的数量要大一到两个数量级。这就是为什么我不认为单独使用 top_hits 是合适的,如 。因此,分区。

示例:

我已经建立了一个包含 1313 个文档(唯一 EventId)的演示索引,属于 101 个不同的 SegmentId(即每个片段 13 个事件)。我希望下面的查询能够工作,但无论我指定哪个 partition 数字,都会返回完全相同的结果。

POST /demo/_search
{
  "size": 0,
  "aggs": {
    "segments": {
      "terms": {
        "field": "segmentId",
        "size": 15,                  <-- I want 15 segments from each query
        "include": {
          "partition": 0,            <-- Trying to retrieve the first partition
          "num_partitions": 7        <-- Expecting 7 partitions (7*15 > 101 segments)
        }
      },
      "aggs": {
        "latest": {
          "top_hits": {
            "size": 1,
            "_source": [
              "timestamp",
              "eventId",
              "segmentId"
            ],
            "sort": {
              "timestamp": "desc"
            }
          }
        }
      }
    }
  }
}

如果我删除 include 并将 size 设置为大于 101 的值,我将获得每个分段的最新事件。但是,我怀疑这是一个百万桶的好方法......

您正在尝试进行 Scroll 聚合。

Scroll API 仅支持搜索查询,不支持聚合。如果您不想使用 Top Hits,如您所说,由于文档数量巨大,您可以尝试:

  1. Parent/Child 方法 - 在其中创建段作为父文档和子文档中的事件。每次添加子文档时,您都可以更新父文档中的时间戳字段。通过这样做,您可以只查询父文档,您将获得您的段 ID + 最后一个事件时间戳

  2. 另一种方法是尝试仅在过去 24 小时内获得最高点击率。因此,您可以添加一个查询以首先过滤过去 24 小时,然后尝试使用 top_hit.

  3. 获取聚合

原来我调查错了问题...我的例子实际上很完美。

问题出在我的本地 ElasticSearch 节点上。我不知道它出了什么问题,但是在另一台机器上重复这个例子时,它起作用了。但是,我无法在我当前的 ES 安装上进行分区。因此,我再次卸载并重新安装了 ElasticSearch,然后该示例成功了。

回答我原来的问题,我提供的例子就是要走的路。我通过使用 cardinality aggregate 来估计产品总数解决了我的问题,我从中得出了合适的分区数。然后我为每个分区循环上面的查询,并将文档添加到最终列表。