Elasticsearch系列聚合查询(一)

编程

基础概念

bucket

数据分组,一些数据按照某个字段进行bucket划分,这个字段值相同的数据放到一个bucket中。可以理解成Java中的Map<String, List<Object>>结构,类似于Mysql中的group by后的查询结果。

metric:

对一个数据分组执行的统计,比如计算最大值,最小值,平均值等

类似于Mysql中的max(),min(),avg()函数的值,都是在group by后使用的。

案例

我们还是以英文儿歌为案例背景,回顾一下索引结构:

PUT /music

{

"mappings": {

"children": {

"properties": {

"id": {

"type": "keyword"

},

"author_first_name": {

"type": "text",

"analyzer": "english"

},

"author_last_name": {

"type": "text",

"analyzer": "english"

},

"author": {

"type": "text",

"analyzer": "english",

"fields": {

"keyword": {

"type": "keyword",

"ignore_above": 256

}

}

},

"name": {

"type": "text",

"fields": {

"keyword": {

"type": "keyword",

"ignore_above": 256

}

}

},

"content": {

"type": "text",

"fields": {

"keyword": {

"type": "keyword",

"ignore_above": 256

}

}

},

"language": {

"type": "text",

"analyzer": "english",

"fielddata": true

},

"tags": {

"type": "text",

"analyzer": "english"

},

"length": {

"type": "long"

},

"likes": {

"type": "long"

},

"isRelease": {

"type": "boolean"

},

"releaseDate": {

"type": "date"

}

}

}

}

}

统计目前收录的哪种语言的歌曲最多

GET /music/children/_search

{

"size": 0,

"aggs": {

"song_qty_by_language": {

"terms": {

"field": "language"

}

}

}

}

语法解释:

  • size:0 表示只要统计后的结果,原始数据不展现
  • aggs:固定语法 ,聚合分析都要声明aggs
  • song_qty_by_language:聚合的名称,可以随便写,建议规范命名
  • terms:按什么字段进行分组
  • field:具体的字段名称

响应结果如下:

{

"took": 2,

"timed_out": false,

"_shards": {

"total": 5,

"successful": 5,

"skipped": 0,

"failed": 0

},

"hits": {

"total": 5,

"max_score": 0,

"hits": []

},

"aggregations": {

"song_qty_by_language": {

"doc_count_error_upper_bound": 0,

"sum_other_doc_count": 0,

"buckets": [

{

"key": "english",

"doc_count": 5

}

]

}

}

}

语法解释:

  • hits: 由于请求时设置了size:0,hits就是空的
  • aggregations:聚合查询的结果
  • song_qty_by_language:请求时声明的名称
  • buckets:根据指定字段查询后得到的数据分组集合,[]内的是每一个数据分组,其中key为每个bucket的对应指定字段的值,doc_count为统计的数量。

默认按doc_count降序排序。

按语种统计每种歌曲的平均时长

GET /music/children/_search

{

"size": 0,

"aggs": {

"lang": {

"terms": {

"field": "language"

},

"aggs": {

"length_avg": {

"avg": {

"field": "length"

}

}

}

}

}

}

这里演示的是两层aggs聚合查询,先按语种统计,得到数据分组,再在数据分组里算平均时长。

多个aggs嵌套语法也是如此,注意一下aggs代码块的位置即可。

统计最长时长、最短时长等的歌曲

最常用的统计:count,avg,max,min,sum,语法含义与mysql相同。

GET /music/children/_search

{

"size": 0,

"aggs": {

"color": {

"terms": {

"field": "language"

},

"aggs": {

"length_avg": {

"avg": {

"field": "length"

}

},

"length_max": {

"max": {

"field": "length"

}

},

"length_min": {

"min": {

"field": "length"

}

},

"length_sum": {

"sum": {

"field": "length"

}

}

}

}

}

}

按时长分段统计歌曲平均时长

以30秒为一段,看各段区间的平均值。

histogram语法位置跟terms一样,作范围分区,搭配interval参数一起使用

interval:30表示分的区间段为[0,30),[30,60),[60,90),[90,120)

段的闭合关系是左开右闭,如果数据在某段区间内没有,也会返回空的区间。

GET /music/children/_search

