Elasticsearch-桶聚合查询详解

打印 上一主题 下一主题

主题 822|帖子 822|积分 2466

媒介

在之前我们详细面熟了es的查询用法,但是es还拥有强大的聚合查询功能,可以得到类似分组,直方图,折线图等数据组合。类似SQL的SUM、AVG、COUNT、GROUP BY
Elasticsearch-02-es的restapi使用
概念

1:ES聚合查询流程

ES聚合查询类似SQL的GROUP by,一般统计分析主要分为两个步骤:


  • 分组
   对查询的数据起首进行一轮分组,可以设置分组条件,例如:新生入学,把所有的学生按专业分班,这个分班的过程就是对学生进行了分组。
  

  • 组内聚合
   组内聚合,就是对组内的数据进行统计,例如:计算总数、求平均值等等,接上面的例子,学生都按专业分班了,那么就可以统计每个班的学生总数, 这个统计每个班学生总数的计算,就是组内聚合计算。
  2:桶的概念

es中满意特定条件的文档的聚集,叫做桶。
桶的就是一组数据的聚集,对数据分组后,得到一组组的数据,就是一个个的桶。
   提示:桶等同于组,分桶和分组是一个意思,ES使用桶代表一组相同特征的数据。
  ES中桶聚合,指的就是先对数据进行分组,ES支持多种分组条件,例如:支持类似SQL的group by根据字段分组,当然ES比SQL更强大,支持更多的分组条件,以满意各种统计需求
3:指标

指标指的是对文档进行统计计算方式,又叫指标聚合。
桶内聚合,说的就是先对数据进行分组(分桶),然后对每一个桶内的数据进行指标聚合。
   说白了就是,前面将数据经过一轮桶聚合,把数据分成一个个的桶之后,我们根据上面计算指标对桶内的数据进行统计。好比计算每个桶内,最大值,最小值,平均值等
  常用的指标有:SUM、COUNT、MAX等统计函数。
ES分组聚合查询

Elasticsearch桶聚合,目的就是数据分组,先将数据按指定的条件分成多个组,然后对每一个组进行统计。 组的概念跟桶是等同的,在ES中统一使用桶(bucket)这个术语。
ES桶聚合的作用跟SQL的group by的作用是一样的,区别是ES支持更加强大的数据分组能力,SQL只能根据字段的唯一值进行分组,分组的数量跟字段的唯一值的数量相等,例如: group by 店铺id, 去掉重复的店铺ID后,有多少个店铺就有多少个分组。
ES常用的桶聚合如下:


  • Terms聚合 - 类似SQL的group by,根据字段唯一值分组
  • Histogram聚合 - 根据数值间隔分组,例如: 价格按100间隔分组,0、100、200、300等等
  • Date histogram聚合 - 根据时间间隔分组,例如:按月、按天、按小时分组
  • Range聚合 - 按数值范围分组,例如: 0-150一组,150-200一组,200-500一组。
Terms聚合 - 类似SQL的group by,根据字段唯一值分组

terms聚合的作用跟SQL中group by作用一样,都是根据字段唯一值对数据进行分组(分桶),字段值相等的文档都分到同一个桶内。
  1. GET person_info/_search
  2. {
  3.   "size": 0,   //这是为了不返回数据,只返回聚合结果
  4.   "aggs": {
  5.     "buket_name": {   // 聚合查询名字,随便取一个
  6.       "terms": {                //聚合类型为: terms
  7.         "field": "source.keyword" //根据source值来分组
  8.       }
  9.     }
  10.   }
  11. }
复制代码
结果:
  1. {
  2.   "took" : 82,
  3.   "timed_out" : false,
  4.   "_shards" : {
  5.     "total" : 3,
  6.     "successful" : 3,
  7.     "skipped" : 0,
  8.     "failed" : 0
  9.   },
  10.   "hits" : {
  11.     "total" : {
  12.       "value" : 6854,
  13.       "relation" : "eq"
  14.     },
  15.     "max_score" : null,
  16.     "hits" : [ ]
  17.   },
  18.   "aggregations" : {
  19.     "buket_name" : {
  20.       "doc_count_error_upper_bound" : 10,
  21.       "sum_other_doc_count" : 1261,
  22.       "buckets" : [
  23.         {
  24.           "key" : "填表",
  25.           "doc_count" : 5340
  26.         },
  27.         {
  28.           "key" : "普查",
  29.           "doc_count" : 56
  30.         },
  31.         {
  32.           "key" : "网上下载",
  33.           "doc_count" : 39
  34.         }
  35.       ]
  36.     }
  37.   }
  38. }
