Elasticsearch学习-- 聚合查询

刺骨的言语ヽ痛彻心扉 2024-04-08 13:11 258阅读 0赞

一、聚合分类

1. 分桶聚合 bucket aggregations

按照每个标签进行分类 ,类似于group by

" class="reference-link">04e347b77a40422d803beb119a99a459.png

acfc34db265a4ef6983bcd44c5e362f7.png

9f71b4b3d9af4a39bcbee12cb5a02edd.png

2. 指标聚合 metrics aggregations

ad81de6bc7a34e199329271126ad9fa2.png

3. 管道聚合 pipeline aggregations

6b182882820e4764af05b4b358e8825b.png

先计算平均值,再计算最小值

47c45c92e3e84ae087172aa130cbda2f.png

二、语法

  1. GET test_index/_search
  2. {
  3. "aggs": {
  4. "聚合后返回的字段": {
  5. "avg": {
  6. "聚合的字段": ""
  7. }
  8. },
  9. "聚合后返回的字段2": {
  10. "avg": {
  11. "聚合的字段": ""
  12. }
  13. }
  14. }
  15. }

默认查询返回结果是10条,可以通过设置size来看返回值数量

  1. GET test_index/_search?size=20
  2. GET test_index/_search
  3. {
  4. "size":20
  5. }

三、桶聚合

1. 统计不同标签的商品数量

  1. PUT product/_doc/1
  2. {
  3. "name":"prodect1 aa",
  4. "price": 1000,
  5. "tags":["tag1","tag2","tag3"]
  6. }
  7. PUT product/_doc/2
  8. {
  9. "name":"prodect2 bb",
  10. "price": 2000,
  11. "tags":["tag2","tag3"]
  12. }
  13. PUT product/_doc/3
  14. {
  15. "name":"prodect3 bb",
  16. "price": 2000,
  17. "tags":["tag4"]
  18. }
  19. PUT product/_doc/4
  20. {
  21. "name":"prodect4 bb",
  22. "price": 3000,
  23. "tags":["tag1","tag4"]
  24. }
  25. PUT product/_doc/5
  26. {
  27. "name":"prodect5 aa",
  28. "price": 3000,
  29. "tags":["tag1","tag5"]
  30. }
  31. PUT product/_doc/6
  32. {
  33. "name":"prodect6 aa",
  34. "price": 4000,
  35. "tags":["tag1","tag2"]
  36. }
  37. GET product/_search
  38. {
  39. "size": 0,
  40. "aggs": {
  41. "agg_tag": {
  42. "terms": {
  43. "field": "tags.keyword",
  44. "size": 10,
  45. "order": {
  46. "_count": "asc"
  47. }
  48. }
  49. }
  50. }
  51. }

18501da470304d96b0d38c19b1584d69.png

2. 为什么上面使用tags.keyword

因为聚合查询使用的是doc_values的正排索引,tags.keyword有正排索引

也可以通过设置fileddata属性进行正排索引

3. fileddata

修改mapping中tags字段的fileddata属性为true

  1. POST product/_mapping
  2. {
  3. "properties":{
  4. "tags":{
  5. "type":"text",
  6. "fielddata":true
  7. }
  8. }
  9. }

这样就可以使用tags直接进行聚合操作

  1. GET product/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "agg_tag": {
  6. "terms": {
  7. "field": "tags",
  8. "size": 10,
  9. "order": {
  10. "_count": "asc"
  11. }
  12. }
  13. }
  14. }
  15. }

31411dbf58ef4603812e5c511e1fa4c8.png

4. doc_values和field_data的区别

doc_values和filed_data都可以用于聚合查询,

doc_vaules是基于磁盘的,filed_data是基于内存的

数据量比较大时,尽量不要使用filed_data

四、指标聚合

1. 统计商品最贵、最便宜、平均价格

  1. GET product/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "max_price": {
  6. "max": {
  7. "field": "price"
  8. }
  9. },
  10. "min_price": {
  11. "min": {
  12. "field": "price"
  13. }
  14. },
  15. "avg_price": {
  16. "avg": {
  17. "field": "price"
  18. }
  19. }
  20. }
  21. }

a626798b16a941c68c9aa6d1be034013.png

