在Elasticsearch 7.3 中,使用Java API实现聚合查询是非常常见的实践。这里给出一个虚构的电视案例,假设我们有一个电视节目索引,其中包含诸如channel
(频道)、genre
(类型)、aired_date
(播出日期)和viewership
(观众人数)等字段。现在我们想通过Java API做如下聚合分析:
- 按照频道名称分组,统计每个频道的节目数量。
- 在每个频道内,按照节目类型进一步细分,并统计每种类型的节目数量。
- 对每个频道的所有节目,计算平均观众人数。
以下是使用RestHighLevelClient
实现这个案例的Java代码片段:
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregation.AggregationBuilders;
import org.elasticsearch.search.aggregation.bucket.terms.Terms;
import org.elasticsearch.search.aggregation.bucket.terms.Terms.Bucket;
import org.elasticsearch.search.aggregation.metrics.Avg;
import java.io.IOException;
public class TvShowAggregationExample {
private RestHighLevelClient client;
public void aggregateTvShows() throws IOException {
// 创建搜索请求
SearchRequest searchRequest = new SearchRequest("tv_shows");
// 设置搜索源,此处假设我们没有特定的查询条件,只需对所有文档进行聚合
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchAllQuery()); // 或者使用具体的查询条件
// 第一层聚合:按频道分组
TermsAggregationBuilder channelsAgg = AggregationBuilders.terms("by_channel").field("channel");
// 第二层聚合:在每个频道内按类型分组
TermsAggregationBuilder genresAgg = AggregationBuilders.terms("by_genre").field("genre");
genresAgg.subAggregation(AggregationBuilders.avg("avg_viewership").field("viewership")); // 计算平均观众人数
channelsAgg.subAggregation(genresAgg);
sourceBuilder.aggregation(channelsAgg);
searchRequest.source(sourceBuilder);
// 执行搜索请求
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 解析聚合结果
Terms byChannel = searchResponse.getAggregations().get("by_channel");
for (Bucket channelBucket : byChannel.getBuckets()) {
String channelName = channelBucket.getKeyAsString();
System.out.println("Channel: " + channelName);
Terms byGenre = channelBucket.getAggregations().get("by_genre");
for (Bucket genreBucket : byGenre.getBuckets()) {
String genre = genreBucket.getKeyAsString();
long genreCount = genreBucket.getDocCount();
Avg avgViewership = genreBucket.getAggregations().get("avg_viewership");
double avgViewers = avgViewership.getValue();
System.out.println("\tGenre: " + genre + ", Count: " + genreCount + ", Average Viewership: " + avgViewers);
}
}
}
// 初始化并关闭Elasticsearch客户端的部分省略...
}
在上述代码中,我们首先创建了一个搜索请求,然后在SearchSourceBuilder
中设置了聚合条件。首先是顶层的按频道名称的terms
聚合,接着在其内部定义了次级按节目类型的terms
聚合,并在此聚合内又添加了一个计算平均观众人数的avg
聚合。最后,执行搜索并解析聚合结果,输出每个频道及其包含的节目类型以及相应的观众人数统计数据。