ElasticSearch

Stella981
• 阅读 808

在Mysql中,我们可以获取一组数据的 **最大值(Max)最小值(Min)**。同样我们能够对这组数据进行 **分组(Group)**。那么对于Elasticsearch中

我们也可以实现同样的功能,聚合有关资料官方文档内容较多,这里大概分3篇或者4篇博客写这个有关Elasticsearch聚合。

官方对聚合有四个关键字: Metric(指标)Bucketing(桶)Matrix(矩阵)Pipeline(管道)

一、聚合概念

1. ES聚合分析是什么?

概念 Elasticsearch除全文检索功能外提供的针对Elasticsearch数据做统计分析的功能。它的实时性高,所有的计算结果都是即时返回。
Elasticsearch将聚合分析主要分为如下4类:

Metric(指标):   指标分析类型,如计算最大值、最小值、平均值等等 (对桶内的文档进行聚合分析的操作)
Bucket(桶):     分桶类型,类似SQL中的GROUP BY语法 (满足特定条件的文档的集合)
Pipeline(管道): 管道分析类型,基于上一级的聚合分析结果进行在分析
Matrix(矩阵):   矩阵分析类型(聚合是一种面向数值型的聚合,用于计算一组文档字段中的统计信息)

2.ES聚合分析查询的写法

在查询请求体中以aggregations节点按如下语法定义聚合分析:

"aggregations" : {
    "<aggregation_name>" : {                                 <!--聚合的名字 -->
        "<aggregation_type>" : {                               <!--聚合的类型 -->
            <aggregation_body>                                 <!--聚合体:对哪些字段进行聚合 -->
        }
        [,"meta" : {  [<meta_data_body>] } ]?               <!--元 -->
        [,"aggregations" : { [<sub_aggregation>]+ } ]?   <!--在聚合里面在定义子聚合 -->
    }
    [,"<aggregation_name_2>" : { ... } ]*                     <!--聚合的名字 -->
}

说明aggregations 也可简写为 aggs

3、指标(metric)和 桶(bucket)

虽然Elasticsearch有四种聚合方式,但在一般实际开发中,用到的比较多的就是Metric和Bucket。

(1) 桶(bucket)

a、简单来说桶就是满足特定条件的文档的集合。

b、当聚合开始被执行,每个文档里面的值通过计算来决定符合哪个桶的条件,如果匹配到,文档将放入相应的桶并接着开始聚合操作。

c、桶也可以被嵌套在其他桶里面。

(2)指标(metric)

a、桶能让我们划分文档到有意义的集合,但是最终我们需要的是对这些桶内的文档进行一些指标的计算。分桶是一种达到目的地的手段:它提供了一种给文档分组的方法来让

我们可以计算感兴趣的指标。

b、大多数指标是简单的数学运算(如:最小值、平均值、最大值、汇总),这些是通过文档的值来计算的。  

二、指标(Metric)详解

官网: 指标聚合官网文档:Metric

Metric聚合分析分为单值分析和多值分析两类:

#1、单值分析,只输出一个分析结果
min,max,avg,sum,cardinality
#2、多值分析,输出多个分析结果
stats,extended_stats,percentile,percentile_rank,top hits

1、Avg(平均值)

计算从聚合文档中提取的数值的平均值。

POST /exams/_search?size=0 { "aggs" : { "avg_grade" : { "avg" : { "field" : "grade" } } } }

2、Max(最大值)

计算从聚合文档中提取的数值的最大值。

POST /sales/_search?size=0 { "aggs" : { "max_price" : { "max" : { "field" : "price" } } } }

3、Min(最小值)

计算从聚合文档中提取的数值的最小值。

POST /sales/_search?size=0 { "aggs" : { "min_price" : { "min" : { "field" : "price" } } } }

4、Sum(总和)

计算从聚合文档中提取的数值的总和。

POST /sales/_search?size=0 { "query" : { "constant_score" : { "filter" : { "match" : { "type" : "hat" } } } }, "aggs" : { "hat_prices" : { "sum" : { "field" : "price" } } } }

5、 Cardinality(唯一值)

cardinality 求唯一值,即不重复的字段有多少(相当于mysql中的distinct)

POST /sales/_search?size=0 { "aggs" : { "type_count" : { "cardinality" : { "field" : "type" } } } }

6、Stats

stats 统计,请求后会直接显示多种聚合结果

POST /exams/_search?size=0 { "aggs" : { "grades_stats" : { "stats" : { "field" : "grade" } } } }

返回

{ ... "aggregations": { "grades_stats": { "count": 2, "min": 50.0, "max": 100.0, "avg": 75.0, "sum": 150.0 } } }

7、Percentiles

对指定字段的值按从小到大累计每个值对应的文档数的占比,返回指定占比比例对应的值。

1)默认取百分比

默认按照[ 1, 5, 25, 50, 75, 95, 99 ]来统计

GET latency/_search { "size": 0, "aggs" : { "load_time_outlier" : { "percentiles" : { "field" : "load_time" } } } }

返回结果可以理解为:占比为50%的文档的age值 <= 445,或反过来:age<=445的文档数占总命中文档数的50%

{ ... "aggregations": { "load_time_outlier": { "values" : { "1.0": 5.0, "5.0": 25.0, "25.0": 165.0, "50.0": 445.0, "75.0": 725.0, "95.0": 945.0, "99.0": 985.0 } } } }

2)指定分位值

GET latency/_search { "size": 0, "aggs" : { "load_time_outlier" : { "percentiles" : { "field" : "load_time", "percents" : [95, 99, 99.9] } } } }

3) Keyed Response

