在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" : { "" : { "" : { } [,"meta" : { [] } ]? [,"aggregations" : { []+ } ]? } [,"" : { ... } ]* } 说明: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" } } } } 返回 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" } } } } 返回 5、求一共有多少工作类型 POST employees/_search { "size": 0, "aggs": { "cardinate": { "cardinality": { "field": "job.keyword" } } } } 返回 注意 我们需要把job的类型为keyword类型,这样就不会分词,把它当成一个整体。 6、查看中位数的薪资 POST employees/_search { "size": 0, "aggs": { "load_time_outlier": { "percentiles": { "field": "salary", "percents" : [50, 99], "keyed": false } } } } 返回 发现这些工作的中位数是: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" } } } } } } } } 返回 参考 1、Elasticsearch核心技术与实战---阮一鸣(eBay Pronto平台技术负责人 2、ES7.3版官方聚合查询API 3、Elasticsearch 聚合分析 我相信,无论今后的道路多么坎坷,只要抓住今天,迟早会在奋斗中尝到人生的甘甜。抓住人生中的一分一秒,胜过虚度中的一月一年!(12)https://www.cnblogs.com/qdhxhz/p/11556764.html