干货 | 通透理解Elasticsearch聚合

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 使用Elasticsearch的过程中,除了全文检索,或多或少会做统计操作,而做统计操作势必会使用Elasticsearch聚合操作。类似mysql中group by的terms聚合用的最多,但当遇到复杂的聚合操作时,往往会捉襟见肘、不知所措…这也是社区中聚合操作几乎每天都会被提问的原因。本文基于官方文档,梳理出聚合的以下几个核心问题,目的:将Elasticsearch的聚合结合实际场景说透。

image.png

链接

1、Elasticsearch聚合最直观展示

区别于倒排索引的key value的全文检索,聚合两个示例如下:

如下图,是基于某特定分类的聚合统计结果。

image.png

如下图:是基于月份的聚合统计结果。

image.png

2、Elasticsearch聚合定义

聚合有助于基于搜索查询提供聚合数据。 它基于称为聚合的简单构建块,可以组合以构建复杂的数据。

基本语法结构如下:


"aggregations" : {

   "<aggregation_name>" : {

       "<aggregation_type>" : {

           <aggregation_body>

       }

       [,"meta" : {  [<meta_data_body>] } ]?

       [,"aggregations" : { [<sub_aggregation>]+ } ]?

   }

   [,"<aggregation_name_2>" : { ... } ]*

}

3、Elasticsearch聚合分类

image.png

3.1 分类1:Metric聚合

基于一组文档进行聚合。所有的文档在一个检索集合里,文档被分成逻辑的分组。

类比Mysql中的: MIN(), MAX(), STDDEV(), SUM() 操作。


       单值Metric

               |

              v

SELECT AVG(price) FROM products



        多值Metric

         |          |

         v          v

SELECT MIN(price), MAX(price) FROM products

Metric聚合的DSL类比实现:

{

   "aggs":{

       "avg_price":{

           "avg":{

               "field":"price"

           }

       }

   }

}

Metric聚合操作对比:


Aggregation Elasticsearch MySQL

Avg Yes Yes

Cardinality——去重唯一值 Yes (Sample based) Yes (Exact)——类似:distinct

Extended Stats Yes StdDev bounds missing

Geo Bounds Yes for future blog post

Geo Centroid Yes for future blog post

Max Yes Yes

Percentiles Yes Complex SQL or UDF

Percentile Ranks Yes Complex SQL or UDF

Scripted Yes No

Stats Yes Yes

Top Hits——很重要,易被忽视 Yes Complex

Value Count Yes Yes

其中,Top hits子聚合用于返回分组中Top X匹配结果集,且支持通过source过滤选定字段值。


分类2:Bucketing聚合

基于检索构成了逻辑文档组,满足特定规则的文档放置到一个桶里,每一个桶关联一个key。

类比Mysql中的group by操作,

Mysql使用举例:


          基于size 分桶 ...、

SELECT size COUNT(*) FROM products GROUP BY size


+----------------------+

| size     |  COUNT(*) |

+----------------------+

| S        |   123     | <--- set of rows with size = S

| M        |   456     |

| ...      |  ...      |

bucket聚合的DSL类比实现:


{

 "query": {

   "match": {

     "title": "Beach"

   }

 },

 "aggs": {

   "by_size": {

     "terms": {

       "field": "size"

     }

   },

   "by_material": {

     "terms": {

       "field": "material"

     }

   }

 }

}


Bucketing聚合对比


Aggregation Elasticsearch MySQL

Childen——父子文档 Yes for future blog post

Date Histogram——基于时间分桶 Yes Complex

Date Range Yes Complex

Filter Yes n/a (yes)

Filters Yes n/a (yes)

Geo Distance Yes for future blog post

GeoHash grid Yes for future blog post

Global Yes n/a (yes)

Histogram Yes Complex

IPv4 Range Yes Complex

Missing Yes Yes

Nested Yes for future blog post

Range Yes Complex

Reverse Nested Yes for future blog post

Sampler Yes Complex

Significant Terms Yes No

Terms——最常用 Yes Yes

分类3:Pipeline聚合

对聚合的结果而不是原始数据集进行操作。

想象一下,你有一个日间交易的网上商店,想要了解所有产品的按照库存日期分组的平均价格。

在SQL中你可以写:


SELECT in_stock_since, AVG(price) FROM products GROUP BY in_stock_since。

1

ES使用举例:

以下Demo实现更复杂,按月统计销售额,并统计出月销售额>200的信息。

下一节详细给出DSL,不再重复。


分类4:Matrix聚合

ES6.4官网释义:此功能是实验性的,可在将来的版本中完全更改或删除。


3、Elasticsearch聚合完整举例

3.1 步骤1:动态Mapping,导入完整数据

POST _bulk

{"index":{"_index":"cars","_type":"doc","_id":"1"}}

{"name":"bmw","date":"2017-06-01", "color":"red", "price":30000}

{"index":{"_index":"cars","_type":"doc","_id":"2"}}

{"name":"bmw","date":"2017-06-30", "color":"blue", "price":50000}

{"index":{"_index":"cars","_type":"doc","_id":"3"}}

{"name":"bmw","date":"2017-08-11", "color":"red", "price":90000}

{"index":{"_index":"cars","_type":"doc","_id":"4"}}

{"name":"ford","date":"2017-07-15", "color":"red", "price":20000}

{"index":{"_index":"cars","_type":"doc","_id":"5"}}

