专栏首页铭毅天下干货 | 通透理解Elasticsearch聚合

干货 | 通透理解Elasticsearch聚合

使用Elasticsearch的过程中,除了全文检索,或多或少会做统计操作,而做统计操作势必会使用Elasticsearch聚合操作。

类似mysql中group by的terms聚合用的最多,但当遇到复杂的聚合操作时,往往会捉襟见肘、不知所措…..这也是社区中聚合操作几乎每天都会被提问的原因。

本文基于官方文档,梳理出聚合的以下几个核心问题,目的:将Elasticsearch的聚合结合实际场景说透。

1、Elasticsearch聚合最直观展示

区别于倒排索引的key value的全文检索,聚合两个示例如下: 如下图,是基于某特定分类的聚合统计结果。

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

2、Elasticsearch聚合定义

聚合是ES除了搜索功能外提供的针对ES数据做统计分析的功能。

搜索引擎的搜索部分侧重于过滤和搜索,而聚合侧重于数据统计和分析。

基本语法结构如下:

 1"aggregations" : {
 2    "<aggregation_name>" : {
 3        "<aggregation_type>" : {
 4            <aggregation_body>
 5        }
 6        [,"meta" : {  [<meta_data_body>] } ]?
 7        [,"aggregations" : { [<sub_aggregation>]+ } ]?
 8    }
 9    [,"<aggregation_name_2>" : { ... } ]*
10}

3、Elasticsearch聚合分类

3.1 分类1:Metric聚合

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

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

 1        单值Metric
 2                |
 3               v
 4SELECT AVG(price) FROM products
 5
 6
 7         多值Metric
 8          |          |
 9          v          v
10SELECT MIN(price), MAX(price) FROM products
11Metric聚合的DSL类比实现:
12{
13    "aggs":{
14        "avg_price":{
15            "avg":{
16                "field":"price"
17            }
18        }
19    }
20}

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使用举例:

1           基于size 分桶 ...、
2SELECT size COUNT(*) FROM products GROUP BY size 
3
4+----------------------+
5| size     |  COUNT(*) |
6+----------------------+ 
7| S        |   123     | <--- set of rows with size = S
8| M        |   456     |
9| ...      |  ...      |

bucket聚合的DSL类比实现:

 1{
 2  "query": {
 3    "match": {
 4      "title": "Beach"
 5    }
 6  },
 7  "aggs": {
 8    "by_size": {
 9      "terms": {
10        "field": "size"
11      }
12    },
13    "by_material": {
14      "terms": {
15        "field": "material"
16      }
17    }
18  }
19}

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中你可以写:

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

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

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

分类4:Matrix聚合

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

3、Elasticsearch聚合完整举例

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

 1POST _bulk
 2{"index":{"_index":"cars","_type":"doc","_id":"1"}}
 3{"name":"bmw","date":"2017-06-01", "color":"red", "price":30000}
 4{"index":{"_index":"cars","_type":"doc","_id":"2"}}
 5{"name":"bmw","date":"2017-06-30", "color":"blue", "price":50000}
 6{"index":{"_index":"cars","_type":"doc","_id":"3"}}
 7{"name":"bmw","date":"2017-08-11", "color":"red", "price":90000}
 8{"index":{"_index":"cars","_type":"doc","_id":"4"}}
 9{"name":"ford","date":"2017-07-15", "color":"red", "price":20000}
10{"index":{"_index":"cars","_type":"doc","_id":"5"}}
11{"name":"ford","date":"2017-07-01", "color":"blue", "price":40000}
12{"index":{"_index":"cars","_type":"doc","_id":"6"}}
13{"name":"bmw","date":"2017-08-01", "color":"green", "price":10000}
14{"index":{"_index":"cars","_type":"doc","_id":"7"}}
15{"name":"jeep","date":"2017-07-08", "color":"red", "price":110000}
16{"index":{"_index":"cars","_type":"doc","_id":"8"}}
17{"name":"jeep","date":"2017-08-25", "color":"red", "price":230000}

3.2 步骤2:确认Mapping

1GET cars/_mapping

3.3 步骤3:Matric聚合实现

求车的平均价钱。

 1POST cars/_search
 2{
 3  "size": 0,
 4  "aggs": {
 5    "avg_grade": {
 6      "avg": {
 7        "field": "price"
 8      }
 9    }
10  }
11}

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

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

 1POST cars/_search
 2{
 3  "size": 0,
 4  "aggs": {
 5    "name_aggs": {
 6      "terms": {
 7        "field": "name.keyword"
 8      },
 9      "aggs": {
10        "color_aggs": {
11          "terms": {
12            "field": "color.keyword"
13          }
14        }
15      }
16    }
17  }
18}

