Elasticsearch 除了支持海量数据的搜索以外,还提供了针对 Elasticsearch 数据进行统计分析的功能,具有海量数据高实时性的特点。

Aggregation 属于 Search 的一部分,一般情况下,建议将其 Size 指定为 0

聚合的分类

  • Bucket Aggregation:一些列满足特定条件的文档的集合,类似于 Mysql 中的 GROUP BY 分组。
  • Metric Aggregation:一些数学运算,可以对文档字段进行统计分析,类似于 Mysql 中的 count、sum等。
  • Pipeline Aggregation:对一些其他的聚合结构进行二次聚合
  • Matrix Aggregation:支持对多个字段的操作并提供一个结果矩阵

    Bucket 分桶

    Terms 分桶

    ```json

    my_index:索引名称

    bucket_name 聚合名称

    type.keyword 聚合字段

GET my_index/_search { “size”: 0, “aggs”: { “bucket_name”: { “terms”: { “field”: “type.keyword” } } } }

  1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/239051/1647572222168-71a92811-deb8-43d6-95f8-e792cf2dde4f.png#clientId=u3247ac91-aeb6-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=uca465585&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1524&originWidth=1840&originalType=url&ratio=1&rotation=0&showTitle=false&size=575313&status=done&style=none&taskId=u5c31e75e-aa66-4d7b-bd8a-f67b29d9d74&title=)
  2. <a name="S6ztX"></a>
  3. ### Range 分桶
  4. ```json
  5. # my_index:索引名称
  6. # price_ranges:聚合名称
  7. # price:聚合字段
  8. GET my_index/_search
  9. {
  10. "aggs": {
  11. "price_ranges": {
  12. "range": {
  13. "field": "price",
  14. "ranges": [
  15. { "key": "cheap", "to": 100 },
  16. { "key": "average", "from": 100, "to": 200 },
  17. { "key": "expensive", "from": 200 }
  18. ]
  19. }
  20. }
  21. }
  22. }

Histogram 分桶

以某个数值为区间,对范围数据进行分桶

  1. # products:索引名称
  2. # price_histogram:聚合名称
  3. # price:聚合字段
  4. POST /products/_search
  5. {
  6. "query": {
  7. "match_all": {}
  8. },
  9. "aggs": {
  10. "price_histogram": {
  11. "histogram": {
  12. "field": "price",
  13. "interval": 1000,
  14. "extended_bounds": {
  15. "min": 0,
  16. "max": 10000
  17. }
  18. }
  19. }
  20. }
  21. }

Top Hits 分桶内容

找出指定数量的分桶信息

  1. # my_index:索引名称
  2. # goods_nameprice_order:聚合名称
  3. # goods_nameprice:聚合字段
  4. POST /my_index/_search
  5. {
  6. "query": {
  7. "match_all": {}
  8. },
  9. "aggs": {
  10. "goods_name": {
  11. "terms": {
  12. "field": "goods_name.keyword"
  13. },
  14. "aggs": {
  15. "price_order": {
  16. "top_hits": {
  17. "from": 0,
  18. "size": 2,
  19. "sort": [
  20. {"price": {"order": "desc"}}
  21. ]
  22. }
  23. }
  24. }
  25. }
  26. }
  27. }

Metric 计算

  1. # my_index:索引名称
  2. # bucket_name 聚合名称
  3. # avg_price / max_price / min_price 聚合结果字段
  4. # deposit 聚合字段
  5. GET /my_index/_search
  6. {
  7. "size": 0,
  8. "aggs": {
  9. "avg_price":{
  10. "avg":{
  11. "field":"deposit"
  12. }
  13. },
  14. "max_price":{
  15. "max":{
  16. "field":"deposit"
  17. }
  18. },
  19. "min_price":{
  20. "min":{
  21. "field":"deposit"
  22. }
  23. }
  24. }
  25. }
Metric 类型 含义
count 文档总数
min 文档最小值
max 文档最大值
avg 文档平均值
sum 文档数求和
stats count、min、max、avg、sum聚合

Pipeline 管道聚合

支持对聚合分析的结果,再次进行聚合分析。Pipeline 的分析结果会输出到原结果中,根据位置的不同,分为:

  • Sibling - 结果和现有分析结果同级
    • Max,Min,Avg & Sum Bucket
    • Stats,Extended Status Bucket
    • Percentiles Bucket
  • Parent - 结果内嵌到现有的聚合分析结果中
    • Derivative(求导)
    • Cumultive Sum(累计求和)
    • Moving Function(滑动窗口) ```json

      products:索引名称

      name_bucket / avg_price / min_goods 聚合结果字段

      找出商品桶平均价格最低的桶

POST /products/_search { “size”: 0, “query”: {“match_all”: {}}, “aggs”: { “name_bucket”: { “terms”: {“field”: “goods_name.keyword”}, “aggs”: { “avg_price”: { “avg”: {“field”: “price”} } } }, “min_goods”: { “min_bucket”: { “buckets_path”: “name_bucket>avg_price” } } } }

  1. | Pipeline 类型 | 含义 |
  2. | --- | --- |
  3. | min_bucket | 文档最小值 |
  4. | max_bucket | 文档最大值 |
  5. | avg_bucket | 文档平均值 |
  6. | stats_bucket | countminmaxavgsum聚合 |
  7. | percentiles_bucket | 百分位 |
  8. ```json
  9. POST employees/_search
  10. {
  11. "size": 0,
  12. "aggs": {
  13. "age": {
  14. "histogram": {
  15. "field": "age",
  16. "min_doc_count": 1,
  17. "interval": 1
  18. },
  19. "aggs": {
  20. "avg_salary": {
  21. "avg": {
  22. "field": "salary"
  23. }
  24. },
  25. "derivative_avg_salary":{
  26. "derivative": {
  27. "buckets_path": "avg_salary"
  28. }
  29. }
  30. }
  31. }
  32. }
  33. }

