码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • elasticsearch聚合之bucket terms聚合


    文章目录

    • 1. 背景
    • 2. 前置条件
      • 2.1 创建索引
      • 2.2 准备数据
    • 3. 各种聚合
      • 3.1 统计人数最多的2个省
        • 3.1.1 dsl
        • 3.1.2 运行结果
      • 3.2 统计人数最少的2个省
        • 3.2.1 dsl
        • 3.2.2 运行结果
      • 3.3 根据字段值排序-根据年龄聚合,返回年龄最小的2个聚合
        • 3.3.1 dsl
        • 3.3.2 运行结果
      • 3.4 子聚合排序-先根据省聚合,然后根据每个聚合后的最小年龄排序
        • 3.4.1 dsl
        • 3.4.2 运行结果
      • 3.5 脚本聚合-根据省聚合,如果地址中有黄冈市则需要出现黄冈市
        • 3.5.1 dsl
        • 3.5.2 运行结果
      • 3.6 filter-以省分组,并且只包含北的省,但是需要排除湖北省
        • 3.6.1 dsl
        • 3.6.2 运行结果
      • 3.7 多term聚合-根据省和性别聚合,然后根据最大年龄倒序
        • 3.7.1 dsl
        • 3.7.2 运行结果
      • 3.8 missing value 处理
      • 3.9 多个聚合-同时返回根据省聚合和根据性别聚合
        • 3.9.1 dsl
        • 3.9.2 运行结果
    • 4. 总结
      • 4.1 可以聚合的字段
      • 4.2 如果我们想返回所有的聚合Term结果
      • 4.3 聚合数据不准
      • 4.4 排序注意事项
        • 4.4.1 _count 排序
        • 4.4.2 字段值排序
        • 4.4.3 子聚合排序
      • 4.5 多term聚合
    • 5、源码地址
    • 6. 参考链接

    1. 背景

    此处简单记录一下bucket聚合下的terms聚合。记录一下terms聚合的各种用法,以及各种注意事项,防止以后忘记。

    2. 前置条件

    2.1 创建索引

    PUT /index_person
    {
      "settings": {
        "number_of_shards": 1
      },
      "mappings": {
        "properties": {
          "id": {
            "type": "long"
          },
          "name": {
            "type": "keyword"
          },
          "sex": {
            "type": "keyword"
          },
          "age": {
            "type": "integer"
          },
          "province": {
            "type": "keyword"
          },
          "address": {
            "type": "text",
            "analyzer": "ik_max_word",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    2.2 准备数据

    PUT /_bulk
    {"create":{"_index":"index_person","_id":1}}
    {"id":1,"name":"张三","sex":"男","age":20,"province":"湖北","address":"湖北省黄冈市罗田县匡河镇"}
    {"create":{"_index":"index_person","_id":2}}
    {"id":2,"name":"李四","sex":"男","age":19,"province":"江苏","address":"江苏省南京市"}
    {"create":{"_index":"index_person","_id":3}}
    {"id":3,"name":"王武","sex":"女","age":25,"province":"湖北","address":"湖北省武汉市江汉区"}
    {"create":{"_index":"index_person","_id":4}}
    {"id":4,"name":"赵六","sex":"女","age":30,"province":"北京","address":"北京市东城区"}
    {"create":{"_index":"index_person","_id":5}}
    {"id":5,"name":"钱七","sex":"女","age":16,"province":"北京","address":"北京市西城区"}
    {"create":{"_index":"index_person","_id":6}}
    {"id":6,"name":"王八","sex":"女","age":45,"province":"北京","address":"北京市朝阳区"}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3. 各种聚合

    3.1 统计人数最多的2个省

    3.1.1 dsl

    GET /index_person/_search
    {
      "size": 0, 
      "aggs": {
        "agg_sex": { 
          "terms": { 
            "field": "province",
            "size": 2
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.1.2 运行结果

    运行结果

    3.2 统计人数最少的2个省

    3.2.1 dsl

    GET /index_person/_search
    {
      "size": 0, 
      "aggs": {
        "agg_sex": { 
          "terms": { 
            "field": "province",
            "size": 2,
            "order": {
              "_count": "asc"
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注意: 不推荐使用 _count:asc来统计,会导致统计结果不准,看下方的总结章节。

    3.2.2 运行结果

    运行结果

    3.3 根据字段值排序-根据年龄聚合,返回年龄最小的2个聚合

    3.3.1 dsl

    GET /index_person/_search
    {
      "size": 0, 
      "aggs": {
        "agg_sex": { 
          "terms": { 
            "field": "age",
            "size": 2,
            "order": {
              "_key": "asc"
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注意: 这种根据字段值来排序,聚合的结果是正确的。

    3.3.2 运行结果

    运行结果

    3.4 子聚合排序-先根据省聚合,然后根据每个聚合后的最小年龄排序

    3.4.1 dsl

    GET /index_person/_search
    {
      "size": 0, 
      "aggs": {
        "agg_sex": { 
          "terms": { 
            "field": "province",
            "order": {
              "min_age": "asc"
            }
          },
          "aggs": {
            "min_age": {
              "min": {
                "field": "age"
              }
            }
          }
        }
      }
    }
    
    GET /index_person/_search
    {
      "size": 0, 
      "aggs": {
        "agg_sex": { 
          "terms": { 
            "field": "province",
            "order": {
              "min_age.min": "asc"
            }
          },
          "aggs": {
            "min_age": {
              "stats": {
                "field": "age"
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    注意: 子聚合排序一般也是不准的,但是如果是根据子聚合的最大值倒序和最小值升序又是准的。

    3.4.2 运行结果

    运行结果

    3.5 脚本聚合-根据省聚合,如果地址中有黄冈市则需要出现黄冈市

    3.5.1 dsl

    GET /index_person/_search
    {
      "size": 0, 
      
      "runtime_mappings": {
        "province_sex": {
          "type": "keyword",
          "script": """
              String province = doc['province'].value;
              String address = doc['address.keyword'].value;
              if(address.contains('黄冈市')){
                emit('黄冈市');
              }else{
                emit(province);
              }
          """
        }
      }, 
      
      "aggs": {
        "agg_sex": { 
          "terms": { 
            "field": "province_sex"
          }
        }
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    注意事项

    3.5.2 运行结果

    运行结果

    3.6 filter-以省分组,并且只包含北的省,但是需要排除湖北省

    3.6.1 dsl

    GET /index_person/_search
    {
      "size": 0, 
      "aggs": {
        "agg_province": { 
          "terms": { 
            "field": "province",
            "include": ".*北.*",
            "exclude": ["湖北"]
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    注意: 当是字符串时,可以写正则表达式,当是数组时,需要写具体的值。

    3.6.2 运行结果

    运行结果

    3.7 多term聚合-根据省和性别聚合,然后根据最大年龄倒序

    3.7.1 dsl

    GET /index_person/_search
    {
      "size": 0,
      "aggs": {
        "genres_and_products": {
          "multi_terms": {
            "size": 10,
            "shard_size": 25,
            "order":{
              "max_age": "desc"    
            },
            "terms": [
              {
                "field": "province",
                "missing": "defaultProvince"
              },
              {
                "field": "sex"
              }
            ]
          },
          "aggs": {
            "max_age": {
              "max": {
                "field": "age"
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    注意: terms聚合默认不支持多字段聚合,需要借助别的方式。此处使用multi terms来实现多字段聚合。

    3.7.2 运行结果

    运行结果

    3.8 missing value 处理

    missing value 处理

    3.9 多个聚合-同时返回根据省聚合和根据性别聚合

    3.9.1 dsl

    GET /index_person/_search
    {
      "size": 0,
      "aggs": {
        "agg_province": {
          "terms": {
            "field": "province"
          }
        },
        "agg_sex":{
          "terms": {
            "field": "sex",
            "size": 10
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.9.2 运行结果

    运行结果

    4. 总结

    4.1 可以聚合的字段

    一般情况下,只有如下几种字段类型可以进行聚合操作 keyword,numeric,ip,boolean和binary类型的字段。text类型的字段默认情况下是不可以进行聚合的,如果需要聚合,需要开启fielddata。
    可以聚合的字段

    4.2 如果我们想返回所有的聚合Term结果

    如果我们只想返回100或1000个唯一结果,可以增大size参数的值。但是如果我们想返回所有的,那么推荐使用 composite aggregation
    如果我们想返回所有的聚合Term结果

    4.3 聚合数据不准

    我们通过terms聚合到的结果是一个大概的结果,不一定是完全正确的。
    为什么?.
    举个例子: 如果我们的集群有3个分片,此处我们想返回值最高的5个统计。即size=5,假设先不考虑shard_size参数,那么此时每个节点会返回值最高的5个统计,然后再次聚合,返回,返回最终值最高的5个。这个貌似没什么问题,但是因为我们的数据是分布es的各个节点上的,可能某个统计项(北京市的用户数),在A节点是是排名前5,但是在B节点上不是排名前5,那么最终的统计结果是否是就会漏统计了。

    如何解决:
    我们可以让es在每个节点上多返回几个结果,比如:我们的size=5,那么我们每个节点就返回 size * 1.5 + 10 个结果,那么误差相应的就会减少。 而这个size * 1.5 + 10就是shard_size的值,当然我们也可以手动指定,但一般需要比size的值大。

    聚合数据不准

    4.4 排序注意事项

    4.4.1 _count 排序

    默认情况下,使用的是 _count 倒序的,但是我们可以指定成升序,但是这是不推荐的,会导致错误结果。如果我们想要升序,可以使用 rare_terms聚合。
    _count排序注意事项

    4.4.2 字段值排序

    使用字段值排序,不管是正序还是倒序,结果是准确的。
    字段值排序

    4.4.3 子聚合排序

    子聚合排序

    4.5 多term聚合

    多term聚合

    5、源码地址

    https://gitee.com/huan1993/spring-cloud-parent/blob/master/es/es8-api/src/main/java/com/huan/es8/aggregations/bucket/TermsAggs.java

    6. 参考链接

    1. https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html
    2. https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-multi-terms-aggregation.html
  • 相关阅读:
    《计算机组成原理/CSAPP》网课总结(二)——编译原理基础
    IB学生喜欢申请哪些英国院校?
    Unity SKFramework框架(二十五)、RSA算法加密、签名工具 RSA Crypto
    Redis(十一) 分布式锁
    18.支持向量机(SVM)的介绍
    数仓开发常用hive命令
    【学习笔记】4、组合逻辑电路(下)
    CS217 2_BLAS Hardware Accelerators for Machine Learning
    [202209]mysql8.0 双主集群搭建 亲测可用
    数字人民币如何将支付宝钱包余额转入到微信支付钱包余额?
  • 原文地址:https://blog.csdn.net/fu_huo_1993/article/details/127822355
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号