- 聚合的分类 aggs
- Metric Aggregation
- min, max, avg, sum
- stats, cardinality
- Bucket Aggregation
- terms
- order
- text -> fielddata
- range
- histogram
- top_hits
- terms
- Pipeline Aggregation
- min_bucket
- stats_bucket
- percentiles_bucket
- cumulative_sum
- 聚合的作用范围 Filter, Post Filter, Global
- 排序 order
- ES聚合分析不精准原因分析 shard_size
- Elasticsearch除搜索以外,提供了针对ES 数据进行统计分析的功能
"aggs" : { # 和 query 同级的关键词
"<aggregation_name>" : { # 自定义的聚合名字
"<aggregation_type>" : { # 聚合的定义: 不同的 type+body
<aggregation_body>
}
[,"meta" : { [<meta_data_body>] } ]?
[,"aggregations" : { [<sub_aggregation>]+ } ]? # 子聚合查询
}
[,"<aggregation_name_2>" : { ... } ]* # 可以包含多个同级的聚合查询
}
聚合的分类
- Metric Aggregation:—些数学运算,可以对文档字段进行统计分析
{"aggs":{"avg_price":{"avg":{"field":"price"}}}}
- Bucket Aggregation: 一些满足特定条件的文档的集合放置到一个桶里,每一个桶关联一个 key
{"aggs":{"by_size":{"terms":{"field":"size"}}}
- Pipeline Aggregation:对其他的聚合结果进行二次聚合
Metric Aggregation
- 单值分析︰只输出一个分析结果
- min, max, avg, sum
- Cardinality(对搜索结果去重)
- 多值分析︰输出多个分析结果
- stats(统计), extended stats
- percentile (百分位), percentile rank
- top hits (排在前面的示例)
- cardinate 对搜索结果去重
# 多个 Metric 聚合,找到最低最高和平均工资
POST /employees/_search
{"size":0,"aggs":{
"max_salary":{"max":{"field":"salary"}},
"min_salary":{"min":{"field":"salary"}},
"avg_salary":{"avg":{"field":"salary"}}}}
# 一个聚合,输出多值
POST /employees/_search
{"size":0,"aggs":{"stats_salary":{"stats":{"field":"salary"}}}}
# cardinate 对搜索结果去重
POST /employees/_search
{"size":0,"aggs":{"cardinate":{"cardinality":{"field":"job.keyword"}}}}
Bucket Aggregation
- 按照一定的规则,将文档分配到不同的桶中,从而达到分类的目的
- Terms,需要字段支持 filedata
- keyword 默认支持 fielddata
- text 需要在 Mapping 中开启 fielddata,会按照分词后的结果进行分桶
- 数字类型
- Range / Data Range
- Histogram(直方图) / Date Histogram
- 支持嵌套:也就在桶里再做分桶
# 对 keword 进行聚合
GET /employees/_search
{"size":0,"aggs":{"jobs":{"terms":{"field":"job.keyword"}}}}
- 聚合可配置属性有
- field:指定聚合字段
- size:指定聚合结果数量
- order:指定聚合结果排序方式
- 默认情况下,Bucket聚合会统计Bucket内的文档数量,记为
_count
,并且按照_count
降序排序- 可以指定order属性,自定义聚合的排序方式
GET /employees/_search
{"size":0,"aggs":{"jobs":{"terms":{"field":"job.keyword","size":10,
"order":{"_count":"desc"}}}}}
- 限定聚合范围
# 只对 salary 在 10000 元以上的文档聚合
GET /employees/_search
{"query":{"range":{"salary":{"gte":10000}}},
"size":0,
"aggs":{"jobs":{"terms":{"field":"job.keyword","size":10,
"order":{"_count":"desc"}}}}}
- 对 Text 字段进行 terms 聚合查询,会失败抛出异常
- 对 Text 字段打开 fielddata,支持terms aggregation
PUT /employees/_mapping
{"properties":{"job":{"type":"text","fielddata":true}}}
# 对 Text 字段进行分词,分词后的 terms
POST /employees/_search
{"size":0,"aggs":{"jobs":{"terms":{"field":"job"}}}}
- Range & Histogram 聚合
- 按照数字的范围,进行分桶
- 在 Range Aggregation 中,可以自定义 Key
- Range 按区间分桶
# Salary Range 分桶,可以自己定义 key
POST employees/_search
{"size":0,"aggs":{"salary_range":{"range":{"field":"salary","ranges":[
{"to":10000},{"from":10000,"to":20000},{"key":">20000","from":20000}]}}}}
- Histogram 按间隔分桶
# 工资 0 到 10 万,以 5000 一个区间进行分桶
POST employees/_search
{"size":0,"aggs":{"salary_histrogram":{"histogram":{
"field":"salary","interval":5000,"extended_bounds":{"min":0,"max":100000}}}}}
- top_hits 应用场景:当获取分桶后,桶内最匹配的顶部文档列表
# 指定size,不同工种中,年纪最大的3个员工的具体信息
POST /employees/_search
{"size":0,"aggs":{"jobs":{"terms":{"field":"job.keyword"},
"aggs":{"old_employee":{"top_hits":{"size":3,
"sort":[{"age":{"order":"desc"}}]}}}}}}
- 嵌套聚合
# 嵌套聚合,按照工作类型分桶,并统计工资信息
POST employees/_search
{"size":0,"aggs":{"Job_salary_stats":{"terms":{"field":"job.keyword"},
"aggs":{"salary":{"stats":{"field":"salary"}}}}}}
# 多次嵌套,根据工作类型分桶,然后按照性别分桶,计算工资的统计信息
POST employees/_search
{"size":0,"aggs":{"Job_gender_stats":{"terms":{"field":"job.keyword"},
"aggs":{"gender_stats":{"terms":{"field":"gender"},
"aggs":{"salary_stats":{"stats":{"field":"salary"}}}}}}}}
Pipeline Aggregation
- 支持对聚合分析的结果,再次进行聚合分析
- Pipeline 的分析结果会输出到原结果中,根据位置的不同,分为两类
- Sibling - 结果和现有分析结果同级
- Max,min,Avg & Sum Bucket
- Stats,Extended Status Bucket
- Percentiles Bucket
- Parent - 结果内嵌到现有的聚合分析结果之中
- Derivative (求导)
- Cumultive Sum (累计求和)
- Moving Function (移动平均值 )
- Sibling - 结果和现有分析结果同级
- 通过bucket_path关键字指定路径
- min_bucket 之前结果的最小值
# 平均工资最低的工种
# min_salary_by_job 结果和 jobs 的聚合同级
POST employees/_search
{"size":0,"aggs":{
"jobs":{"terms":{"field":"job.keyword","size":10},
"aggs":{"avg_salary":{"avg":{"field":"salary"}}}},
"min_salary_by_job":{"min_bucket":{"buckets_path":"jobs>avg_salary"}}}}
- Stats 统计分析
# 平均工资的统计分析
POST employees/_search
{"size":0,"aggs":{
"jobs":{"terms":{"field":"job.keyword","size":10},
"aggs":{"avg_salary":{"avg":{"field":"salary"}}}},
"stats_salary_by_job":{"stats_bucket":{"buckets_path":"jobs>avg_salary"}}}}
- percentiles 百分位数
# 平均工资的百分位数
POST employees/_search
{"size":0,"aggs":{
"jobs":{"terms":{"field": "job.keyword","size":10},
"aggs":{"avg_salary":{"avg":{"field":"salary"}}}},
"percentiles_salary_by_job":{
"percentiles_bucket":{"buckets_path":"jobs>avg_salary"}}}}
- Cumulative_sum 累计求和
#Cumulative_sum 累计求和
POST employees/_search
{"size":0,"aggs":{"age":{"histogram":{"field":"age","min_doc_count":0,"interval":1},
"aggs":{"avg_salary":{"avg":{"field":"salary"}},
"cumulative_salary":{"cumulative_sum":{"buckets_path":"avg_salary"}}}}}}
聚合的作用范围
- ES聚合分析的默认作用范围是query的查询结果集
- ES还支持以下方式改变聚合的作用范围
- Filter, Post Filter, Global
# Query
POST employees/_search
{"size":0,"query":{"range":{"age":{"gte":20}}},
"aggs":{"jobs":{"terms":{"field":"job.keyword"}}}}
# Filter
POST employees/_search
{"size":0,"aggs":{
"older_person":{
"filter":{"range":{"age":{"from":35}}},
"aggs":{"jobs":{"terms":{"field":"job.keyword"}}}},
"all_jobs":{"terms":{"field":"job.keyword"}}}}
# Post field
# 一条语句,找出所有的job类型,还能找到聚合后符合条件的结果
POST employees/_search
{"aggs":{"jobs":{"terms":{"field":"job.keyword"}}},
"post_filter":{"match":{"job.keyword":"Dev Manager"}}}
# global
POST employees/_search
{"size":0,
"query":{"range":{"age":{"gte":40}}},
"aggs":{"jobs":{"terms":{"field":"job.keyword"}},
"all":{"global":{},"aggs":{"salary_avg":{"avg":{"field":"salary"}}}}}}
排序
- 指定order,按照count和key进行排序
- 默认情况,按照count降序排序
- 指定size,就能返回相应的桶
POST employees/_search
{"size":0,
"query":{"range":{"age":{"gte":20}}},
"aggs":{"jobs":{"terms":{"field":"job.keyword",
"order":[{"_count":"asc"},{"_key":"desc"}]}}}}
POST employees/_search
{"size":0,"aggs":{"jobs":{
"terms":{"field":"job.keyword","order":[{"avg_salary":"desc"}]},
"aggs":{"avg_salary":{"avg":{"field":"salary"}}}}}}
POST employees/_search
{"size":0,"aggs":{"jobs":{
"terms":{"field":"job.keyword","order":[{"stats_salary.min":"desc"}]},
"aggs":{"stats_salary":{"stats":{"field":"salary"}}}}}}
ES聚合分析不精准原因分析
- ElasticSearch 在对海量数据进行聚合分析的时候会损失搜索的精准度来满足实时性的需求
- Terms 聚合分析的执行流程
-
不精准的原因: 数据分散到多个分片,聚合是每个分片的取 Top X,导致结果不精准
- 可以不每个分片Top X,而是全量聚合,但势必这会有很大的性能问题
- 如何提高聚合精确度
- 设置主分片为1(7.x版本已经默认为1)
- 适用场景:数据量小的小集群规模业务场景
- 调大 shard_size 值
- shard_size 值越大,结果越趋近于精准聚合结果值
- 官方推荐:
size*1.5+10
- size:是聚合结果的返回值,客户期望返回聚合排名前三,size值就是 3
- shard_size: 每个分片上聚合的数据条数。shard_size 原则上要大于等于 size
- 可以通过
show_term_doc_count_error
参数显示最差情况下的错误值,用于辅助确定 shard_size 大小 - 适用场景:数据量大、分片数多的集群业务场景
- 将size设置为全量值,来解决精度问题
- 将size设置为2的32次方减去1也就是分片支持的最大值,来解决精度问题
- 弊端:如果分片数据量极大,这样做会耗费巨大的CPU 资源来排序,而且可能会阻塞网络
- 适用场景:对聚合精准度要求极高的业务场景,由于性能问题,不推荐使用
- 使用 Clickhouse/Spark 进行精准聚合
- 适用场景:数据量非常大、聚合精度要求高、响应速度快的业务场景
- 设置主分片为1(7.x版本已经默认为1)
# shard_size
GET kibana_sample_data_flights/_search
{"size":0,"aggs":{"weather":{"terms":{"field":"OriginWeather","size":5,
"shard_size":10,"show_term_doc_count_error":true}}}}
- 在 Terms Aggregation 的返回中有两个特殊的数值
- doc_count_error_upper_bound : 被遗漏的term 分桶,包含的文档,有可能的最大值
- sum_other_doc_count: 除了返回结果 bucket的terms以外,其他 terms 的文档总数(总数-返回的总数)