默认情况下,keyed标志设置为true,它将唯一的字符串键与每个存储桶相关联,并将范围作为哈希而不是数组返回。

GET latency/_search { "size": 0, "aggs": { "load_time_outlier": { "percentiles": { "field": "load_time", "keyed": false } } } }

返回结果

{ ... "aggregations": { "load_time_outlier": { "values": [ { "key": 1.0, "value": 5.0 }, { "key": 5.0, "value": 25.0 }, { "key": 25.0, "value": 165.0 }, { "key": 50.0, "value": 445.0 }, { "key": 75.0, "value": 725.0 }, { "key": 95.0, "value": 945.0 }, { "key": 99.0, "value": 985.0 } ] } } }

8、 Percentile Ranks

上面是通过百分比求文档值,这里通过文档值求百分比。

GET latency/_search { "size": 0, "aggs" : { "load_time_ranks" : { "percentile_ranks" : { "field" : "load_time", "values" : [500, 600] } } } }

返回结果

{ ... "aggregations": { "load_time_ranks": { "values" : { "500.0": 55.1, "600.0": 64.0 } } } }

结果说明:时间小于500的文档占比为55.1%,时间小于600的文档占比为64%,

9、Top Hits

一般用于分桶后获取该桶内匹配前n的文档列表

POST /sales/_search?size=0 { "aggs": { "top_tags": { "terms": { "field": "type", #根据type进行分组 每组显示前3个文档 "size": 3 }, "aggs": { "top_sales_hits": { "top_hits": { "sort": [ { "date": { "order": "desc" #按照时间进行倒叙排序 } } ], "_source": { "includes": [ "date", "price" ] #只显示文档指定字段 }, "size" : 1 } } } } } }

三、示例

下面会针对上面官方文档的例子进行举例说明。

1、添加测试数据

1)创建索引

DELETE /employees PUT /employees/ { "mappings" : { "properties" : { "age" : { "type" : "integer" }, "gender" : { "type" : "keyword" }, "job" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 50 } } }, "name" : { "type" : "keyword" }, "salary" : { "type" : "integer" } } } }

2)添加数据

添加10条数据,每条数据包含:姓名、年龄、工作、性别、薪资

PUT /employees/_bulk { "index" : { "_id" : "1" } } { "name" : "Emma","age":32,"job":"Product Manager","gender":"female","salary":35000 } { "index" : { "_id" : "2" } } { "name" : "Underwood","age":41,"job":"Dev Manager","gender":"male","salary": 50000} { "index" : { "_id" : "3" } } { "name" : "Tran","age":25,"job":"Web Designer","gender":"male","salary":18000 } { "index" : { "_id" : "4" } } { "name" : "Rivera","age":26,"job":"Web Designer","gender":"female","salary": 22000} { "index" : { "_id" : "5" } } { "name" : "Rose","age":25,"job":"QA","gender":"female","salary":18000 } { "index" : { "_id" : "6" } } { "name" : "Lucy","age":31,"job":"QA","gender":"female","salary": 25000} { "index" : { "_id" : "7" } } { "name" : "Byrd","age":27,"job":"QA","gender":"male","salary":20000 } { "index" : { "_id" : "8" } } { "name" : "Foster","age":27,"job":"Java Programmer","gender":"male","salary": 20000} { "index" : { "_id" : "9" } } { "name" : "Gregory","age":32,"job":"Java Programmer","gender":"male","salary":22000 } { "index" : { "_id" : "10" } } { "name" : "Bryant","age":20,"job":"Java Programmer","gender":"male","salary": 9000}

2、求薪资最低值

POST employees/_search { "size": 0, "aggs": { "min_salary": { "min": { "field":"salary" } } } }

返回

ElasticSearch

3、找到最低、最高和平均工资

POST employees/_search { "size": 0, "aggs": { "max_salary": { "max": { "field": "salary" } }, "min_salary": { "min": { "field": "salary" } }, "avg_salary": { "avg": { "field": "salary" } } } }

4、一个聚合,输出多值

POST employees/_search { "size": 0, "aggs": { "stats_salary": { "stats": { "field":"salary" } } } }

返回

ElasticSearch

5、求一共有多少工作类型

POST employees/_search { "size": 0, "aggs": { "cardinate": { "cardinality": { "field": "job.keyword" } } } }

返回

ElasticSearch

注意 我们需要把job的类型为keyword类型,这样就不会分词,把它当成一个整体。

6、查看中位数的薪资

POST employees/_search { "size": 0, "aggs": { "load_time_outlier": { "percentiles": { "field": "salary", "percents" : [50, 99], "keyed": false } } } }

返回

ElasticSearch

发现这些工作的中位数是:21000元。

7、取每个工作类型薪资最高的数据

多层嵌套 根据工作类型分桶,然后按照性别分桶,计算每个桶中工资的最高的薪资。

POST employees/_search { "size": 0, "aggs": { "Job_gender_stats": { "terms": { "field": "job.keyword" }, "aggs": { "gender_stats": { "terms": { "field": "gender" }, "aggs": { "salary_stats": { "max": { "field": "salary" } } } } } } } }

返回

ElasticSearch

参考

1、Elasticsearch核心技术与实战---阮一鸣(eBay Pronto平台技术负责人

2、ES7.3版官方聚合查询API

3、Elasticsearch 聚合分析

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Gson之实例五
前面四篇博客基本上可以满足我们处理的绝大多数需求,但有时项目中对json有特殊的格式规定.比如下面的json串解析:{"tableName":"students","tableData":{"id":1,"name":"李坤","birthDay":"Jun 22, 2012 9:54:49 PM"},{"id":2,"name":"曹贵生"
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这