3.5 步骤5:Pipeline聚合实现

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

 1POST /cars/_search
 2{
 3  "size": 0,
 4  "aggs": {
 5    "sales_per_month": {
 6      "date_histogram": {
 7        "field": "date",
 8        "interval": "month"
 9      },
10      "aggs": {
11        "total_sales": {
12          "sum": {
13            "field": "price"
14          }
15        },
16        "sales_bucket_filter": {
17          "bucket_selector": {
18            "buckets_path": {
19              "totalSales": "total_sales"
20            },
21            "script": "params.totalSales > 200000"
22          }
23        }
24      }
25    }
26  }
27}

4、Elasticsearch聚合使用指南

认知前提:知道Elasticsearch聚合远比Mysql中种类要多,可实现的功能点要多。 遇到聚合问题,基于4个分类,查询对应的官网API信息。 以最常见场景为例:

  1. 确定是否是分组group by 操作,如果是,使用bucket聚合中的terms聚合实现;
  2. 确定是否是按照时间分组操作,如果是,使用bucket聚合中date_histogram的聚合实现;
  3. 确定是否是分组,组间再分组操作,如果是,使用bucket聚合中terms聚合内部再terms或者内部top_hits子聚合实现;确定是否是分组,组间再分组操作,
  4. 确定是否是求最大值、最小值、平均值等,如果是,使用Metric聚合对应的Max, Min,AVG等聚合实现;
  5. 确定是否是基于聚合的结果条件进行判定后取结果,如果是,使用pipline聚合结合其他聚合综合实现;

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

参考: 1、http://t.cn/R8Gk7V0 2、http://t.cn/EhxwB63 3、http://t.cn/EhxwDKR

本文分享自微信公众号 - 铭毅天下(gh_0475cf887cf7)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-10-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • React与Redux开发实例精解

    因为我身边掌握React技术栈的同事极少,所以一直只是自己在研究和实践。因此,买这本书想看看其他人都是如何使用这些技术的。从这点上来看,这本书确实起到了这样的作...

    张子阳
  • 使用Spark读取Hive中的数据

    在默认情况下,Hive使用MapReduce来对数据进行操作和运算,即将HQL语句翻译成MapReduce作业执行。而MapReduce的执行速度是比较慢的,一...

    张子阳
  • 吐槽下《MongoDB 实战》(第二版)的翻译

    最近在研究 Mongo,买了华中科技大学出版社的《MongoDB 实战》第二版,但是在看了一个小时后就发现,全书的翻译满满的槽点,不吐不快。

    Yano_nankai
  • 案例分析:程序媛记一次特殊的“故障”处理

    作者 | 兰珊,多年数据库服务经验、主要服务于政府、电网等企。擅长数据库升级、迁移、故障处理。

    数据和云
  • Nginx基于TCP/UDP端口的四层负载均衡(stream模块)配置梳理

    通过我们会用Nginx的upstream做基于http/https端口的7层负载均衡,由于Nginx老版本不支持tcp协议,所以基于tcp/udp端口的四层负载...

    洗尽了浮华
  • 基于tensorflow的一元一次方程回归预测

    安装tensorflow命令:pip install tensorflow 下面一段代码能够成功运行,则说明安装tensorflow环境成功。

    潇洒坤
  • 31、地址新增 — 定义数据结构与获取方式

    (1)让我们进入addressEdit.vue页面填写一条地址,ok,现在假设你已经填写完毕。 (2)这个时候我们点击保存按钮且应该为这个按钮添加一个save...

    Ewall
  • ReactNative之从HelloWorld中看环境搭建、组件封装、Props及State

    开篇呢,先给大家问个好,今天是中秋节,祝大家中秋节快乐!!虽然是中秋节,但是木有回家还是总结一下知识点写写博客吧,想着昨天总结一下的,但是昨天和几个同学小聚了一...

    lizelu
  • 分布式作业 Elastic-Job-Lite 源码分析 —— 作业配置

    一个作业( ElasticJob )的调度,需要配置独有的一个作业调度器( JobScheduler ),两者是 1 : 1 的关系。这点大家要注意下,当然下文...

    芋道源码
  • 科普一下小程序云能力会带来什么影响

    以往我们开发一个小程序或者小游戏,可能会涉及到数据存储的功能(如全网排行榜、获奖记录、留言评论等功能),整个项目,起码要有5个角色要参与到开发中:

    花叔

扫码关注云+社区

领取腾讯云代金券