聚合嵌套

  1. # my_index:索引名称
  2. # bucket_name 聚合名称
  3. # avg_price / max_price / min_price 聚合结果字段
  4. # deposit 聚合字段
  5. GET my_index/_search
  6. {
  7. "size": 0,
  8. "aggs":{
  9. "bucket_name":{
  10. "terms": {
  11. "field": "type.keyword"
  12. },
  13. "aggs":{
  14. "avg_price":{
  15. "avg":{
  16. "field":"deposit"
  17. }
  18. },
  19. "name":{
  20. "terms":{
  21. "field":"nams"
  22. }
  23. }
  24. }
  25. }
  26. }
  27. }

image.png

优化 Terms 聚合的性能

  1. PUT index
  2. {
  3. "mappings": {
  4. "properties": {
  5. "foo": {
  6. "type": "keyword",
  7. "eager_global_ordinals": true
  8. }
  9. }
  10. }
  11. }

聚合的作用范围

Elasticsearch 聚合分析的默认作用范围是 query 的查询集,同时还支持以下方式改变聚合的作用范围:

filter 前置过滤器

过滤查询结果,同时过滤聚合结果

  1. POST /products/_search
  2. {
  3. "aggs": {
  4. "name_bucket": {
  5. "filter": {
  6. "term": {
  7. "goods_name": "php"
  8. }
  9. },
  10. "aggs": {
  11. "avg_price": {
  12. "avg": {"field": "price"}
  13. }
  14. }
  15. }
  16. }
  17. }

post_filter 后置过滤器

过滤查询结果,不过滤聚合查询

  1. POST /products/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "avg_price": {
  6. "avg": {"field": "price"}
  7. }
  8. },
  9. "post_filter": {
  10. "match": {
  11. "goods_name.keyword": "php"
  12. }
  13. }
  14. }

global 全局作用范围

忽略 query 查询中的条件进行聚合

  1. POST /products/_search
  2. {
  3. "query": {
  4. "term": {
  5. "goods_name": {
  6. "value": "php"
  7. }
  8. }
  9. },
  10. "aggs": {
  11. "all_price": {
  12. "global": {},
  13. "aggs": {
  14. "sum_price": {
  15. "sum": {
  16. "field": "price"
  17. }
  18. }
  19. }
  20. }
  21. }
  22. }

聚合排序

  1. POST /products/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "name_bucket": {
  6. "terms": {
  7. "field": "goods_name.keyword",
  8. "order": [
  9. {"_count": "asc"},
  10. {"_key": "desc"}
  11. ]
  12. }
  13. }
  14. }
  15. }
  1. POST /products/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "name_bucket": {
  6. "terms": {
  7. "field": "goods_name.keyword",
  8. "order": [
  9. {"sum_price": "desc"}
  10. ]
  11. },
  12. "aggs": {
  13. "sum_price": {
  14. "sum": {
  15. "field": "price"
  16. }
  17. }
  18. }
  19. }
  20. }
  21. }

聚合原理与聚合精准度

image.png

分桶原理与异常场景

image.png

如何解决 Terms 不准的问题

  • Terms 聚合分析不准的原因,数据分散再多个分片上,Coordinating Node 无法获取数据全貌。
  • 解决方案1:当数据量不大时,设置 Primary Shard 为1;实现准确率。
  • 解决方案2:在分布式数据上,设置 shard_size 参数,提高精准度。
    • 原理:每次从 Shard 上额外多获取数据,提升准确率。
    • 增加了整体的计算量,提高了准确度,但会降低相应时间。
    • shard_size 默认大小设置等于 size * 1.5 + 10
      1. POST /products/_search
      2. {
      3. "size": 0,
      4. "aggs": {
      5. "name_bucket": {
      6. "terms": {
      7. "field": "goods_type",
      8. "size": 3,
      9. "shard_size": 4,
      10. "order": [
      11. {"_count": "desc"}
      12. ]
      13. }
      14. }
      15. }
      16. }

      打开 show_term_doc_count_error

      打开该选项可以查看分桶文档是否正常
      1. POST /products/_search
      2. {
      3. "size": 0,
      4. "aggs": {
      5. "name_bucket": {
      6. "terms": {
      7. "field": "goods_type",
      8. "size": 3,
      9. "show_term_doc_count_error": true
      10. }
      11. }
      12. }
      13. }