Elasticsearch:检索“获取最新”折叠/inner_hits 查询中的项目总数

分享于2023年02月22日 elasticsearch opensearch 问答
【问题标题】:Elasticsearch: Retrieving total number of items in a "get most recent" collapse/inner_hits queryElasticsearch:检索“获取最新”折叠/inner_hits 查询中的项目总数
【发布时间】:2023-01-25 18:00:11
【问题描述】:

我有一组带有数字(字符串)和时间戳(日期)字段的文档。我构建了一个查询,以按数值返回最近文档的列表,以及每个数字的计数。

例如,对于像这样的数据集

number timestamp
test-number-1 2023-01-01T00:00:00.000Z
test-number-1 2023-01-02T00:00:00.000Z
test-number-2 2023-01-01T00:00:00.000Z
test-number-3 2023-01-01T00:00:00.000Z
test-number-3 2023-01-02T00:00:00.000Z
test-number-3 2023-01-03T00:00:00.000Z

我会取回这些信息

number timestamp count
test-number-1 2023-01-02T00:00:00.000Z 2
test-number-2 2023-01-01T00:00:00.000Z 1
test-number-3 2023-01-03T00:00:00.000Z 3

很简单, collapse with inner_hits 可以提供帮助。如果我按 timestamp 排序,同时将 size 限制为 1,我只会返回按 number 分组的最新文档。甜的。

{
  "collapse": {
    "field": "number",
    "inner_hits": {
      "name": "most_recent",
      "_source": [
        "id",
        "timestamp",
        "foo",
        "number"
      ],
      "size": 1,
      "sort": [
        {
          "timestamp": "desc"
        }
      ]
    }
  }
}

问题是***计数

这是一个截断的简化结果示例。

{
  "hits": {
    "total": {
      "value": 6, <=== TOTAL HITS COUNT: 6
      "relation": "eq"
    },
    "hits": [ <=== ARRAY SIZE: 3
      {
        "fields": {
          "number": [
            "test-number-1"
          ]
        },
        "inner_hits": {
          "most_recent": {
            "hits": {
              "total": {
                "value": 2,
                "relation": "eq"
              },
              "hits": [
                {
                  "_source": {
                    "number": "test-number-1",
                    "timestamp": "2023-01-02T00:00:00.000Z"
                  }
                }
              ]
            }
          }
        }
      }
    },
    {
...
        "number": [
          "test-number-2"
        ]
...
        "total": {
          "value": 1,
          }
...
    },
    {
...
        "number": [
          "test-number-3"
        ]
...
        "total": {
          "value": 3,
          }
...
    }
  }
}

请注意包含所有 inner_hits 结果的 hits 数组中有 3 个项目,

{
  "hits": {
    "hits": [ <=== ARRAY SIZE: 3
      { ... },
      { ... },
      { ... } 
    ]
  }
}

而查询的总命中数显示为 6 次命中

{
  "hits": {
    "total": {
      "value": 6, <=== TOTAL HITS COUNT: 6
      "relation": "eq"
    }
  }
}

我如何获得真实的点击次数?

以便它显示 3 而不是上面示例中的 6?我希望能够对结果进行分页,所以我的真实查询会限制页面大小,例如

{ "size": 10, "from": 20 }

因此我不能依赖 hits 数组大小,因为在我的情况下,它会被限制为每页 10 个项目。

  • 到目前为止,我能找到的唯一解决方法是将 term_aggregations 添加到查询中,并使用生成的 buckets 数组大小作为总计数值,但我不喜欢它,因为它感觉像是 hack。 { ..., "aggs": { "term_aggregations": { "terms": { "field": "number", "size": 10000 } } } }

【解决方案1】:

你应该使用 terms 聚合和 top_hits 子聚合来实现你想要的,如果你想要 paginate ,我什至会把 composite 聚合混在一起:

POST test/_search
{
  "size": 0,
  "aggs": {
    "pages": {
      "composite": {
        "sources": [
          {
            "number": {
              "terms": {
                "field": "number"
              }
            }
          }
        ]
      },
      "aggs": {
        "hits": {
          "top_hits": {
            "size": 1,
            "_source": [
             "id",
             "timestamp",
             "foo",
             "number"
            ],
            "sort": [
              {
                "timestamp": "desc"
              }
            ]
          }
        }
      }
    }
  }
}

【讨论】: