1. 概念
聚合(aggs)不同于普通查询,是目前学到的第二种大的查询分类,第一种即“query”,因此在代码中的第一层嵌套由“query”变为了“aggs”。用于进行聚合的字段必须是exact value,分词字段不可进行聚合,对于text字段如果需要使用聚合,需要开启fielddata,但是通常不建议,因为fielddata是将聚合使用的数据结构由磁盘(docvalues)变为了堆内存(fielddata),大数据的聚合操作很容易导致OOM,详细原理会在进阶篇中阐述。
聚合分类
分桶聚合(Bucket agregations):类比SQL中的group by的作用,主要用于统计不同类型数据的数量
指标聚合(Metrics agregations):主要用于最大值、最小值、平均值、字段之和等指标的统计
管道聚合(Pipeline agregations):用于对聚合的结果进行二次聚合,如要统计绑定数量最多的标签bucket,就是要先按照标签进行分桶,再在分桶的结果上计算最大值。
语法
json GET product/_search
{"aggs":{"<aggs_name>":{"<agg_type>":{"field":"<field_name>"}}}}
aggs_name:聚合函数的名称
agg_type:聚合种类,比如是桶聚合(terms)或者是指标聚合(avg、sum、min、max等)
field_name:字段名称或者叫域名。
2. 桶聚合:
场景:用于统计不同种类的文档的数量,可进行嵌套统计。
函数:terms
注意:聚合字段必须是exact value,如keyword
3. 指标聚合
场景:用于统计某个指标,如最大值、最小值、平均值,可以结合桶聚合一起使用,如按照商品类型分桶,统计每个桶的平均价格。
函数:平均值:Avg、最大值:Max、最小值:Min、求和:Sum、详细信息:Stats、数量:Value count
4. 管道聚合
场景:用于对聚合查询的二次聚合,如统计平均价格最低的商品分类,即先按照商品分类进行桶聚合,并计算其平均价格,然后对其平均价格计算最小值聚合
函数:Min bucket:最小桶、Max bucket:最大桶、Avg bucket:桶平均值、Sum bucket:桶求和、Stats bucket:桶信息
注意:bucketspath为管道聚合的关键字,其值从当前聚合统计的聚合函数开始计算为第一级。比如下面例子中,myaggs和myminbucket同级, myaggs就是bucketspath值的起始值。
json GET product/_search
{"size":0,
"aggs":{"my_aggs":{"terms":{...
},
"aggs":{"my_price_bucket":{...
}}},
"my_min_bucket":{"min_bucket":{"buckets_path":"my_aggs>price_bucket"}}}}
5. 嵌套聚合
语法:
jsonGETproduct/_search{"size":0,"aggs":{"<agg_name>":{"<agg_type>":{"field":"<field_name>"},"aggs":{"<agg_name_child>":{"<agg_type>":{"field":"<field_name>"}}}}}}
用途:用于在某种聚合的计算结果之上再次聚合,如统计不同类型商品的平均价格,就是在按照商品类型桶聚合之后,在其结果之上计算平均价格
聚合和查询的相互关系
6. 基于query或filter的聚合
语法:
json GET product/_search
{"query":{...
},
"aggs":{...
}}
注意:以上语法,执行顺序为先query后aggs,顺序和谁在上谁在下没有关系。query中可以是查询、也可以是filter、或者bool query
7. 基于聚合结果的查询、
GET product/_search
{"aggs":{...
},
"post_filter":{...
}}
注意:以上语法,执行顺序为先aggs后post_filter,顺序和谁在上谁在下没有关系。
8. 查询条件的作用域
json GET product/_search
{"size":10,
"query":{...
},
"aggs":{"avg_price":{...
},
"all_avg_price":{"global":{},
"aggs":{...
}}}}
上面例子中,avgprice的计算结果是基于query的查询结果的,而allavg_price的聚合是基于all data的
聚合排序
9. 排序规则:
ordertype:count(数量) _key(聚合结果的key值) _term(废弃但是仍然可用,使用_key代替)
json GET product/_search
{"aggs":{"type_agg":{"terms":{"field":"tags",
"order":{"<order_type>":"desc"},
"size":10}}}}
10. 多级排序:即排序的优先级,按照外层优先的顺序
json GET product/_search?size=0{"aggs":{"first_sort":{..."aggs":{"second_sort":{...
}}}}}
上例中,先按照firstsort排序,再按照secondsort排序
11. 多层排序:即按照多层聚合中的里层某个聚合的结果进行排序
json GET product/_search
{"size":0,
"aggs":{"tag_avg_price":{"terms":{"field":"type.keyword",
"order":{"agg_stats>my_stats.sum":"desc"}},
"aggs":{"agg_stats":{..."aggs":{"my_stats":{"extended_stats":{...
}}}}}}}}
上例中,按照里层聚合“my_stats”进行排序
常用的查询函数
12. histogram:直方图或柱状图统计
用途:用于区间统计,如不同价格商品区间的销售情况
语法:
json GET product/_search?size=0{"aggs":{"<histogram_name>":{"histogram":{"field":"price",
#字段名称"interval": 1000,#区间间隔"keyed": true,#返回数据的结构化类型"min_doc_count": <num>,#返回桶的最小文档数阈值,即文档数小于num的桶不会被输出"missing": 1999#空值的替换值,即如果文档对应字段的值为空,则默认输出1999(参数值)}}}}
date-histogram:基于日期的直方图,比如统计一年每个月的销售额
语法:
json GET product/_search?size=0{"aggs":{"my_date_histogram":{"date_histogram":{"field":"createtime",
#字段需为date类型"<interval_type>": "month",#时间间隔的参数可选项"format": "yyyy-MM",#日期的格式化输出"extended_bounds": {#输出空桶"min": "2020-01","max":"2020-12"}}}}}
interval_type:时间间隔的参数可选项
fixed_interval:ms(毫秒)、s(秒)、 m(分钟)、h(小时)、d(天),注意单位需要带上具体的数值,如2d为两天。需要当心当单位过小,会 导致输出桶过多而导致服务崩溃。
calendar_interval:month、year
interval:(废弃,但是仍然可用)
13. percentile 百分位统计 或者 饼状图
计算结果为何为近似值。
percentiles:用于评估当前数值分布情况,比如99 percentile 是 1000 , 是指 99%的数值都在1000以内。常见的一个场景就是我们制定 SLA 的时候常说 99% 的请求延迟都在100ms 以内,这个时候你就可以用 99 percentile 来查一下,看一下 99 percenttile 的值如果在 100ms 以内,就代表SLA达标了。
语法:
json GET product/_search?size=0{"aggs":{"<percentiles_name>":{"percentiles":{"field":"price",
"percents":[
percent1,#区间的数值,如5、10、30、50、99即代表5%、10%、30%、50%、99%的数值分布 percent2,...]}}}}
percentile_ranks: percentile rank 其实就是percentiles的反向查询,比如我想看一下 1000、3000 在当前数值中处于哪一个范围内,你查一下它的 rank,发现是95,99,那么说明有95%的数值都在1000以内,99%的数值都在3000以内。
json GET product/_search?size=0{"aggs":{"<percentiles_name>":{"percentile_ranks":{"field":"<field_value>",
"values":[
rank1,
rank2,
...
]}}}}
版权归原作者 蓝天⊙白云 所有, 如有侵权,请联系我们删除。