• -------------------------------------------------------------
  • ====================================

ElasticSearch java API – 聚合查询

elasticsearch dewbay 5年前 (2019-04-12) 1882次浏览 已收录 0个评论 扫描二维码

以球员信息为例,player 索引的 player type 包含 5 个字段,姓名,年龄,薪水,球队,场上位置。
index 的 mapping 为:
“mappings”: {
“quote”: {
“properties”: {
“adj_close”: {
“type”: “long”
},
“open”: {
“type”: “long”
},
“symbol”: {
“index”: “not_analyzed”,
“type”: “string”
},
“volume”: {
“type”: “long”
},
“high”: {
“type”: “long”
},
“low”: {
“type”: “long”
},
“date”: {
“format”: “strict_date_optional_time||epoch_millis”,
“type”: “date”
},
“close”: {
“type”: “long”
}
},
“_all”: {
“enabled”: false
}
}
}

索引中的全部数据:
name age salary team position
james 33 3000 cav sf
irving 25 2000 cav pg
curry 29 1000 war pg
thompson 26 2000 war sg
green 26 2000 war pf
garnett 40 1000 tim pf
towns 21 500 tim c
lavin 21 300 tim sg
wigins 20 500 tim sf
首先,初始化 Builder:
SearchRequestBuilder sbuilder = client.prepareSearch(“player”).setTypes(“player”);
接下来举例说明各种聚合操作的实现方法,因为在 es 的 api 中,多字段上的聚合操作需要用到子聚合(subAggregation),初学者可能找不到方法(网上资料比较少,笔者在这个问题上折腾了两天,最后度了源码才彻底搞清楚 T_T),后边会特意说明多字段聚合的实现方法。另外,聚合后的排序也会单独说明。

  1. group by/count
    例如要计算每个球队的球员数,如果使用 SQL 语句,应表达如下:
    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();2.group by 多个 field例如要计算每个球队每个位置的球员数,如果使用 SQL 语句,应表达如下: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();
    3.max/min/sum/avg
    例如要计算每个球队年龄最大/最小/总/平均的球员年龄,如果使用 SQL 语句,应表达如下:
    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();
    4.对多个 field 求 max/min/sum/avg
    例如要计算每个球队球员的平均年龄,同时又要计算总年薪,如果使用 SQL 语句,应表达如下:
    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();
    5.聚合后对 Aggregation 结果排序
    例如要计算每个球队总年薪,并按照总年薪倒序排列,如果使用 SQL 语句,应表达如下:
    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 表示倒序。
6.Aggregation 结果条数的问题
默认情况下,search 执行后,仅返回 10 条聚合结果,如果想反悔更多的结果,需要在构建 TermsBuilder 时指定 size:
TermsBuilder teamAgg= AggregationBuilders.terms(“team”).size(15);
7.Aggregation 结果的解析/输出
得到 response 后:
Map aggMap = response.getAggregations().asMap();
StringTerms teamAgg= (StringTerms) aggMap.get(“keywordAgg”);
Iterator 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 以此类推
}

  1. 总结
    综上,聚合操作主要是调用了 SearchRequestBuilder 的 addAggregation 方法,通常是传入一个 TermsBuilder,子聚合调用 TermsBuilder 的 subAggregation 方法,可以添加的子聚合有 TermsBuilder、SumBuilder、AvgBuilder、MaxBuilder、MinBuilder 等常见的聚合操作。

从实现上来讲,SearchRequestBuilder 在内部保持了一个私有的 SearchSourceBuilder 实例, SearchSourceBuilder 内部包含一个 List,每次调用 addAggregation 时会调用 SearchSourceBuilder 实例,添加一个 AggregationBuilder。
同样的,TermsBuilder 也在内部保持了一个 List,调用 addAggregation 方法(来自父类 addAggregation)时会添加一个 AggregationBuilder。有兴趣的读者也可以阅读源码的实现。

如果有任何问题,欢迎一起讨论,如果文中有什么错误,欢迎批评指正。

注:文中使用的 Elastic Search API 版本为 2.3.2

作者:debug_myself
来源:CSDN
原文:https://blog.csdn.net/carlislelee/article/details/52598022
版权声明:本文为博主原创文章,转载请附上博文链接!


露水湾 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:ElasticSearch java API – 聚合查询
喜欢 (0)
[]
分享 (0)
关于作者:
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址