elasticsearch聚合之bucket terms聚合

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           }         }       }     }   } } 

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":"北京市朝阳区"} 

3. 各种聚合

3.1 统计人数最多的2个省

3.1.1 dsl

GET /index_person/_search {   "size": 0,    "aggs": {     "agg_sex": {        "terms": {          "field": "province",         "size": 2       }     }   } } 

3.1.2 运行结果

elasticsearch聚合之bucket terms聚合

3.2 统计人数最少的2个省

3.2.1 dsl

GET /index_person/_search {   "size": 0,    "aggs": {     "agg_sex": {        "terms": {          "field": "province",         "size": 2,         "order": {           "_count": "asc"         }       }     }   } } 

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

3.2.2 运行结果

elasticsearch聚合之bucket terms聚合

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

3.3.1 dsl

GET /index_person/_search {   "size": 0,    "aggs": {     "agg_sex": {        "terms": {          "field": "age",         "size": 2,         "order": {           "_key": "asc"         }       }     }   } } 

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

3.3.2 运行结果

elasticsearch聚合之bucket terms聚合

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"           }         }       }     }   } } 

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

3.4.2 运行结果

elasticsearch聚合之bucket terms聚合

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"       }     }   } }  

elasticsearch聚合之bucket terms聚合

3.5.2 运行结果

elasticsearch聚合之bucket terms聚合

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

3.6.1 dsl

GET /index_person/_search {   "size": 0,    "aggs": {     "agg_province": {        "terms": {          "field": "province",         "include": ".*北.*",         "exclude": ["湖北"]       }     }   } } 

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

3.6.2 运行结果

elasticsearch聚合之bucket terms聚合

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"           }         }       }     }   } } 

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

3.7.2 运行结果

elasticsearch聚合之bucket terms聚合

3.8 missing value 处理

elasticsearch聚合之bucket terms聚合

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       }     }   } } 

3.9.2 运行结果

elasticsearch聚合之bucket terms聚合

4. 总结

4.1 可以聚合的字段

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

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

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

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的值大。

elasticsearch聚合之bucket terms聚合

4.4 排序注意事项

4.4.1 _count 排序

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

4.4.2 字段值排序

使用字段值排序,不管是正序还是倒序,结果是准确的。
elasticsearch聚合之bucket terms聚合

4.4.3 子聚合排序

elasticsearch聚合之bucket terms聚合

4.5 多term聚合

elasticsearch聚合之bucket terms聚合

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
发表评论

评论已关闭。

相关文章