2. stats 查看所有指标

  1. # 查看price的所有指标
  2. GET product/_search
  3. {
  4. "size": 0,
  5. "aggs": {
  6. "stats_price": {
  7. "stats": {
  8. "field": "price"
  9. }
  10. }
  11. }
  12. }

dcbfe2e92a2c4f1c8b1be8449f01e54d.png

3. cardinality去重后的数量

  1. # 按照price字段进行去重后的数量
  2. GET product/_search
  3. {
  4. "_source": false,
  5. "aggs": {
  6. "price_count": {
  7. "cardinality": {
  8. "field": "price"
  9. }
  10. }
  11. }
  12. }

a6dd4757785749aab38b9502794bc6d0.png

五、管道聚合(二次聚合)

统计平均价格最低的商品分类

1)先对tags进行分桶

2)对分桶后的tags取平均price(在哪个的基础上进行操作,就放在同一级)

3)对上面的平均价格取最小平均价格的标签

  1. # 统计平均价格最低的商品分类
  2. GET product/_search
  3. {
  4. "size": 0,
  5. "aggs": {
  6. "tags_bucket": {
  7. "terms": {
  8. "field": "tags.keyword"
  9. },
  10. "aggs":{
  11. "avg_price_bucket":{
  12. "avg": {
  13. "field": "price"
  14. }
  15. }
  16. }
  17. },
  18. "min_price_bucket":{
  19. "min_bucket": {
  20. "buckets_path": "tags_bucket>avg_price_bucket"
  21. }
  22. }
  23. }
  24. }

78f21ac2027e41738281b91495251ab8.png

六、基于聚合结果的聚合—案例

1. 准备数据

11条商品信息

  1. PUT /goods/_doc/1
  2. {
  3. "name" : "小米手机",
  4. "desc" : "手机中的战斗机",
  5. "price" : 3999,
  6. "lv":"旗舰机",
  7. "type":"手机",
  8. "createtime":"2020-10-01T08:00:00Z",
  9. "tags": [ "性价比", "发烧", "不卡顿" ]
  10. }
  11. PUT /goods/_doc/2
  12. {
  13. "name" : "小米NFC手机",
  14. "desc" : "支持全功能NFC,手机中的滑翔机",
  15. "price" : 4999,
  16. "lv":"旗舰机",
  17. "type":"手机",
  18. "createtime":"2020-05-21T08:00:00Z",
  19. "tags": [ "性价比", "发烧", "公交卡" ]
  20. }
  21. PUT /goods/_doc/3
  22. {
  23. "name" : "NFC手机",
  24. "desc" : "手机中的轰炸机",
  25. "price" : 2999,
  26. "lv":"高端机",
  27. "type":"手机",
  28. "createtime":"2020-06-20",
  29. "tags": [ "性价比", "快充", "门禁卡" ]
  30. }
  31. PUT /goods/_doc/4
  32. {
  33. "name" : "小米耳机",
  34. "desc" : "耳机中的黄焖鸡",
  35. "price" : 999,
  36. "lv":"百元机",
  37. "type":"耳机",
  38. "createtime":"2020-06-23",
  39. "tags": [ "降噪", "防水", "蓝牙" ]
  40. }
  41. PUT /goods/_doc/5
  42. {
  43. "name" : "红米耳机",
  44. "desc" : "耳机中的肯德基",
  45. "price" : 399,
  46. "type":"耳机",
  47. "lv":"百元机",
  48. "createtime":"2020-07-20",
  49. "tags": [ "防火", "低音炮", "听声辨位" ]
  50. }
  51. PUT /goods/_doc/6
  52. {
  53. "name" : "小米手机10",
  54. "desc" : "充电贼快掉电更快,超级无敌望远镜,高刷电竞屏",
  55. "price" : "",
  56. "lv":"旗舰机",
  57. "type":"手机",
  58. "createtime":"2020-07-27",
  59. "tags": [ "120HZ刷新率", "120W快充", "120倍变焦" ]
  60. }
  61. PUT /goods/_doc/7
  62. {
  63. "name" : "挨炮 SE2",
  64. "desc" : "除了CPU,一无是处",
  65. "price" : "3299",
  66. "lv":"旗舰机",
  67. "type":"手机",
  68. "createtime":"2020-07-21",
  69. "tags": [ "割韭菜", "割韭菜", "割新韭菜" ]
  70. }
  71. PUT /goods/_doc/8
  72. {
  73. "name" : "XS Max",
  74. "desc" : "听说要出新款12手机了,终于可以换掉手中的4S了",
  75. "price" : 4399,
  76. "lv":"旗舰机",
  77. "type":"手机",
  78. "createtime":"2020-08-19",
  79. "tags": [ "5V1A", "4G全网通", "大" ]
  80. }
  81. PUT /goods/_doc/9
  82. {
  83. "name" : "小米电视",
  84. "desc" : "70寸性价比只选,不要一万八,要不要八千八,只要两千九百九十八",
  85. "price" : 2998,
  86. "lv":"高端机",
  87. "type":"耳机",
  88. "createtime":"2020-08-16",
  89. "tags": [ "巨馍", "家庭影院", "游戏" ]
  90. }
  91. PUT /goods/_doc/10
  92. {
  93. "name" : "红米电视",
  94. "desc" : "我比上边那个更划算,我也2998,我也70寸,但是我更好看",
  95. "price" : 2999,
  96. "type":"电视",
  97. "lv":"高端机",
  98. "createtime":"2020-08-28",
  99. "tags": [ "大片", "蓝光8K", "超薄" ]
  100. }
  101. PUT /goods/_doc/11
  102. {
  103. "name": "红米电视",
  104. "desc": "我比上边那个更划算,我也2998,我也70寸,但是我更好看",
  105. "price": 2998,
  106. "type": "电视",
  107. "lv": "高端机",
  108. "createtime": "2020-08-28",
  109. "tags": [
  110. "大片",
  111. "蓝光8K",
  112. "超薄"
  113. ]
  114. }