复制代码
java代码

  1. TermsAggregationBuilder termAggBuilder = AggregationBuilders.terms("buket_name").field("analysis.sensitive_words").size(100).minDocCount(0);
  2. searchSourceBuilder.aggregation(termAggBuilder);
  3. ~~~~~~~~
  4.                 try {
  5.             searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
  6.         } catch (IOException e) {
  7.             throw new RuntimeException(e);
  8.         }
  9.         Aggregations aggregations = searchResponse.getAggregations();
  10.         if(aggregations!= null){
  11.             Terms terms = aggregations.get("buket_name");
  12.             List<? extends Terms.Bucket> buckets = terms.getBuckets();
  13.             JSONObject reslut = new JSONObject(true);
  14.             for (Terms.Bucket bucket : buckets) {
  15.                 //分组的key
  16.                 String key = bucket.getKeyAsString();
  17.                 long docCount = bucket.getDocCount();
  18.                 reslut.put(key,docCount);
  19.             }
  20.             return AjaxResult.success(reslut);
  21.         }else {
  22.             return AjaxResult.error("查询无数据");
  23.         }
复制代码
Histogram聚合 - 根据数值间隔分组,可做直方图

histogram(直方图)聚合,主要根据数值间隔分组,使用histogram聚合分桶统计结果,通常用在绘制条形图报表。
  1. GET person_info/_search
  2. {
  3.   "size": 0, //这是为了不返回数据,只返回聚合结果
  4.   "aggs": {
  5.     "buket_name": {  // 聚合查询名字,随便取一个
  6.       "histogram": { // 聚合类型为:histogram
  7.         "field": "age",  //对age字段进行分类
  8.         "interval": 5        //数字间隔为5
  9.       }
  10.     }
  11.   }
  12. }
复制代码
结果:
  1. {
  2.   "took" : 4,
  3.   "timed_out" : false,
  4.   "_shards" : {
  5.     "total" : 3,
  6.     "successful" : 3,
  7.     "skipped" : 0,
  8.     "failed" : 0
  9.   },
  10.   "hits" : {
  11.     "total" : {
  12.       "value" : 6854,
  13.       "relation" : "eq"
  14.     },
  15.     "max_score" : null,
  16.     "hits" : [ ]
  17.   },
  18.   "aggregations" : {
  19.     "buket_name" : {
  20.       "buckets" : [
  21.         {
  22.           "key" : 10,
  23.           "doc_count" : 814
  24.         },
  25.         {
  26.           "key" : 15.0,
  27.           "doc_count" : 1612
  28.         },
  29.         {
  30.           "key" : 20.0,
  31.           "doc_count" : 1290
  32.         },
  33.         {
  34.           "key" : 25.0,
  35.           "doc_count" : 3138
  36.         }
  37.       ]
  38.     }
  39.   }
  40. }
复制代码
Date histogram聚合 - 根据时间间隔分组,可做时间折线图

类似histogram聚合,区别是Date histogram可以很好的处理时间类型字段,主要用于根据时间、日期分桶的场景。
  1. GET person_info/_search
  2. {
  3.   "size": 0,
  4.   "aggs": {
  5.     "buket_name": { //这是为了不返回数据,只返回聚合结果
  6.       "date_histogram": {  // 聚合类型为: date_histogram
  7.         "field": "data",        // 根据date字段分组
  8.         "calendar_interval": "month",                // 分组间隔,详解在下边
  9.         "format" : "yyyy-MM-dd",        // 设置返回结果中桶key的时间格式
  10.         "time_zone": "+08:00",                 //**设置时区,如果存入的时候没设置就不用填**
  11.         "min_doc_count": 0,                        // 没有数据的月份返回0
  12.         "extended_bounds": {                //强制返回的日期区间,既需要填充0的范围
  13.           "min": "2000-01-01",
  14.           "max": "2003-01-01"
  15.         }
  16.       }
  17.     }
  18.   }
  19. }
复制代码
结果:
  1. {
  2.   "took" : 17,
  3.   "timed_out" : false,
  4.   "_shards" : {
  5.     "total" : 3,
  6.     "successful" : 3,
  7.     "skipped" : 0,
  8.     "failed" : 0
  9.   },
  10.   "hits" : {
  11.     "total" : {
  12.       "value" : 6854,
  13.       "relation" : "eq"
  14.     },
  15.     "max_score" : null,
  16.     "hits" : [ ]
  17.   },
  18.   "aggregations" : {
  19.     "buket_name" : {
  20.       "buckets" : [
  21.         {
  22.           "key_as_string" : "2002-01-01",
  23.           "key" : 1009843200000,
  24.           "doc_count" : 5
  25.         }
  26.       ]
  27.     }
  28.   }
  29. }
