聚合
请教一个计算平均差值的问题
Elasticsearch • God_lockin 回复了问题 • 3 人关注 • 3 个回复 • 3595 次浏览 • 2024-01-02 10:13
nested聚合, 如何获取父类字段?
Elasticsearch • yilongchuan 回复了问题 • 2 人关注 • 2 个回复 • 5641 次浏览 • 2022-02-11 18:10
复杂检索,复杂聚合,带数量限制
Elasticsearch • kirito 回复了问题 • 2 人关注 • 1 个回复 • 2017 次浏览 • 2021-09-09 15:05
ElasticSearch查询的语句怎么对聚合过滤分组
回复Elasticsearch • Rewardingggg 发起了问题 • 2 人关注 • 0 个回复 • 2270 次浏览 • 2021-08-08 23:35
复杂聚合后计算Others的方法
Elasticsearch • thewind 回复了问题 • 2 人关注 • 2 个回复 • 1859 次浏览 • 2021-05-25 11:26
聚合查询是否支持类似SQL IN的用法
Elasticsearch • medcl 回复了问题 • 4 人关注 • 3 个回复 • 3129 次浏览 • 2020-05-20 09:21
Elasticsearch使用类似having查询满足条件的数据
Elasticsearch • sun_tie 回复了问题 • 7 人关注 • 6 个回复 • 7675 次浏览 • 2020-05-06 16:36
聚合某个字段,后获取其发帖天数最多的前两个
Elasticsearch • laoyang360 回复了问题 • 2 人关注 • 1 个回复 • 3036 次浏览 • 2020-05-02 22:51
根据指定field搜索无重复元素的文档
Elasticsearch • bsll 回复了问题 • 3 人关注 • 2 个回复 • 2285 次浏览 • 2020-04-11 21:35
Elasticsearch对聚合结果进行分页,请问是否能够实现
Elasticsearch • laoyang360 回复了问题 • 3 人关注 • 1 个回复 • 6659 次浏览 • 2020-03-25 21:14
【聚合分析】一个订单作为一个文档,返回文档中指定field出现次数超过10的文档
Elasticsearch • laoyang360 回复了问题 • 2 人关注 • 1 个回复 • 2366 次浏览 • 2020-02-15 16:39
子聚合父 问题, 子文档关联查父文档时,怎么聚合每条子文档所对应的父文档?
Elasticsearch • laoyang360 回复了问题 • 3 人关注 • 3 个回复 • 2619 次浏览 • 2020-02-08 22:12
"aggs": {
"avg_rating": {
"avg": {
"script": "_score"
}
}
}
聚合部分这样写就可以了,如果script报
【scripts of type [inline], operation [aggs] and lang [groovy] are disabled】的错误
就在
就在配置文件elasticsearch.yml里
把
script.inline: on
script.indexed: on
script.engine.groovy.inline.aggs: on
script.engine.groovy.inline.update: on这几行配置加上然后重启els就可以了
我已经使用在了生产环境,是没有问题的。这个问题纠结了几天,终于找到方法了,跟帖在这里。
DELETE /test_agg
PUT /test_agg
{
"mappings": {
"agg_type": {
"properties": {
"all":{
"type": "nested",
"properties": {
"parent_id": {
"type": "integer"
},
"child_id": {
"type": "integer"
}
}
}
}
}
}
}
POST /test_agg/agg_type/1
{
"all":{
"parent_id":1,
"child_id":2
}
}
POST /test_agg/agg_type/2
{
"all":{
"parent_id":1,
"child_id":3
}
}
POST /test_agg/agg_type/3
{
"all":{
"parent_id":2,
"child_id":3
}
}
POST /test_agg/_search
POST /test_agg/agg_type/_search
{
"size": 0,
"aggs": {
"category": {
"aggs": {
"term_list": {
"terms": {
"field": "all.parent_id"
},
"aggs": {
"term_list": {
"terms": {
"field": "all.child_id"
}
}
}
}
},
"nested": {
"path": "all"
}
}
}
}
最简单的单层terms聚合大致是下面这样一个执行步骤:
[list=1]
为要聚合的字段构造Global Ordinals。 (什么是Global... 显示全部 »
最简单的单层terms聚合大致是下面这样一个执行步骤:
[list=1]
为要聚合的字段构造Global Ordinals。 (什么是Global Ordinals参考 global-ordinals . ), 这个过程的速度不是单纯和文档数量有关系,更多的是取决于索引有多少个段文件,以及字段的不同唯一值的数量(cardinality)。 段文件的数量和磁盘IO能力决定了多快能将这些数据读入内存,而字段唯一值的多少决定了需要在内存里生成多少个分桶,唯一值越多,分桶占用的内存越高。
根据match查询的结果,也就是得到的文档ID集合,借助统计字段的doc values,拿到统计字段的值集合。
将统计字段的值集合映射到为global ordinals构建的分桶里。
统计各个分桶里的值个数.
根据聚合设置的size,返回top size的分桶数据。
[/list]
海量数据场景下,对Terms aggregation性能影响最大的还是对应字段的唯一值的多寡。 冷执行的情况下,由于需要读取各个segments的doc values,如果segments非常多,构造global ordinals可能耗时非常长。对于不再更新的索引,将其force merge成一个segment,可以免去global ordinals的构造过程,从而极大提速聚合速度。 对于一直在更新的索引,可以延长索引refresh周期,提高global ordinals缓存的有效期。 在查询聚合性能要求高于写入性能的场景下,也可以利用eager_global_ordinals来将构建时间移到索引阶段。
如果聚合的场景是从大量的数据中过滤出少量数据进行聚合(百万级),可以在执行参数里加入 execution_hint: map ,直接在结果集上用map的方式进行计算,对比默认的global ordinals的计算方式速度可能会高几倍到几十倍。
如果是多层聚合,则又要复杂得多,bucket构建过程分为depth first和breath first两种,建议仔细读一下相关文档,结合数据特性进行测试分析后,选用合适的执行方式。
总结来说对于terms aggregation,ES提供了多种执行方式,各种方式在内存使用方面,速度方面各有取舍。通常来说,默认的执行方式多数场景下都没有什么问题,只有一些比较极端的场景下,ES不会非常智能的自动选择最佳执行路径,需要使用者对数据和ES本身有一定熟悉程度,灵活选择。
nested聚合, 如何获取父类字段?
回复Elasticsearch • yilongchuan 回复了问题 • 2 人关注 • 2 个回复 • 5641 次浏览 • 2022-02-11 18:10
ElasticSearch查询的语句怎么对聚合过滤分组
回复Elasticsearch • Rewardingggg 发起了问题 • 2 人关注 • 0 个回复 • 2270 次浏览 • 2021-08-08 23:35
Elasticsearch使用类似having查询满足条件的数据
回复Elasticsearch • sun_tie 回复了问题 • 7 人关注 • 6 个回复 • 7675 次浏览 • 2020-05-06 16:36
聚合某个字段,后获取其发帖天数最多的前两个
回复Elasticsearch • laoyang360 回复了问题 • 2 人关注 • 1 个回复 • 3036 次浏览 • 2020-05-02 22:51
Elasticsearch对聚合结果进行分页,请问是否能够实现
回复Elasticsearch • laoyang360 回复了问题 • 3 人关注 • 1 个回复 • 6659 次浏览 • 2020-03-25 21:14
【聚合分析】一个订单作为一个文档,返回文档中指定field出现次数超过10的文档
回复Elasticsearch • laoyang360 回复了问题 • 2 人关注 • 1 个回复 • 2366 次浏览 • 2020-02-15 16:39
子聚合父 问题, 子文档关联查父文档时,怎么聚合每条子文档所对应的父文档?
回复Elasticsearch • laoyang360 回复了问题 • 3 人关注 • 3 个回复 • 2619 次浏览 • 2020-02-08 22:12
ES Aggs根据聚合的结果(数值)进行过滤
Elasticsearch • ziyou 发表了文章 • 1 个评论 • 23205 次浏览 • 2019-10-10 14:32
前言
我们在使用聚合时总是有各种各样的聚合需求,其中一个比较常用的就是根据聚合的结果过滤聚合的桶,例如:1、每个IP登录次数超过5次的IP;2、每个IP登录人数超过2的IP。 还有我之前的一个案例,访问量超过1000的人数,这些都是很常见的统计需求。
案例需求
我们在使用聚合计算的时候一般都有两类,一种是计算文档的数量,另一种是计算文档内字段的值的数量(去重计算)或者值的数学计算。两种聚合计算在过滤的时候采用不同的方法来计算。
我们使用以下案例来说明两种过滤的不同: 用户每次登录都会记录一个登录记录:
{"userID":"a","IP":"10.70.25.1","time":"2019-10-10 12:12:12.222"}
然后提出以下两个需求: 1、每个IP登录次数超过5次的IP; 2、每个IP登录人数超过2的IP。
实现
每个IP登录次数超过5次的IP
这个是对登录记录个数的桶聚合统计,然后过滤。使用IP做term聚合,就可以得出每个IP的登录次数,然后term聚合中有一个参数min_doc_count这个字段就可以对文档数量进行过滤,具体的语句如下: 查询语句
{
"aggs": {
"IP": {
"terms": {
"field": "IP",
"size": 3000,
"order": {
"_count": "desc"
},
"min_doc_count": 5
}
}
},
"size": 0
}
结果
{
"took" : 614,
"timed_out" : false,
"num_reduce_phases" : 3,
"_shards" : {
"total" : 1105,
"successful" : 1105,
"skipped" : 75,
"failed" : 0
},
"hits" : {
"total" : 2826,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"IP" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "10.25.90.139",
"doc_count" : 61
},
{
"key" : "10.25.78.146",
"doc_count" : 45
},
{
"key" : "10.25.94.22",
"doc_count" : 21
},
{
"key" : "10.25.75.52",
"doc_count" : 18
},
{
"key" : "10.25.89.32",
"doc_count" : 13
},
{
"key" : "10.25.93.243",
"doc_count" : 10
},
{
"key" : "10.25.78.189",
"doc_count" : 9
},
{
"key" : "10.25.90.82",
"doc_count" : 8
},
{
"key" : "10.25.91.240",
"doc_count" : 8
},
{
"key" : "10.25.90.57",
"doc_count" : 7
},
{
"key" : "10.25.91.251",
"doc_count" : 7
},
{
"key" : "10.25.95.166",
"doc_count" : 6
},
{
"key" : "10.25.89.33",
"doc_count" : 5
},
{
"key" : "10.25.90.88",
"doc_count" : 5
},
{
"key" : "10.25.92.53",
"doc_count" : 5
}
]
}
}
}
每个IP登录人数超过2的IP
这个是对登录记录用户ID的去重数聚合,然后过滤。对用户ID进行去重可以使用Cardinality Aggregation聚合,然后再使用Bucket Selector Aggregation聚合过滤器过滤数据。具体内容如下: 查询语句
{
"aggs": {
"IP": {
"terms": {
"field": "IP",
"size": 3000,
"order": {
"distinct": "desc"
},
"min_doc_count": 5
},
"aggs": {
"distinct": {
"cardinality": {
"field": "IP.keyword"
}
},
"dd":{
"bucket_selector": {
"buckets_path": {"userCount":"distinct"},
"script": "params.userCount > 2"
}
}
}
}
},
"size": 0
}
结果
{
"took" : 317,
"timed_out" : false,
"num_reduce_phases" : 3,
"_shards" : {
"total" : 1105,
"successful" : 1105,
"skipped" : 75,
"failed" : 0
},
"hits" : {
"total" : 2826,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"IP" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "10.25.75.52",
"doc_count" : 18,
"distinct" : {
"value" : 4
}
},
{
"key" : "10.25.78.146",
"doc_count" : 45,
"distinct" : {
"value" : 3
}
},
{
"key" : "10.25.90.139",
"doc_count" : 61,
"distinct" : {
"value" : 3
}
},
{
"key" : "10.25.91.240",
"doc_count" : 8,
"distinct" : {
"value" : 3
}
},
{
"key" : "10.25.94.22",
"doc_count" : 21,
"distinct" : {
"value" : 3
}
}
]
}
}
}
ElasticSearch java API - 聚合查询
Elasticsearch • carlislelee 发表了文章 • 3 个评论 • 53986 次浏览 • 2016-09-20 17:16
"mappings": {
"player": {
"properties": {
"name": {
"index": "not_analyzed",
"type": "string"
},
"age": {
"type": "integer"
},
"salary": {
"type": "integer"
},
"team": {
"index": "not_analyzed",
"type": "string"
},
"position": {
"index": "not_analyzed",
"type": "string"
}
},
"_all": {
"enabled": false
}
}
}
索引中的全部数据:
首先,初始化Builder:SearchRequestBuilder sbuilder = client.prepareSearch("player").setTypes("player");
接下来举例说明各种聚合操作的实现方法,因为在es的api中,多字段上的聚合操作需要用到子聚合(subAggregation),初学者可能找不到方法(网上资料比较少,笔者在这个问题上折腾了两天,最后度了源码才彻底搞清楚T_T),后边会特意说明多字段聚合的实现方法。另外,聚合后的排序也会单独说明。
- group by/count
select team, count(*) as player_count from player group by team;
ES的java api:TermsBuilder teamAgg= AggregationBuilders.terms("player_count ").field("team");
sbuilder.addAggregation(teamAgg);
SearchResponse response = sbuilder.execute().actionGet();
- group by多个field
select team, position, count(*) as pos_count from player group by team, position;
ES的java api:TermsBuilder teamAgg= AggregationBuilders.terms("player_count ").field("team");
TermsBuilder posAgg= AggregationBuilders.terms("pos_count").field("position");
sbuilder.addAggregation(teamAgg.subAggregation(posAgg));
SearchResponse response = sbuilder.execute().actionGet();
- max/min/sum/avg
select team, max(age) as max_age from player group by team;
ES的java api:TermsBuilder teamAgg= AggregationBuilders.terms("player_count ").field("team");
MaxBuilder ageAgg= AggregationBuilders.max("max_age").field("age");
sbuilder.addAggregation(teamAgg.subAggregation(ageAgg));
SearchResponse response = sbuilder.execute().actionGet();
- 对多个field求max/min/sum/avg
select team, avg(age)as avg_age, sum(salary) as total_salary from player group by team;
ES的java api:TermsBuilder teamAgg= AggregationBuilders.terms("team");
AvgBuilder ageAgg= AggregationBuilders.avg("avg_age").field("age");
SumBuilder salaryAgg= AggregationBuilders.avg("total_salary ").field("salary");
sbuilder.addAggregation(teamAgg.subAggregation(ageAgg).subAggregation(salaryAgg));
SearchResponse response = sbuilder.execute().actionGet();
- 聚合后对Aggregation结果排序
select team, sum(salary) as total_salary from player group by team order by total_salary desc;
ES的java api:TermsBuilder teamAgg= AggregationBuilders.terms("team").order(Order.aggregation("total_salary ", false);
SumBuilder salaryAgg= AggregationBuilders.avg("total_salary ").field("salary");
sbuilder.addAggregation(teamAgg.subAggregation(salaryAgg));
SearchResponse response = sbuilder.execute().actionGet();
需要特别注意的是,排序是在TermAggregation处执行的,Order.aggregation函数的第一个参数是aggregation的名字,第二个参数是boolean型,true表示正序,false表示倒序。
- Aggregation结果条数的问题
TermsBuilder teamAgg= AggregationBuilders.terms("team").size(15);
- Aggregation结果的解析/输出
Map<String, Aggregation> aggMap = response.getAggregations().asMap();
StringTerms teamAgg= (StringTerms) aggMap.get("keywordAgg");
Iterator<Bucket> teamBucketIt = teamAgg.getBuckets().iterator();
while (teamBucketIt .hasNext()) {
Bucket buck = teamBucketIt .next();
//球队名
String team = buck.getKey();
//记录数
long count = buck.getDocCount();
//得到所有子聚合
Map subaggmap = buck.getAggregations().asMap();
//avg值获取方法
double avg_age= ((InternalAvg) subaggmap.get("avg_age")).getValue();
//sum值获取方法
double total_salary = ((InternalSum) subaggmap.get("total_salary")).getValue();
//...
//max/min以此类推
}
- 总结