Top_Hits聚合返回常规搜索命中数,因为可以支持许多每次命中的功能:
在下面的示例中,我们按类型对销售进行分组,并按类型显示最后一次销售。对于每次销售,只有日期和价格字段包含在source中。
POST /sales/_search?size=0
{
"aggs": {
"top_tags": {
"terms": {
"field": "type",
"size": 3
},
"aggs": {
"top_sales_hits": {
"top_hits": {
"sort": [
{
"data": {
"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" : {
"value": 3,
"relation": "eq"
},
"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" : {
"value": 3,
"relation": "eq"
},
"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" : {
"value": 1,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "sales",
"_type": "_doc",
"_id": "AVnNBmatCQpcRyxw6ChH",
"_source": {
"date": "2015/01/01 00:00:00",
"price": 150
},
"sort": [
1420070400000
],
"_score": null
}
]
}
}
}
]
}
}
}
字段折叠或结果分组是一种功能,它可以将结果集按逻辑分组,每组返回顶级文档。组的顺序由组中第一个文档的相关性决定。在ElasticSearch中,这可以通过一个将top_hits聚合器包装为子聚合器的bucket聚合器来实现。
在下面的示例中,我们搜索已爬网的网页。对于我们存储的每个网页,其主体和网页所属的域。通过在域字段上定义术语聚合器,我们按域对网页的结果集进行分组。然后,顶部的命中聚合器被定义为子聚合器,以便每个存储桶收集顶部匹配的命中。
此外,还定义了max聚合器,术语聚合器的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"
}
}
}
}
}
}
}
目前,需要使用max(或min)聚合器来确保术语聚合器中的存储桶是根据每个域中最相关网页的得分排序的。不幸的是,术语聚合器的order选项中还不能使用top_hits聚合器。
如果top_hits 聚合器包装在nested 或reverse_nested 聚合器中,则返回嵌套命中。嵌套命中在某种意义上是隐藏的迷你文档,它是常规文档的一部分,在映射中配置了嵌套字段类型。如果顶部“命中”聚合器包装在嵌套或反向“嵌套”聚合器中,则它能够取消隐藏这些文档。阅读有关嵌套类型映射中嵌套的详细信息。
如果已配置嵌套类型,则单个文档实际上被索引为多个Lucene文档,并且它们共享相同的ID。为了确定嵌套命中的标识,需要的不仅仅是ID,因此嵌套命中还包括其嵌套标识。嵌套标识保存在搜索命中的嵌套字段下,包括数组字段和嵌套命中所属的数组字段中的偏移量。偏移量以零为基础。
让我们看看它如何与真实的样本一起工作。考虑到以下映射:
PUT /sales
{
"mappings": {
"properties" : {
"tags" : { "type" : "keyword" },
"comments" : { <1>
"type" : "nested",
"properties" : {
"username" : { "type" : "keyword" },
"comment" : { "type" : "text" }
}
}
}
}
}
还有一些文件:
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":{}
}
}
}
}
}
}
}
具有嵌套命中的top hits响应片段,该命中位于数组字段注释的第一个槽中:
{
...
"aggregations": {
"by_sale": {
"by_user": {
"buckets": [
{
"key": "baddriver007",
"doc_count": 1,
"by_nested": {
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.3616575,
"hits": [
{
"_index": "sales",
"_type" : "_doc",
"_id": "1",
"_nested": {
"field": "comments", <1>
"offset": 0 <2>
},
"_score": 0.3616575,
"_source": {
"comment": "This car could have better brakes", <3>
"username": "baddriver007"
}
}
]
}
}
}
...
]
}
}
}
}
如果请求_source,则只返回嵌套对象源的一部分,而不是文档的整个源。嵌套内部对象级别上的存储字段也可以通过嵌套或反向嵌套聚合器中的Top_Hits聚合器访问。
只有_nested命中才会在命中中有嵌套字段,非嵌套(常规)命中不会有_nested 字段。
如果没有启用_source ,_nested 中的信息也可以用于在其他地方解析原始_source 。
如果在映射中定义了多个层次的嵌套对象类型,那么_nested信息也可以是分层的,以表示两层或更深层的嵌套命中的标识。
在下面的示例中,nested_grand_child_field嵌套“Grand”子字段的第一个槽中,然后驻留在**nested_child_field **的第二个慢槽中:
...
"hits": {
"total" : {
"value": 2565,
"relation": "eq"
},
"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": ...
},
...
]
}
...