复制代码
参考
参数说明1:“time_zone”: “+08:00”



  • 日期(date)类型的字段在 es中是以 long类型的值保存的。
  • es中默认 默认的时区是 0时区。
  • 假如我们有一个东八区的时间,那么在es中是如何存储的呢?
  • 假如我们此时存在 如下 东八区时间 2022-11-29 12:12:12,那么在 es 会存储为 2022-11-29 12:12:12 +0000 对应的时间戳,为什么会加上+0000,由于我们自己的时间字符串中没偶然区,就会加上默认的0时区。
  • 也可用 时差(offset)来表示,使用 offset 参数按指定的正(+)或负(-)偏移量持续时间来更改每个桶的起始值,例如1h表示一个小时,1d表示一天。例如,当使用day作为时间间隔时,每个桶的时间区间从午夜到午夜。 将参数 offset 设置为 +6h 会将每个桶的时间区间更改为从早上6点到早上6点:
参数说明2:fixed_interval 和calendar_interval 区别



  • 原本的interval 字段在7.2中被弃用
  • 日历感知间隔是用参数 calendar_interval 配置的。 日历间隔只能以单位的“单数”数量指定(1d、1M等)。 不支持像 2d如许的倍数,否则会引发异常。
   minute (1m)
hour(1h)
day(1d)
week(1w)
month(1m)
quarter( 季度1q)
year(1y)
  

  • 固定间隔是用参数 fixed_interval 配置的。
   与日历感知间隔差别,固定间隔是固定命量的国际单位制(SI)单位,无论它们在日历上的位置如何,都不会偏离。 一秒钟总是由1000毫秒构成。 这允许以支持单位的任何倍数值指定固定间隔。
然而,这意味着固定的间隔不能表达其他单位,如“月(month)”,由于一个月的持续时间不是一个固定的量。 试图指定月或季度(quarter)等日历间隔将引发异常。
    固定间隔支持的单位有:
毫秒 (ms)
秒 (s):定义为每个1000毫秒
分钟 (m):所有分钟都从00秒开始。 定义为每个60秒(60,000毫秒)
小时 (h):所有小时都从00分00秒开始。 定义为每60分钟(3,600,000毫秒)
天 (d):所有天都在尽大概早的时间开始,通常是00:00:00(午夜)。 定义为24小时(86,400,000毫秒)
  java代码

  1. DateHistogramAggregationBuilder dateHisAggBuilder = AggregationBuilders.dateHistogram("trendWeek")
  2.                 .field("data_time")
  3.                 .fixedInterval(DateHistogramInterval.DAY)//设置多久一个点
  4.                 .minDocCount(0);//设置查询最小文档数为0,为了占位使用
  5.                
  6. searchSourceBuilder.aggregation(dateHisAggBuilder);
  7. ~~~~~
  8.                 try {
  9.             searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
  10.         } catch (IOException e) {
  11.             throw new RuntimeException(e);
  12.         }
  13.         Aggregations aggregations = searchResponse.getAggregations();
  14.         if(aggregations!= null){
  15.             Histogram histogram = aggregations.get("trendWeek");
  16.             List<? extends Histogram.Bucket> buckets = histogram.getBuckets();
  17.             JSONObject reslut = new JSONObject(true);
  18.             for (Histogram.Bucket bucket : buckets) {
  19.                 //分组的key
  20.                 String key = bucket.getKeyAsString();
  21.                 long docCount = bucket.getDocCount();
  22.                 reslut.put(key,docCount);
  23.             }
  24.             return AjaxResult.success(reslut);
  25.         }else {
  26.             return AjaxResult.error("查询无数据");
  27.         }
复制代码
Range聚合 - 按数值范围分组,自定义分组

  1. GET /xxx/_search
  2. {
  3.     "query": {
  4.     "range": {
  5.       "alarmNum": {
  6.         "gte": 20,
  7.         "lte": 50
  8.       }
  9.     }
  10.   },
  11.   "size": 0,
  12.   "aggs": {
  13.     "warncont": {
  14.       "range": {
  15.         "field": "alarmNum",
  16.         "ranges": [
  17.           {
  18.             "to": 24    #<
  19.           },
  20.           {
  21.             "from": 24,   #>= and <
  22.             "to": 32
  23.           },
  24.           {
  25.             "from": 32  #>=
  26.           }
  27.         ]
  28.       }
  29.     }
  30.   }
  31. }
复制代码
Elasticsearch 指标聚合(metrics)-函数

ES指标聚合,就是类似SQL的统计函数,指标聚合可以单独使用,也可以跟桶聚合一起使用。
常用的统计函数如下:


  • Value Count - 类似sql的count函数,统计总数
  • Cardinality - 类似SQL的count(DISTINCT 字段), 统计不重复的数据总数
  • Avg - 求平均值
  • Sum - 求和
  • Max - 求最大值
  • Min - 求最小值