2. 统计不同lv下的不同type的数量

  1. # 统计不同lv下的不同type的数量
  2. GET goods/_search
  3. {
  4. "size": 0,
  5. "aggs": {
  6. "lv_type_agg": {
  7. "terms": {
  8. "field": "lv.keyword"
  9. },
  10. "aggs": {
  11. "type_agg": {
  12. "terms": {
  13. "field": "type.keyword"
  14. }
  15. }
  16. }
  17. }
  18. }
  19. }

94c5f839df304521b073fb650a81b79f.png

3. 统计不同lv的价格信息

  1. # 统计不同lv下价格信息
  2. GET goods/_search
  3. {
  4. "size": 0,
  5. "aggs": {
  6. "lv_type_agg": {
  7. "terms": {
  8. "field": "lv.keyword"
  9. },
  10. "aggs": {
  11. "price_agg": {
  12. "stats": {
  13. "field": "price"
  14. }
  15. }
  16. }
  17. }
  18. }
  19. }

e5c3efde37984eafb6bfc1f13d88ee99.png

4. 统计不同type下的,不同lv的,price信息

  1. #统计不同type下的,不同lv的,price信息
  2. GET goods/_search
  3. {
  4. "size": 0,
  5. "aggs": {
  6. "type_agg": {
  7. "terms": {
  8. "field": "type.keyword"
  9. },
  10. "aggs": {
  11. "lv_agg": {
  12. "terms": {
  13. "field": "lv.keyword"
  14. },
  15. "aggs": {
  16. "price_agg": {
  17. "stats": {
  18. "field": "price"
  19. }
  20. }
  21. }
  22. }
  23. }
  24. }
  25. }
  26. }

487331a419ff4816b9ae7effdaeaaf8b.png

统计不同type下的,不同lv的,price信息和tag信息

  1. #统计不同type下的,不同lv的,price信息和tag信息
  2. GET goods/_search
  3. {
  4. "size": 0,
  5. "aggs": {
  6. "type_agg": {
  7. "terms": {
  8. "field": "type.keyword"
  9. },
  10. "aggs": {
  11. "lv_agg": {
  12. "terms": {
  13. "field": "lv.keyword"
  14. },
  15. "aggs": {
  16. "price_agg": {
  17. "stats": {
  18. "field": "price"
  19. }
  20. },
  21. "tag_agg": {
  22. "terms": {
  23. "field": "tags.keyword"
  24. }
  25. }
  26. }
  27. }
  28. }
  29. }
  30. }
  31. }

565928e1fd6a49738f75b95207d7bb34.png

