ElasticSearch-聚合操作

  • 聚合的分类 aggs
  • Metric Aggregation
    • min, max, avg, sum
    • stats, cardinality
  • Bucket Aggregation
    • terms
      • order
      • text -> fielddata
      • range
      • histogram
      • top_hits
  • Pipeline Aggregation
    • min_bucket
    • stats_bucket
    • percentiles_bucket
    • cumulative_sum
  • 聚合的作用范围 Filter, Post Filter, Global
  • 排序 order
  • ES聚合分析不精准原因分析 shard_size

  • Elasticsearch除搜索以外,提供了针对ES 数据进行统计分析的功能
rest 复制代码
"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 对搜索结果去重
rest 复制代码
# 多个 Metric 聚合,找到最低最高和平均工资
POST /employees/_search
{"size":0,"aggs":{
 "max_salary":{"max":{"field":"salary"}},
 "min_salary":{"min":{"field":"salary"}},
 "avg_salary":{"avg":{"field":"salary"}}}}
rest 复制代码
# 一个聚合,输出多值
POST /employees/_search 
{"size":0,"aggs":{"stats_salary":{"stats":{"field":"salary"}}}}
rest 复制代码
# 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
    • 支持嵌套:也就在桶里再做分桶
rest 复制代码
# 对 keword 进行聚合
GET /employees/_search 
{"size":0,"aggs":{"jobs":{"terms":{"field":"job.keyword"}}}}
  • 聚合可配置属性有
    • field:指定聚合字段
    • size:指定聚合结果数量
    • order:指定聚合结果排序方式
  • 默认情况下,Bucket聚合会统计Bucket内的文档数量,记为_count,并且按照_count降序排序
    • 可以指定order属性,自定义聚合的排序方式
rest 复制代码
GET /employees/_search
{"size":0,"aggs":{"jobs":{"terms":{"field":"job.keyword","size":10,
  "order":{"_count":"desc"}}}}}
  • 限定聚合范围
rest 复制代码
# 只对 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
rest 复制代码
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 按区间分桶
rest 复制代码
# 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 按间隔分桶
rest 复制代码
# 工资 0 到 10 万,以 5000 一个区间进行分桶 
POST employees/_search
{"size":0,"aggs":{"salary_histrogram":{"histogram":{
   "field":"salary","interval":5000,"extended_bounds":{"min":0,"max":100000}}}}}
  • top_hits 应用场景:当获取分桶后,桶内最匹配的顶部文档列表
rest 复制代码
# 指定size,不同工种中,年纪最大的3个员工的具体信息 
POST /employees/_search
{"size":0,"aggs":{"jobs":{"terms":{"field":"job.keyword"},
 "aggs":{"old_employee":{"top_hits":{"size":3,
   "sort":[{"age":{"order":"desc"}}]}}}}}}
  • 嵌套聚合
rest 复制代码
# 嵌套聚合,按照工作类型分桶,并统计工资信息 
POST employees/_search
{"size":0,"aggs":{"Job_salary_stats":{"terms":{"field":"job.keyword"},
  "aggs":{"salary":{"stats":{"field":"salary"}}}}}}
rest 复制代码
# 多次嵌套,根据工作类型分桶,然后按照性别分桶,计算工资的统计信息 
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 (移动平均值 )
  • 通过bucket_path关键字指定路径
  • min_bucket 之前结果的最小值
rest 复制代码
# 平均工资最低的工种
# 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 统计分析
rest 复制代码
# 平均工资的统计分析
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 百分位数
rest 复制代码
# 平均工资的百分位数
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 累计求和
rest 复制代码
#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
rest 复制代码
# 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,就能返回相应的桶
rest 复制代码
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 进行精准聚合
      • 适用场景:数据量非常大、聚合精度要求高、响应速度快的业务场景
rest 复制代码
# 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 的文档总数(总数-返回的总数)
相关推荐
老纪的技术唠嗑局17 小时前
告别OpenClaw配置丢失——Mindkeeper内测版邀测
大数据·elasticsearch·搜索引擎
Elasticsearch17 小时前
使用 Elasticsearch + Jina embeddings 进行无监督文档聚类
elasticsearch
勇哥的编程江湖19 小时前
flinkcdc streaming 同步数据到es记录过程
大数据·elasticsearch·flink·flinkcdc
曾阿伦19 小时前
Elasticsearch 7.x 常用命令备忘录
大数据·elasticsearch·搜索引擎
斯特凡今天也很帅20 小时前
Elasticsearch数据库专栏(二)DSL语句总结(更新中)
大数据·elasticsearch·搜索引擎
要记得喝水20 小时前
适用于 Git Bash 的脚本,批量提交和推送多个仓库的修改
git·elasticsearch·bash
二十七剑20 小时前
Elasticsearch的索引问题
大数据·elasticsearch·搜索引擎
A__tao1 天前
Elasticsearch Mapping 一键生成 Java 实体类(支持嵌套 + 自动过滤注释)
java·python·elasticsearch
A__tao1 天前
Elasticsearch Mapping 一键生成 Proto 文件(支持嵌套 + 注释过滤)
大数据·elasticsearch·jenkins
Devin~Y1 天前
高并发电商与AI智能客服场景下的Java面试实战:从Spring Boot到RAG与向量数据库落地
java·spring boot·redis·elasticsearch·spring cloud·kafka·rag