一、概要
在ES中会分为4种,常用的有度量和桶。后者其实就是前者的细分。比如参加此次活动的人数为1000人,男生占400人女生占 600人。这个1000可以看成是度量,后面的男生女生可看成是桶。
分类
- 桶(bucket):每个桶都与键和文档关联;
- 度量:在一组文档上跟踪和计算度量值;
- 矩阵:对多个字段进行操作并根据从请求的文档字段中撮的值生成矩阵结果;
- 管道:聚合其它聚合的输出;
处理的逻辑如下图所示:
使用时会有一些限制:
- 使用同样的JSON,用aggregations或aggs属性来定义且要给每个聚集起一外名字;
- 运行在查询结果之上,不在查询结果中的不统计。也可以用golbal来统计所有;
- 可以使用后过滤器,查询过程开始时可以使用一种过滤器,在统计时也可以一种在查询后再运行的过滤器称为后过滤器;前者注重结果性能好,后者重准确性能差;用post_filter属性指定。这两种过滤器各有各应用的场景;聚合有四中不同的类型:
度量-全局
计算一组文档的统计值,如某个数值型字段的最大最小值
- 普通统计:min、max、sum、value_count;
- 高级统计:平方、方差、标准差
- 近似统计:百分位(所有结果中比给定值低或高的百分比,比如有10%的用户购买了此商品);基类(某个字段中唯一的值,比如某个UV数量)
存储桶-分组
将文档放入一或多个桶里,并返回这些桶的计数器,相当于分组统计;
- 词条聚集:
- 范围聚集:
- 直方图聚集:
- 嵌套聚集:
- 地址距离聚集:
二、全局度量
单个统计值-avg,max, min, sum
GET /_search
{
"size": 0, #设置后不返回具体数据
"aggs": {"avg_balance": {"avg": {"field": "balance"}}}
}
"aggregations": {
"avg_balance": {
"value": 25701.313313313312
}
//默认如果字段中没有值则忽略,但也可以人为指定一个值,
{"avg": {"field": "balance", "missing":10}}
百分位数-percentiles
这个统计可应用于TP99这样的计算中,比如99.0=49347.16,表示tp99的值为49347.16。这个值也是存在误差的,大概是数据量与百分比成正比,比如50的误差在0.05%左右,99。和的误差在0.25%左右,所以对于大数据量建议计算异常值q(1-q),然后再做减法会更准确。
如果误差过大,也意味着数据分布不均匀。另外也可以用压缩参数来控制 所以在测试时可以随时对比以调整此值。
{
"size": 0,
"aggs": {"stats_balance": {"percentiles": {"field": "balance"}}}
}
"aggregations": {
"stats_balance": {
"values": {
"1.0": 1454.8400000000001,
"5.0": 3590.35,
"25.0": 13686.125,
"50.0": 25980.25,
"75.0": 38152.25,
"95.0": 47607.049999999996,
"99.0": 49347.16
}
}
//自已指定百分比
"percents": "[50, 90, 99]"
//以key-value数组形式返回
"keyed": false
//因为误差的原因,所以想要更高的精度可设置压缩值,用来平衡内存和精度,所以在测试时可以随时对比以调整此值
"tdigest": {"compression": 200} //默认值为100
"aggs": {"stats_balance": {"percentiles": {"field": "balance", "tdigest": {"compression": 200}}}}
百分比聚合-percentile_ranks
{
"size": 0,
"aggs": {
"stats_balance": {
"percentile_ranks": {
"field": "balance",
"values":[500, 4000]
}
}
}
}
//表示值小于500的占了0%, 值小于4000的占了6.1%,后面的值的统计包含了前面的值的占比
"aggregations": {
"stats_balance": {
"values": {
"500.0": 0.0,
"4000.0": 6.135050713363966
}
}
计数-cardinality
{
"size": 0,
"aggs": {"count_balance": {"cardinality": {"field": "balance"}}}
}
"aggregations": {
"count_balance": {
"value": 994
}
}
//precision_threshold参数是一个阈值,如果统计出的数小于这个设定值,则为精确的,否则不太准确(偏差一般在1%~6%左右),最大设定值40000,
//这个参数也会增加开销,如果数量比较大,就没啥必要设置了。
"aggs": {"count_balance": {"cardinality": {"field": "balance", "precision_threshold": 120}}}
统计聚合-extended_stats
这个命令一下会统计出所有的聚合操作
{
"size": 0,
"aggs": {"stats_balance": {"extended_stats": {"field": "balance"}}}
}
"aggregations": {
"stats_balance": {
"count": 999,
"min": 1011.0,
"max": 49989.0,
"avg": 25701.313313313312,
"sum": 2.5675612E7,
"sum_of_squares": 8.5708820711E11,
"variance": 1.9738864723416716E8,
"std_deviation": 14049.507010360441
"std_deviation_bounds": {
"upper": 53800.3273340342,
"lower": -2397.70070740757
}
}
}
std_deviation,表示与平均值正负两个标准差的间隔,可通过 {"extended_stats": {"field": "balance", "sigma": "2", }}这样来个性化设置
地理坐标计算-geo_bounds
{
"size": 0,
"aggs": {"stats_balance": {"geo_bounds": {"field": "balance", "wrap_longitude": true}}}
}
//geo_centroid:地理中心
单值度量-value_count
这个相当于count功能,只不过它提取的是参与计算的值的数量。
{
"size": 0,
"aggs": {"avg_balance": {"value_count": {"field": "balance"}}}
}
"aggregations": {
"avg_balance": {
"value": 999
}
}
中位数偏差-median_absolute_deviation
下面例子说明,中位数是25701,但绝对偏差为12246,说明曲线波动很大,比如一个商品的评分为3,但偏差为2,则说明有人打了1分。需要仔细分析下数据。
{
"size": 0,
"aggs": {"avg_balance": {"avg": {"field": "balance"}},
"review": {"median_absolute_deviation": {"field": "balance"}}}
}
"aggregations": {
"review": {
"value": 12246.0
},
"avg_balance": {
"value": 25701.313313313312
}
}
//同样可以通过压缩参数来控制其精度
"review": {"median_absolute_deviation": {"field": "balance", "compression": 200}}}
三、分组存储桶
每个bucket都与一个条件关联,此条件确定当前上下文中的文档是否落入其中。相当于桶定义了一个数据子集。不同的bucket有不同的分桶策略。单个响应中允许的最大存储桶数由search.max_buckets来限制,默认为10000。如果是多个分片,多数是每个分片返回指定的数量,然后聚合后再截取,比如要求返回10条,则ES每个分片都返回10条数据,经协调节点后再截取其中10条返给客户端。
邻接矩阵聚合-adjacency_matrix
提供一个称为过滤器表达式的集合,类似filters聚合请求,一个过滤器相当于一个bucket。然后求合运算
{
"size": 0,
"aggs": {
"interactions": {
"adjacency_matrix": {
"filters": {
"grapA": {"terms": {"firstname": ["Hattie"]}},
"grapB": {"terms": {"firstname": ["Burton"]}}
}
}
}
}
}
区间聚合-range
基于source,允许用户定义一组范围,每个范围代表一个桶,范围包含from值,但不包含to值。
"account_number_range": {
"range": {
"field": "account_number",
"ranges": [
{"to": 100},
{"from": 100,"to": 200},
{"from": 200}
]
}
}
"aggregations": {
"account_number_range": {
"buckets": [
{
"key": "*-100.0",
"to": 100.0,
"doc_count": 99
},
{
"key": "100.0-200.0",
"from": 100.0,
"to": 200.0,
"doc_count": 100
},
{
"key": "200.0-*",
"from": 200.0,
"doc_count": 800
}
]
}
}
//" keyed":true, //可选参数,把上面结果的key做为json串的key。即数组变对象
//{"to": 100, key="cheap"}, //人为指定,建议用这种
日期区间-date_range
{
"size": 0,
"aggs": {
"account_number_range": {
"date_range": {
"field": "account_number",
"format": "MM-YY",
"ranges": [
{"to": "now-10M/M"}, //当前时间udfcu10个月并四舍五入到月初
{"from": "now-10M/M"}
]
}
}
}
}
//可选参数,同时也支持keyed和key参数
"time_zone":"CET"
IP区间-ip_range
{
"size": 0,
"aggs": {
"account_number_range": {
"ip_range": {
"field": "ip",
"ranges": [
{"to": "10.0.0.5"}, //也可定义为 {"mask":"10.0.0.5/255"}
{"from": "10.0.0.155"}
]
}
}
}
}
//可选参数,同时也支持keyed和key参数
动态桶聚合-Term
是一种多桶值聚合,其中桶是动态构建的。每个唯一值对应一个桶。有一个size参数,因为协调原因,所以此值越大,结果越准确,相应的开销也大。它与另一个参数shard_size有点关系,默认shard_size要大于等于size。要查询的分片数量(shard_size)参数=size*1.5+10,所以当分片数过多时,会有部分数据统计不到。如果过小则直接重置为10。
{
"size": 0,
"aggs": {
"genres": {
"terms": {
"field": "age"
}
}
}
}
"aggregations": {
"genres": {
"doc_count_error_upper_bound": 0, #错误文档计数
"sum_other_doc_count": 463, #当唯一值太多时,es只返回一部分,即前10个桶,这个值表示还有463的记录未统计
"buckets": [ //前10个桶,按doc_count倒序排列
{
"key": 31,
"doc_count": 61
},
....
]
}
}
//可选参数,设置结果返回值
"terms": {
"field": "age",
"size": 3
}
//调整查询分片的数量,查看上面的公式
"shard_size":20
//由于这是一个近似值,所以可以通过加参数来查询每一个桶的错误数,
"terms": {
"field": "age",
"size": 3,
"show_term_doc_count_error": true
}
自定义排序-order
//自定义排序
"terms": {
"field": "age",
"size": 3,
"show_term_doc_count_error": true,
"order": {"_count":"asc"} //可选的有_key可以有多个
}
//自定义排序
{
"size": 0,
"aggs": {
"genres": {
"terms": {
"field": "age",
"size": 3,
"show_term_doc_count_error": true,
"order": {"max_count": "desc"}
},
"aggs": {
"max_count": {"max": { "field": "age"}}
}
}
}
}
过滤-min_doc_count
只返回超过某个值的term,默认为1
"min_doc_count": 10,
直方图聚合-histogram
其实就是自动设计间隔, interval指值多少一间隔,例子中表示年龄按3岁一间隔来统计。
{
"size": 0,
"aggs": {
"genres": {
"histogram": {
"field": "age",
"interval": 3
}
}
}
}
"aggregations": {
"genres": {
"buckets": [
{
"key": 18.0,
"doc_count": 44
},
{
"key": 21.0,
"doc_count": 139
},
{
"key": 24.0,
"doc_count": 143
},
...
{
"key": 39.0,
"doc_count": 105
}
]
}
边界处理,但这个值没啥用,因为它不会过滤桶,想过滤数据需要在query条件上做过滤。但可以用于补全数据或探索边界用,
{
"size": 0,
"aggs": {
"genres": {
"histogram": {
"field": "age",
"interval": 3,
"extended_bounds": {
"min": 0,
"max": 10
}
}
}
}
}
过滤器聚合-filter
用于当当前聚合上下文缩小到一组特定的文档,本质是在term聚合中增加了过滤器。
{
"size": 0,
"aggs": {
"age": {
"filter": { "term": { "age": "36" } },
"aggs": { "avg_age" : {"avg":{"field": "age"}}
}
}
}
}
"aggregations": {
"age": {
"doc_count": 52,
"avg_age": {
"value": 36.0
}
}
}
多过滤器聚合-filters
这里注意是两个filters嵌套的方式实现多条件写法。
{
"size": 0,
"aggs": {
"messag2es": {
"filters": {
"filters": {
"age1": {
"match": {
"age": "32"
}
},"age2": {
"match": {
"age": "33"
}
}
}
}
}
}
}
"aggregations": {
"messag2es": {
"buckets": {
"age1": {
"doc_count": 51
},
"age2": {
"doc_count": 50
}
}
}
}
不匹配的文档单独列出一列 other_bucket_key,这是定义一个名为ddd的key,里面放的是全部文档其了age1和age2其它的统计数据的和。
{
"size": 0,
"aggs": {
"messag2es": {
"filters": {
"other_bucket_key": "other_without_result",
"filters": {
"age1": {
"match": {
"age": "32"
}
},"age2": {
"match": {
"age": "33"
}
}
}
}
}
}
}
四、高级聚合
嵌套统计
{
"size": 0,
"aggs": {
"account_number_range": {
"range": {
"field": "account_number",
"ranges": [
{"to": 100},
{"from": 100,"to": 200},
{"from": 200}
]
},
"aggs": {
"stats": {
"stats": {"field": "account_number"}
}
}
}
}
}
{
"key": "100.0-200.0",
"from": 100.0,
"to": 200.0,
"doc_count": 100,
"stats": {
"count": 100,
"min": 100.0,
"max": 199.0,
"avg": 149.5,
"sum": 14950.0
}
}