{

"size": 0,

"aggs": {

"sales_price_range": {

"histogram": {

"field": "length",

"interval": 30

},

"aggs": {

"length_avg": {

"avg": {

"field": "length"

}

}

}

}

}

}

这种数据的结果可以用来生成柱状图或折线图。

按上架日期分段统计新歌数量

按月统计

date histogram与histogram语法类似,搭配date interval指定区间间隔

extended_bounds表示最大的时间范围。

GET /music/children/_search

{

"size": 0,

"aggs": {

"sales": {

"date_histogram": {

"field": "releaseDate",

"interval": "month",

"format": "yyyy-MM-dd",

"min_doc_count": 0,

"extended_bounds": {

"min": "2019-10-01",

"max": "2019-12-31"

}

}

}

}

}

interval的值可以天、周、月、季度、年等。我们可以延伸一下,比如统计今年每个季度的新发布歌曲的点赞数量

GET /music/children/_search

{

"size": 0,

"aggs": {

"sales": {

"date_histogram": {

"field": "releaseDate",

"interval": "quarter",

"format": "yyyy-MM-dd",

"min_doc_count": 0,

"extended_bounds": {

"min": "2019-01-01",

"max": "2019-12-31"

}

},

"aggs": {

"lang_qty": {

"terms": {

"field": "language"

},

"aggs": {

"like_sum": {

"sum": {

"field": "likes"

}

}

}

},

"total" :{

"sum": {

"field": "likes"

}

}

}

}

}

}

带上过滤条件

聚合查询可以和query搭配使用,相当于mysql中where与group by联合使用

查询条件

GET /music/children/_search

{

"size": 0,

"query": {

"match": {

"language": "english"

}

},

"aggs": {

"sales": {

"terms": {

"field": "language"

}

}

}

}

过滤条件

GET /music/children/_search

{

"size": 0,

"query": {

"constant_score": {

"filter": {

"term": {

"language": "english"

}

}

}

},

"aggs": {

"sales": {

"terms": {

"field": "language"

}

}

}

}

global bucket查询

global:就是global bucket,会将所有的数据纳入聚合scope,不受前面的query或filter影响。

global bucket适用于同时统计指定条件的数据与全部数据的对比,如我们创造的场景:指定作者的歌与全部歌曲的点赞数量对比。

GET /music/children/_search

{

"size": 0,

"query": {

"match": {

"author": "Jean Ritchie"

}

},

"aggs": {

"likes": {

"sum": {

"field": "likes"

}

},

"all": {

"global": {},

"aggs": {

"all_likes": {

"sum": {

"field": "likes"

}

}

}

}

}

}

统计近2月,近1月的点赞数

aggs.filter针对是聚合里的数据

bucket filter:对不同的bucket下的aggs,进行filter

类似于mysql的中having语法

GET /music/children/_search

{

"size": 0,

"aggs": {

"recent_60d": {

"filter": {

"range": {

"releaseDate": {

"gte": "now-60d"

}

}

},

"aggs": {

"recent_60d_likes_sum": {

"sum": {

"field": "likes"

}

}

}

},

"recent_30d": {

"filter": {

"range": {

"releaseDate": {

"gte": "now-30d"

}

}

},

"aggs": {

"recent_30d_likes_sum": {

"avg": {

"field": "likes"

}

}

}

}

}

}

统计排序

默认按doc_count降序排序,排序规则可以改,order里面可以指定aggs的别名,如length_avg,类似于mysql的order by cnt asc。

GET /music/children/_search

{

"size": 0,

"aggs": {

"group_by_lang": {

"terms": {

"field": "language",

"order": {

"length_avg": "desc"

}

},

"aggs": {

"length_avg": {

"avg": {

"field": "length"

}

}

}

}

}

}

小结

本篇主要介绍常用的聚合查询,均以示例为主,了解基本写法后可以快速阅读,有不好理解的地方,多与我们熟悉的数据库查询SQL作比较,谢谢。

专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区

可以扫左边二维码添加好友,邀请你加入Java架构社区微信群共同探讨技术

以上是 Elasticsearch系列聚合查询(一) 的全部内容, 来源链接: utcz.com/z/515040.html

回到顶部