elasticsearch聚合之bucketterms聚合
1。背景
此处简单记录一下bucket聚合下的terms聚合。记录一下terms聚合的各种用法,以及各种注意事项,防止以后忘记。2。前置条件2。1创建索引PUTindexperson{settings:{numberofshards:1},mappings:{properties:{id:{type:long},name:{type:keyword},sex:{type:keyword},age:{type:integer},province:{type:keyword},address:{type:text,analyzer:ikmaxword,fields:{keyword:{type:keyword,ignoreabove:256}}}}}}2。2准备数据PUTbulk{create:{index:indexperson,id:1}}{id:1,name:张三,sex:男,age:20,province:湖北,address:湖北省黄冈市罗田县匡河镇}{create:{index:indexperson,id:2}}{id:2,name:李四,sex:男,age:19,province:江苏,address:江苏省南京市}{create:{index:indexperson,id:3}}{id:3,name:王武,sex:女,age:25,province:湖北,address:湖北省武汉市江汉区}{create:{index:indexperson,id:4}}{id:4,name:赵六,sex:女,age:30,province:北京,address:北京市东城区}{create:{index:indexperson,id:5}}{id:5,name:钱七,sex:女,age:16,province:北京,address:北京市西城区}{create:{index:indexperson,id:6}}{id:6,name:王八,sex:女,age:45,province:北京,address:北京市朝阳区}3。各种聚合3。1统计人数最多的2个省3。1。1dslGETindexpersonsearch{size:0,aggs:{aggsex:{terms:{field:province,size:2}}}}3。1。2运行结果
运行结果
3。2统计人数最少的2个省3。2。1dslGETindexpersonsearch{size:0,aggs:{aggsex:{terms:{field:province,size:2,order:{count:asc}}}}}
注意:不推荐使用count:asc来统计,会导致统计结果不准,看下方的总结章节。3。2。2运行结果
运行结果
3。3根据字段值排序根据年龄聚合,返回年龄最小的2个聚合3。3。1dslGETindexpersonsearch{size:0,aggs:{aggsex:{terms:{field:age,size:2,order:{key:asc}}}}}
注意:这种根据字段值来排序,聚合的结果是正确的。3。3。2运行结果
运行结果
3。4子聚合排序先根据省聚合,然后根据每个聚合后的最小年龄排序3。4。1dslGETindexpersonsearch{size:0,aggs:{aggsex:{terms:{field:province,order:{minage:asc}},aggs:{minage:{min:{field:age}}}}}}GETindexpersonsearch{size:0,aggs:{aggsex:{terms:{field:province,order:{minage。min:asc}},aggs:{minage:{stats:{field:age}}}}}}
注意:子聚合排序一般也是不准的,但是如果是根据子聚合的最大值倒序和最小值升序又是准的。3。4。2运行结果
运行结果
3。5脚本聚合根据省聚合,如果地址中有黄冈市则需要出现黄冈市
3。5。1dsl
GETindexpersonsearch{size:0,runtimemappings:{provincesex:{type:keyword,script:Stringprovincedoc〔province〕。value;Stringaddressdoc〔address。keyword〕。value;if(address。contains(黄冈市)){emit(黄冈市);}else{emit(province);}}},aggs:{aggsex:{terms:{field:provincesex}}}}
注意事项
3。5。2运行结果
运行结果
3。6filter以省分组,并且只包含北的省,但是需要排除湖北省3。6。1dslGETindexpersonsearch{size:0,aggs:{aggprovince:{terms:{field:province,include:。北。,exclude:〔湖北〕}}}}
注意:当是字符串时,可以写正则表达式,当是数组时,需要写具体的值。3。6。2运行结果
运行结果
3。7多term聚合根据省和性别聚合,然后根据最大年龄倒序3。7。1dslGETindexpersonsearch{size:0,aggs:{genresandproducts:{multiterms:{size:10,shardsize:25,order:{maxage:desc},terms:〔{field:province,missing:defaultProvince},{field:sex}〕},aggs:{maxage:{max:{field:age}}}}}}
注意:terms聚合默认不支持多字段聚合,需要借助别的方式。此处使用multiterms来实现多字段聚合。3。7。2运行结果
运行结果
3。8missingvalue处理
missingvalue处理
3。9多个聚合同时返回根据省聚合和根据性别聚合
3。9。1dsl
GETindexpersonsearch{size:0,aggs:{aggprovince:{terms:{field:province}},aggsex:{terms:{field:sex,size:10}}}}
3。9。2运行结果
运行结果
4。总结
4。1可以聚合的字段
一般情况下,只有如下几种字段类型可以进行聚合操作keyword,numeric,ip,boolean和binary类型的字段。text类型的字段默认情况下是不可以进行聚合的,如果需要聚合,需要开启fielddata。
可以聚合的字段
4。2如果我们想返回所有的聚合Term结果
如果我们只想返回100或1000个唯一结果,可以增大size参数的值。但是如果我们想返回所有的,那么推荐使用compositeaggregation
如果我们想返回所有的聚合Term结果4。3聚合数据不准
我们通过terms聚合到的结果是一个大概的结果,不一定是完全正确的。
为什么?。举个例子:如果我们的集群有3个分片,此处我们想返回值最高的5个统计。即size5,假设先不考虑shardsize参数,那么此时每个节点会返回值最高的5个统计,然后再次聚合,返回,返回最终值最高的5个。这个貌似没什么问题,但是因为我们的数据是分布es的各个节点上的,可能某个统计项(北京市的用户数),在A节点是是排名前5,但是在B节点上不是排名前5,那么最终的统计结果是否是就会漏统计了。
如何解决:我们可以让es在每个节点上多返回几个结果,比如:我们的size5,那么我们每个节点就返回size1。510个结果,那么误差相应的就会减少。而这个size1。510就是shardsize的值,当然我们也可以手动指定,但一般需要比size的值大。
聚合数据不准
4。4排序注意事项
4。4。1count排序
默认情况下,使用的是count倒序的,但是我们可以指定成升序,但是这是不推荐的,会导致错误结果。如果我们想要升序,可以使用rareterms聚合。
count排序
4。4。2字段值排序
使用字段值排序,不管是正序还是倒序,结果是准确的。
字段值排序
4。4。3子聚合排序
子聚合排序
4。5多term聚合
多term聚合
5、源码地址
https:gitee。comhuan1993springcloudparentblobmastereses8apisrcmainjavacomhuanes8aggregationsbucketTermsAggs。java6。参考链接https:www。elastic。coguideenelasticsearchreferencecurrentsearchaggregationsbuckettermsaggregation。htmlhttps:www。elastic。coguideenelasticsearchreferencecurrentsearchaggregationsbucketmultitermsaggregation。html