{"name":"ford","date":"2017-07-01", "color":"blue", "price":40000}

{"index":{"_index":"cars","_type":"doc","_id":"6"}}

{"name":"bmw","date":"2017-08-01", "color":"green", "price":10000}

{"index":{"_index":"cars","_type":"doc","_id":"7"}}

{"name":"jeep","date":"2017-07-08", "color":"red", "price":110000}

{"index":{"_index":"cars","_type":"doc","_id":"8"}}

{"name":"jeep","date":"2017-08-25", "color":"red", "price":230000}

3.2 步骤2:确认Mapping

GET cars/_mapping

1

3.3 步骤3:Matric聚合实现

求车的平均价钱。


POST cars/_search

{

 "size": 0,

 "aggs": {

   "avg_grade": {

     "avg": {

       "field": "price"

     }

   }

 }

}

3.4 步骤4:bucket聚合与子聚合实现

按照车品牌分组,组间按照车颜色再二次分组。


POST cars/_search

{

 "size": 0,

 "aggs": {

   "name_aggs": {

     "terms": {

       "field": "name.keyword"

     },

     "aggs": {

       "color_aggs": {

         "terms": {

           "field": "color.keyword"

         }

       }

     }

   }

 }

}

3.5 步骤5:Pipeline聚合实现

按月统计销售额,并统计出总销售额大于200000的月份信息。


POST /cars/_search

{

 "size": 0,

 "aggs": {

   "sales_per_month": {

     "date_histogram": {

       "field": "date",

       "interval": "month"

     },

     "aggs": {

       "total_sales": {

         "sum": {

           "field": "price"

         }

       },

       "sales_bucket_filter": {

         "bucket_selector": {

           "buckets_path": {

             "totalSales": "total_sales"

           },

           "script": "params.totalSales > 200000"

         }

       }

     }

   }

 }

}

4、Elasticsearch聚合使用指南

认知前提:知道Elasticsearch聚合远比Mysql中种类要多,可实现的功能点要多。

遇到聚合问题,基于4个分类,查询对应的官网API信息。

以最常见场景为例:


确定是否是分组group by 操作,如果是,使用bucket聚合中的terms聚合实现;

确定是否是按照时间分组操作,如果是,使用bucket聚合中date_histogram的聚合实现;

确定是否是分组,组间再分组操作,如果是,使用bucket聚合中terms聚合内部再terms或者内部top_hits子聚合实现;

确定是否是求最大值、最小值、平均值等,如果是,使用Metric聚合对应的Max, Min,AVG等聚合实现;

确定是否是基于聚合的结果条件进行判定后取结果,如果是,使用pipline聚合结合其他聚合综合实现;

多尝试,多在kibana的 dev tool部分多验证。


参考:

1、https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html

2、http://blog.ulf-wendel.de/2016/aggregation-features-elasticsearch-vs-mysql-vs-mongodb/

3、https://elasticsearch.cn/article/629


image.pngimage.png

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
1月前
|
存储 搜索推荐 Java
|
10天前
|
SQL 安全 数据挖掘
Elasticsearch如何聚合查询多个统计值,如何嵌套聚合?并相互引用,统计索引中某一个字段的空值率?语法是怎么样的?
Elasticsearch聚合查询用于复杂数据分析,包括统计空值率。示例展示了如何计算字段`my_field`非空非零文档的百分比。查询分为三步:总文档数计数、符合条件文档数计数及计算百分比。聚合概念涵盖度量、桶和管道聚合。脚本在聚合中用于动态计算。常见聚合类型如`sum`、`avg`、`date_histogram`等。组合使用可实现多值统计、嵌套聚合和空值率计算。[阅读更多](https://zhangfeidezhu.com/?p=515)
81 0
Elasticsearch如何聚合查询多个统计值,如何嵌套聚合?并相互引用,统计索引中某一个字段的空值率?语法是怎么样的?
|
2天前
|
存储 缓存 自然语言处理
elasticsearch 聚合 : 指标聚合、桶聚合、管道聚合解析使用总结
elasticsearch 聚合 : 指标聚合、桶聚合、管道聚合解析使用总结
|
3天前
|
缓存 Java API
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——聚合与搜索(三)
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——聚合与搜索(三)
|
1月前
|
测试技术 定位技术 API
万字长文:一文彻底搞懂Elasticsearch中Geo数据类型查询、聚合、排序
万字长文:一文彻底搞懂Elasticsearch中Geo数据类型查询、聚合、排序
94800 140
|
1月前
|
存储 缓存 Java
Elasticsearch 8.X 聚合查询下的精度问题及其解决方案
Elasticsearch 8.X 聚合查询下的精度问题及其解决方案
41 0
|
1月前
|
存储 SQL Java
聚合在Elasticsearch中的使用及示例验证
聚合在Elasticsearch中的使用及示例验证
76 0
|
1月前
|
iOS开发 索引 MacOS
Elasticsearch 聚合字段aggregate-metric-double
Elasticsearch 聚合字段aggregate-metric-double
40 0
|
1月前
|
缓存 Java API
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——聚合与搜索(三)
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——聚合与搜索(三)
|
1月前
|
数据库 Python
Python-ElasticSearch客户端的封装(聚合查询、统计查询、全量数据)
Python-ElasticSearch客户端的封装(聚合查询、统计查询、全量数据)
80 0