5. 统计每个商品type中,不同的lv商品中,平均price最低的lv

  1. # 统计每个商品type中,不同的lv商品中,平均price最低的lv
  2. GET goods/_search
  3. {
  4. "size": 0,
  5. "aggs": {
  6. "type_agg": {
  7. "terms": {
  8. "field": "type.keyword"
  9. },
  10. "aggs": {
  11. "lv_agg": {
  12. "terms": {
  13. "field": "lv.keyword"
  14. },
  15. "aggs": {
  16. "price_agg": {
  17. "avg": {
  18. "field": "price"
  19. }
  20. }
  21. }
  22. },
  23. "min_price_bucket": {
  24. "min_bucket": {
  25. "buckets_path": "lv_agg>price_agg"
  26. }
  27. }
  28. }
  29. }
  30. }
  31. }

4334f697dcc443c4a809027bcba6675a.png

七、基于查询结果的聚合和基于聚合结果的查询—案例

1. 基于查询结果的聚合

1)查询price>4000的tags信息

  1. GET goods/_search
  2. {
  3. "size": 10,
  4. "query": {
  5. "range": {
  6. "price": {
  7. "gte": 4000
  8. }
  9. }
  10. },
  11. "aggs": {
  12. "tags_bucket": {
  13. "terms": {
  14. "field": "tags.keyword"
  15. }
  16. }
  17. }
  18. }

a5027853bc0c4b56935878ce25e14ce0.png

2) 基于filter

与上面的结果一样

  1. GET goods/_search
  2. {
  3. "size": 10,
  4. "query": {
  5. "constant_score": {
  6. "filter": {
  7. "range": {
  8. "price": {
  9. "gte": 4000
  10. }
  11. }
  12. }
  13. }
  14. },
  15. "aggs": {
  16. "tags_bucket": {
  17. "terms": {
  18. "field": "tags.keyword"
  19. }
  20. }
  21. }
  22. }

2. 基于聚合结果的查询

使用post_filter

  1. GET goods/_search
  2. {
  3. "size": 10,
  4. "aggs": {
  5. "tags_bucket": {
  6. "terms": {
  7. "field": "tags.keyword"
  8. }
  9. }
  10. },
  11. "post_filter": {
  12. "term": {
  13. "tags.keyword": "性价比"
  14. }
  15. }
  16. }
  17. GET goods/_search
  18. {
  19. "size": 10,
  20. "query": {
  21. "term": {
  22. "tags.keyword": {
  23. "value": "性价比"
  24. }
  25. }
  26. },
  27. "aggs": {
  28. "tags_bucket": {
  29. "terms": {
  30. "field": "tags.keyword"
  31. }
  32. }
  33. }
  34. }

以上两个语句,查询结果相同

1)查询price>4000的平均price和所有商品的平均price

  1. #查询price>4000的平均price和所有商品的平均price
  2. GET goods/_search
  3. {
  4. "size": 0,
  5. "query": {
  6. "range": {
  7. "price": {
  8. "gte": 4000
  9. }
  10. }
  11. },
  12. "aggs": {
  13. "avg_price": {
  14. "avg": {
  15. "field": "price"
  16. }
  17. },
  18. "all_avg_price":{
  19. "global": {},
  20. "aggs":{
  21. "avg_price2":{
  22. "avg": {
  23. "field": "price"
  24. }
  25. }
  26. }
  27. }
  28. }
  29. }

e2db909c470d4a3fb7132eaae5b5f72c.png

2) 将上面的global换成filter的话,是与最上面的查询条件产生交集

  1. GET goods/_search
  2. {
  3. "size": 0,
  4. "query": {
  5. "range": {
  6. "price": {
  7. "gte": 4000
  8. }
  9. }
  10. },
  11. "aggs": {
  12. "avg_price": {
  13. "avg": {
  14. "field": "price"
  15. }
  16. },
  17. "all_avg_price":{
  18. "filter": {
  19. "range": {
  20. "price": {
  21. "lte": 3000
  22. }
  23. }
  24. },
  25. "aggs":{
  26. "avg_price2":{
  27. "avg": {
  28. "field": "price"
  29. }
  30. }
  31. }
  32. }
  33. }
  34. }

0cf57cbc27864e8896778c1351c2b69d.png

八、聚合排序

1. _count

按照doc_count排序

  1. GET goods/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "tags_aggs": {
  6. "terms": {
  7. "field": "tags.keyword",
  8. "order": {
  9. "_count": "desc"
  10. }
  11. }
  12. }
  13. }
  14. }

