ElasticSearch分组聚合分页
类似SQL里面group by
后分页输出列表。
这里需要分成两个步骤,一个是计算总数,第二个是输出列表。
数据场景:
展示一个车主列表,输入关键字,可以通过车主的姓名、车辆的车牌来搜索出对应的车主数据列表。
添加一个车辆索引:car
,里面包括车主姓名:name
,车主id:uid
,车牌:car_no
因为车主和车辆是一对多的关系,所以我们在车辆索引里面搜索车主的时候需要对uid去重,这里就用到了聚合。
计算聚合桶的个数
方法就是用cardinality
聚合和sum_bucket
聚合结合起来计算。
{
"size": 0,
"query": {
"bool": {
//这里用前缀搜索name和car_no
"should": [
{
"prefix": {
"name": "113566"
}
},
{
"prefix": {
"car_no": "113566"
}
}
],
//should必须至少需要一个匹配,不设置这个,即使没有任何匹配也会返回数据
"minimum_should_match": 1
}
},
"aggs": {
"uid": {
//这里是设置用uid去重,类似sql的group by
"terms": {
"field": "uid"
},
"aggs": {
//对当前桶(bucket)的uid计数,因为上面已经对id去重了,所以每个桶的uid数量都是1
"uid_count": {
"cardinality": {
"field": "uid"
}
}
}
},
//这里是Pipeline Aggregations的Sum Bucket Aggregation
//对上面的uid_count求和
"sun_uid": {
"sum_bucket": {
"buckets_path": "uid>uid_count"
}
}
}
}
返回结果:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 27,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"uid": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 19,
"doc_count": 7,
"uid_count": {
"value": 1
}
},
{
"key": 34,
"doc_count": 7,
"uid_count": {
"value": 1
}
},
{
"key": 15,
"doc_count": 5,
"uid_count": {
"value": 1
}
},
{
"key": 25,
"doc_count": 3,
"uid_count": {
"value": 1
}
},
{
"key": 43,
"doc_count": 2,
"uid_count": {
"value": 1
}
},
{
"key": 39,
"doc_count": 1,
"uid_count": {
"value": 1
}
},
{
"key": 44,
"doc_count": 1,
"uid_count": {
"value": 1
}
},
{
"key": 49,
"doc_count": 1,
"uid_count": {
"value": 1
}
}
]
},
"sun_uid": {
"value": 8
}
}
}
上面的sun_uid.value
就是桶的总数了。
获取分页后的数据列表
{
"size": 0,
"query": {
"bool": {
"should": [
{
"prefix": {
"name": "11356"
}
},
{
"prefix": {
"car_no": "11356"
}
}
],
"minimum_should_match": 1
}
},
"aggs": {
"uid": {
"composite": {
"size": 2,
"sources": [
{
"uid": {
"terms": {
"field": "uid",
"order": "desc"
}
}
}
],
//"after": {
// "uid": 19
//}
}
}
}
}
关键字搜索那里和上面获取总数那里是没有区别的,区别是在聚合那里。
聚合是使用的composite
。
size
:指定本次查询需要获取的数量sources
:里面指定用uid
去重,根据uid
排序。after
:指定获取数据的开始点,这里就是分页的关键了。不指定就是获取的是第一页的数据,如果指定上一页的最后一条数据,就可以获取下一页的数据。
假如sources
里面指定了多字段,在after
里面也是要相应的指定这些字段的值的,如下实例:
GET /_search
{
"size": 0,
"aggs": {
"my_buckets": {
"composite": {
"size": 2,
"sources": [
{ "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
{ "product": { "terms": { "field": "product", "order": "asc" } } }
],
"after": { "date": 1494288000000, "product": "mad max" }
}
}
}
}
数据查询结果会返回一个after_key
,可以直接拿来放到到after
参数里面获取下一页数据。
这里聚合拿到一页车主id数据之后,就可以到车主表里面去获取车主信息了
siez
、after
分页缺点就是只能上一页,下一页,不能跳页。
本文链接:https://360us.net/article/71.html