top_hits指标聚合器用于跟踪正在聚合的相关文档。
为了让每个桶能聚合最佳文档,该聚合器通常会用作子聚合器(sub aggregator)。
top_hits聚合器能有效地利用桶聚合器,这样它就能根据特定字段来对结果集进行分组。
一个或多个桶聚合器可确定如何将结果集切分到哪个属性中.
选项
- from - 要获取的第一个结果的偏移.
- size - 每个桶返回的最大匹配数。默认只返回前三个匹配.
- sort - 指定匹配的排序方式. 默认会主查询的评分排序(降序).
每个匹配支持的特性
由于top_hits聚合支持多个命中特性,因此它能返回常规搜索命中:
- Highlighting
- Explain
- Named filters and queries
- Source filtering
- Stored fields
- Script fields
- Doc value fields
- Include versions
示例
在下面的示例中,我们会根据tag来对questions进行分组,对于每个tag,我们只显示最后激活的问题.对于每个问题,source中只包含title字段(示例中是date和price字段).
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": "sale",
"_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": "sale",
"_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": "sale",
"_id": "AVnNBmatCQpcRyxw6ChH",
"_source": {
"date": "2015/01/01 00:00:00",
"price": 150
},
"sort": [
1420070400000
],
"_score": null
}
]
}
}
}
]
}
}
}
字段折叠示例
字段折叠或结果分组只是一种功能,它可以将结果集按逻辑分组,每组返回前面几个文档.
组的顺序由组中第一个文档的相关性所决定. 在Elasticsearch中,这可以通过将top_hits包装为桶聚合的子聚合器来实现.
在下面的示例中,我们将搜索已爬取的网页. 针对每个网页,我们都存储了网页的body和它所属的domain. 通过在domain字段上定义terms聚合,我们可以将结果集按domain进行分组.
然后,我们还将top_hits 聚合定义为了子聚合,以便每个桶收集最佳匹配。
此外,我们还定义了max 聚合,它会使用terms聚合的order特性来返回桶中相关性最高的文档.
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"
}
}
}
}
}
}
}
目前,为了能确保terms聚合中的桶能根据每个域中的相关网页得分进行排序,还需要依靠max (或min)聚合器.不幸的是,top_hits聚合还不能使用terms聚合中的order选项.
top_hits对nested或reverse_nested聚合器的支持
如果将top_hits 聚合包装在nested或reverse_nested 聚合中,那么它会嵌套命中.
嵌套命中在某种意义上是隐藏的迷你文档,它是常规文档的一部分,在映射中已经配置了嵌套字段类型。如果top_hits聚合器包含在 nested 或reverse_nested聚合中,则它会取消这些隐藏文档。
有关嵌套的详细信息,请参考nested类型映射。
如果在单个文档中配置了nested类型,那么在索引时,实际上会产生多个Lucene文档,只不过它们共享了同一id. 为了确定嵌套命中的身份,需要的不仅仅是id,还需要它们的嵌套标识.
嵌套标识保存在搜索命中的_nested字段中,还包括数组字段和嵌套匹配所属的数组字段的偏移量。 偏移量基于零。
考虑以下映射:
PUT /sales
{
"mappings": {
"product" : {
"properties" : {
"tags" : { "type" : "keyword" },
"comments" : { #1
"type" : "nested",
"properties" : {
"username" : { "type" : "keyword" },
"comment" : { "type" : "text" }
}
}
}
}
}
}
1.comments是一个数组,它是product对象下的一个嵌套文档.
添加一些文档:
PUT /sales/product/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 聚合(包装在nested聚合中):
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":{}
}
}
}
}
}
}
}
带有嵌套命中的命中响应片段,它位于数组字段comments的第1个插槽:
{
...
"aggregations": {
"by_sale": {
"by_user": {
"buckets": [
{
"key": "baddriver007",
"doc_count": 1,
"by_nested": {
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [
{
"_nested": {
"field": "comments", #1
"offset": 0 #2
},
"_score": 0.2876821,
"_source": {
"comment": "This car could have better brakes", #3
"username": "baddriver007"
}
}
]
}
}
}
...
]
}
}
}
}
1 包含嵌套命中的数组字段名称
2 嵌套命中在包含数组中的位置
3 nested hit的source
如果请求带有_source,那么只会返回嵌套对象的source部分,不会返回文档的整个source.
嵌套对象内部的存储字段可通过驻包装在nested或reverse_nested聚合内的top_hits聚合来访问.
仅在hit中存在_nested字段时才有嵌套命中 ,反之则没有嵌套命中.
在没有启用_source的情况下,可使用_nested的信息来解析原始source.
如果在映射中定义了多个级别的嵌套对象类型,为了表现嵌套命中的层次(两层或更深),_nested展示的信息也可以是分层的.
在下面的示例中,嵌套命中位于字段nested_grand_child_field的第一个槽中,而它又位于nested_child_field字段的第二个缓冲区中:
...
"hits": {
"total": 2565,
"max_score": 1,
"hits": [
{
"_index": "a",
"_type": "b",
"_id": "1",
"_score": 1,
"_nested" : {
"field" : "nested_child_field",
"offset" : 1,
"_nested" : {
"field" : "nested_grand_child_field",
"offset" : 0
}
}
"_source": ...
},
...
]
}
...
全部指标聚合,请参考
单值指标聚合
多值指标聚合
地理位置相关聚合
可执行Map-Reduce计算的聚合
閱讀更多 Java源 的文章