023e68c76ae04a6f854adf01ff2ad052.png

2._term/_key

_term已经淘汰,按照key字典序排序

  1. GET goods/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "tags_aggs": {
  6. "terms": {
  7. "field": "tags.keyword",
  8. "order": {
  9. "_key": "asc"
  10. }
  11. }
  12. }
  13. }
  14. }

26f4bb0998654801961af8657657153a.png

3. 多层聚合

外层按照type的数量倒序排,里层按照lv的数量正序排

  1. GET goods/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "type_aggs": {
  6. "terms": {
  7. "field": "type.keyword",
  8. "order": {
  9. "_count": "desc"
  10. }
  11. },
  12. "aggs": {
  13. "lv_aggs": {
  14. "terms": {
  15. "field": "lv.keyword",
  16. "order": {
  17. "_count": "asc"
  18. }
  19. }
  20. }
  21. }
  22. }
  23. }
  24. }

12da8badd97e401db35a1e86375c6fcf.png

根据price_stats中的最小值进行排序

  1. # 根据price_stats中的最小值进行排序
  2. GET goods/_search
  3. {
  4. "size": 0,
  5. "aggs": {
  6. "type_aggs": {
  7. "terms": {
  8. "field": "type.keyword",
  9. "order": {
  10. "filter_aggs>price_stats.min": "asc"
  11. }
  12. },
  13. "aggs": {
  14. "filter_aggs": {
  15. "filter": {
  16. "terms": {
  17. "type.keyword": [
  18. "耳机",
  19. "手机",
  20. "电视"
  21. ]
  22. }
  23. },
  24. "aggs": {
  25. "price_stats": {
  26. "stats": {
  27. "field": "price"
  28. }
  29. }
  30. }
  31. }
  32. }
  33. }
  34. }
  35. }

f11503c3887b40c3a5576450fb058b00.png

九、图形化

1. 根据价格range分桶

  1. GET goods/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "price_range": {
  6. "range": {
  7. "field": "price",
  8. "ranges": [
  9. {
  10. "from": 0,
  11. "to": 1000
  12. },
  13. {
  14. "from": 1000,
  15. "to": 2000
  16. },
  17. {
  18. "from": 2000,
  19. "to": 3000
  20. },
  21. {
  22. "from": 3000,
  23. "to": 4000
  24. },
  25. {
  26. "from": 4000,
  27. "to": 5000
  28. }
  29. ]
  30. }
  31. }
  32. }
  33. }

5b944ef1591c485c8b36a79388c18323.png

2. histogram(直方图、柱状图)

根据price,间隔1000,跟上面的基本相同

  1. GET goods/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "price_range": {
  6. "histogram": {
  7. "field": "price",
  8. "interval": 1000
  9. }
  10. }
  11. }
  12. }

eec5b59ca113461da696896845f9b58f.png

跟field、interval同级的其他参数

keyed:设置true,表示将结果输出为key、value形式

min_doc_count:设置成1,表示输出结果doc_value大于等于1的数据(过滤0)

missing:对空值赋默认值(设置成500,上图中表示,将price缺失的数据的price设置成500)

3. date-histogram

专门针对日期类型的直方图

根据月份进行分桶,可以用format进行指定格式输出

  1. GET goods/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "date_range": {
  6. "date_histogram": {
  7. "field": "createtime",
  8. "interval": "month"
  9. }
  10. }
  11. }
  12. }

c7b7bb76819540f9b896550fafb184fe.png

可以设置extended_bounds,展示没有的数据0

1a0fb07b771f4c649f961ca641ac9334.png

4. auto_date_histogram

自动设置interval,根据buckets

97e871f3058943899f898ce1ab5f7b43.png

5. cumulative_sum(累加聚合)

十、percentile (百分位统计、饼状图)

1. percentiles

7269cd281d624ad5b15fe7b0f917f4cc.png

2. percentile_ranks

0622d66e6aa14d59ac450cbb786268bd.png

发表评论

表情:
评论列表 (有 0 条评论,258人围观)

还没有评论,来说两句吧...

相关阅读

    相关 ElasticSearch java API - 聚合查询

    今天给大家转载一篇关于ES聚合相关的文章,是利用Java API实现的。因为公司最近要上搜索引擎相关的功能,所以最近一直在学习es相关的内容。基本内容有:组合查询、聚合、分页、