Skip to main content

排行榜聚合 top_hits

Top Hits Aggregation

top_hits度量聚合器跟踪正在聚合的最相关文档。该聚合器旨在用作子聚合器,以便每个bucket可以聚合最匹配的文档。

top_hits聚合器可以有效地用于通过bucket聚合器按特定字段对结果集进行分组。一个或多个桶聚合器确定结果集被划分为哪些属性。

Example

在下面的示例中,我们按类型对销售进行分组,并按类型显示上一次销售。对于每次销售,源中只包含日期和价格字段。

POST /sales/_search?size=0
{
"aggs": {
"top_tags": {
"terms": {
"field": "type",
"size": 3
},
"aggs": {
"top_sales_hits": {
"top_hits": {
"sort": [
{
"date": {
"order": "desc"
}
}
],
"_source": {
"includes": [ "date", "price" ]
},
"size" : 1
}
}
}
}
}
}

返回

{
...
"aggregations": {
"top_tags": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "hat",
"doc_count": 3,
"top_sales_hits": {
"hits": {
"total": 3,
"max_score": null,
"hits": [
{
"_index": "sales",
"_type": "_doc",
"_id": "AVnNBmauCQpcRyxw6ChK",
"_source": {
"date": "2015/03/01 00:00:00",
"price": 200
},
"sort": [
1425168000000
],
"_score": null
}
]
}
}
},
{
"key": "t-shirt",
"doc_count": 3,
"top_sales_hits": {
"hits": {
"total": 3,
"max_score": null,
"hits": [
{
"_index": "sales",
"_type": "_doc",
"_id": "AVnNBmauCQpcRyxw6ChL",
"_source": {
"date": "2015/03/01 00:00:00",
"price": 175
},
"sort": [
1425168000000
],
"_score": null
}
]
}
}
},
{
"key": "bag",
"doc_count": 1,
"top_sales_hits": {
"hits": {
"total": 1,
"max_score": null,
"hits": [
{
"_index": "sales",
"_type": "_doc",
"_id": "AVnNBmatCQpcRyxw6ChH",
"_source": {
"date": "2015/01/01 00:00:00",
"price": 150
},
"sort": [
1420070400000
],
"_score": null
}
]
}
}
}
]
}
}
}

字段折叠示例 (Field collapse)

字段折叠或结果分组是一种功能,它在逻辑上将结果集分组,并按组返回顶部文档。组的排序由组中第一个文档的相关性确定。在Elasticsearch中,这可以通过将top_hits聚合器包装为子聚合器的bucket聚合器来实现。

在下面的示例中,我们搜索已爬网的网页。对于每个网页,我们存储网页所属的主体和域。通过在域字段上定义术语聚合器,我们可以按域对网页的结果集进行分组。然后将top_hits聚合器定义为子聚合器,以便每个bucket收集最匹配的命中数。

此外,还定义了一个最大聚合器,术语聚合器的顺序功能使用该最大聚合器按桶中最相关文档的相关性顺序返回桶。

POST /sales/_search
{
"query": {
"match": {
"body": "elections"
}
},
"aggs": {
"top_sites": {
"terms": {
"field": "domain",
"order": {
"top_hit": "desc"
}
},
"aggs": {
"top_tags_hits": {
"top_hits": {}
},
"top_hit" : {
"max": {
"script": {
"source": "_score"
}
}
}
}
}
}
}

目前,需要最大(或最小)聚合器来确保术语聚合器中的桶是根据每个域最相关网页的得分排序的。不幸的是,top_hits聚合器还不能在术语聚合器的order选项中使用。

嵌套或反向嵌套聚合器中的top_hits支持

如果top_hits聚合器包装在嵌套或反向嵌套聚合器中,则返回嵌套命中。嵌套命中在某种意义上是隐藏的迷你文档,它们是常规文档的一部分,在映射中已配置了嵌套字段类型。如果top_hits聚合器被封装在嵌套或反向嵌套聚合器中,则它可以取消隐藏这些文档。阅读有关嵌套类型映射中嵌套的更多信息。

如果已经配置了嵌套类型,则单个文档实际上被索引为多个Lucene文档,并且它们共享相同的id。为了确定嵌套命中的标识,需要的不仅仅是id,因此嵌套命中也包括它们的嵌套标识。嵌套标识保存在搜索命中中的_nested字段下,并包括嵌套命中所属的数组字段中的数组字段和偏移量。偏移量从零开始。

让我们看看它是如何使用真实样本的。考虑以下映射

PUT /sales
{
"mappings": {
"_doc" : {
"properties" : {
"tags" : { "type" : "keyword" },
"comments" : {
"type" : "nested",
"properties" : {
"username" : { "type" : "keyword" },
"comment" : { "type" : "text" }
}
}
}
}
}
}

comments 是一个数组,其中包含product对象下的嵌套文档。

添加一些文档

PUT /sales/_doc/1?refresh
{
"tags": ["car", "auto"],
"comments": [
{"username": "baddriver007", "comment": "This car could have better brakes"},
{"username": "dr_who", "comment": "Where's the autopilot? Can't find it"},
{"username": "ilovemotorbikes", "comment": "This car has two extra wheels"}
]
}

现在可以执行以下 top_hits 聚合(包含在嵌套聚合中):

POST /sales/_search
{
"query": {
"term": { "tags": "car" }
},
"aggs": {
"by_sale": {
"nested" : {
"path" : "comments"
},
"aggs": {
"by_user": {
"terms": {
"field": "comments.username",
"size": 1
},
"aggs": {
"by_nested": {
"top_hits":{}
}
}
}
}
}
}
}

具有嵌套命中的热门命中响应片段,位于数组字段注释的第一个槽中:

{
...
"aggregations": {
"by_sale": {
"by_user": {
"buckets": [
{
"key": "baddriver007",
"doc_count": 1,
"by_nested": {
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [
{
"_index": "sales",
"_type" : "_doc",
"_id": "1",
"_nested": {
"field": "comments",
"offset": 0
},
"_score": 0.2876821,
"_source": {
"comment": "This car could have better brakes",
"username": "baddriver007"
}
}
]
}
}
}
...
]
}
}
}
}