如何用Java API的QueryBuilder实现Elasticsearch嵌套分组查询
基于Elasticsearch Java API按
@geo.Source.Country.IsoCode分组统计的实现方案 要实现按@geo.Source.Country.IsoCode字段分组统计并得到指定格式的结果,核心是使用Elasticsearch的Terms Aggregation(词条聚合)完成分组计数,以下是具体实现方案:
1. 完整代码实现
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.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; // 假设已初始化RestHighLevelClient实例(client) public class GeoCountryAggregation { public static List<Map<String, Object>> queryCountryIsoCodeCount(String targetIndex) throws IOException { // 构建词条聚合:按@geo.Source.Country.IsoCode字段分组 TermsAggregationBuilder isoCodeAgg = AggregationBuilders.terms("country_iso_agg") .field("@geo.Source.Country.IsoCode.keyword") // 必须用keyword类型避免分词干扰 .size(100); // 控制返回的分组数量,按需调整 // 构建搜索请求,只返回聚合结果 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(QueryBuilders.matchAllQuery()) // 替换为你的过滤条件(如时间范围、severity过滤等) .aggregation(isoCodeAgg) .size(0); // 设置为0,不返回原始文档,提升效率 SearchRequest searchRequest = new SearchRequest(targetIndex); searchRequest.source(sourceBuilder); // 执行请求并解析结果 SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); Terms termsAggResult = response.getAggregations().get("country_iso_agg"); List<Map<String, Object>> resultList = new ArrayList<>(); for (Terms.Bucket bucket : termsAggResult.getBuckets()) { resultList.add(Map.of( "iso_code", bucket.getKeyAsString(), "count", bucket.getDocCount() )); } return resultList; } }
2. 关键注意事项
- 字段后缀
.keyword:如果@geo.Source.Country.IsoCode字段类型是text,必须使用.keyword后缀引用其不分词的子字段,否则分词会导致分组结果混乱(比如"US"被拆分成单个字符)。 - 聚合名称唯一性:
country_iso_agg是自定义的聚合标识,需确保在同一个搜索请求中唯一,用于后续从响应中提取聚合数据。 - 结果数量控制:
terms.size(100)限制返回的分组数,若需要更多分组可增大该值;sourceBuilder.size(0)避免返回原始文档,大幅提升查询性能。 - 过滤条件扩展:将
QueryBuilders.matchAllQuery()替换为实际业务需要的过滤查询(如QueryBuilders.rangeQuery("timestamp").gte("2022-11-01")),实现特定范围内的统计。
3. 返回结果示例
执行代码后,返回的List结构完全符合需求:
[{"iso_code": "US", "count": 15}, {"iso_code": "AE", "count": 102}, {"iso_code": "UA", "count": 8}]
内容的提问来源于stack exchange,提问作者Hayk Mkhitaryan
相关产品推荐
相关产品推荐