Value Count - 类似sql的count函数,统计总数

  1. GET /sales/_search?size=0
  2. {
  3.   "aggs": {
  4.     "types_count": { // 聚合查询的名字,随便取个名字
  5.       "value_count": { // 聚合类型为:value_count
  6.         "field": "type" // 计算type这个字段值的总数
  7.       }
  8.     }
  9.   }
  10. }
  11. 等价SQL:
  12. select count(type) from sales
复制代码
Cardinality - 类似SQL的count(DISTINCT 字段), 统计不重复的数据总数

  1. POST /sales/_search?size=0
  2. {
  3.     "aggs" : {
  4.         "type_count" : { // 聚合查询的名字,随便取一个
  5.             "cardinality" : { // 聚合查询类型为:cardinality
  6.                 "field" : "type" // 根据type这个字段统计文档总数
  7.             }
  8.         }
  9.     }
  10. }
  11. 等价SQL:
  12. select count(DISTINCT type) from sales
复制代码
Avg - 求平均值 Sum - 求和 Max - 求最大值 Min - 求最小值

  1. POST /exams/_search?size=0
  2. {
  3.   "aggs": {
  4.     "avg_grade": { // 聚合查询名字,随便取一个名字
  5.       "avg": { // 聚合查询类型为: avg
  6.         "field": "grade" // 统计grade字段值的平均值
  7.       }
  8.     }
  9.   }
  10. }
复制代码
综合使用-多层嵌套

  1. GET /project_zcy/_search
  2. {
  3.   "size": 0,
  4.   "query": {
  5.     "term": {
  6.       "project_status.keyword": {
  7.         "value": "执行中"
  8.       }
  9.     }
  10.   },
  11.   "aggs": {
  12.     "institue_bulk": {
  13.       "terms": {
  14.         "field": "institute_code.keyword",  #分组code
  15.          "order": {
  16.               "_count": "asc"
  17.             }
  18.       },
  19.       "aggs": {
  20.         "depart_bulk": {
  21.           "terms": {
  22.             "field": "institute_name.keyword"  #再次分组获取名称
  23.            
  24.           },
  25.           "aggs": {                #指标sum
  26.             "warm_sum": {
  27.               "sum": {
  28.                 "field": "alarmNum"
  29.               }
  30.             },
  31.             "index_count": {    #指标count
  32.               "value_count": {
  33.                 "field": "institute_code.keyword"
  34.               }
  35.             }
  36.           }
  37.         }
  38.       }
  39.     }
  40.   }
  41. }
复制代码
ES聚合排序

排序是对桶内里数据排序
默认情况,ES会根据doc_count文档总数,降序排序。
ES桶聚合支持两种方式排序:


  • 内置排序
  • 按度量指标排序
1:内置排序

内置排序参数:


  • _count - 按文档数排序。对 terms 、 histogram 、 date_histogram 有用
  • _term - 按词项的字符串值的字母序次排序。只在 terms 内使用
  • _key - 按每个桶的键值数值排序, 仅对 histogram 和 date_histogram 有用
  1. GET /cars/_search
  2. {
  3.     "size" : 0,
  4.     "aggs" : {
  5.         "colors" : { // 聚合查询名字,随便取一个
  6.             "terms" : { // 聚合类型为: terms
  7.               "field" : "color",
  8.               "order": { // 设置排序参数
  9.                 "_count" : "asc"  // 根据_count排序,asc升序,desc降序
  10.               }
  11.             }
  12.         }
  13.     }
  14. }
复制代码
2:按度量排序

通常情况下,我们根据桶聚合分桶后,都会对桶内进行多个维度的指标聚合,所以我们也可以根据桶内指标聚合的结果进行排序。
  1. GET /cars/_search
  2. {
  3.     "size" : 0,
  4.     "aggs" : {
  5.         "colors" : { // 聚合查询名字
  6.             "terms" : { // 聚合类型: terms,先分桶
  7.               "field" : "color", // 分桶字段为color
  8.               "order": { // 设置排序参数
  9.                 "avg_price" : "asc"  // 根据avg_price指标聚合结果,升序排序。
  10.               }
  11.             },
  12.             "aggs": { // 嵌套聚合查询,设置桶内聚合指标
  13.                 "avg_price": { // 聚合查询名字,前面排序引用的就是这个名字
  14.                     "avg": {"field": "price"} // 计算price字段平均值
  15.                 }
  16.             }
  17.         }
  18.     }
  19. }
复制代码
限定返回桶的数量 -size

  1. GET /_search
  2. {
  3.     "aggs" : {
  4.         "products" : { // 聚合查询名字
  5.             "terms" : { // 聚合类型为: terms
  6.                 "field" : "product", // 根据product字段分桶
  7.                 "size" : 5 // 限制最多返回5个桶
  8.             }
  9.         }
  10.     }
  11. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

写过一篇

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表