通过单次跨索引聚合(terms on `_index` + 子聚合 on `provider.keyword`),替代逐索引循环查询,可显著提升多索引去重查询性能。
在 Elasticsearch 中,当需要从上百个索引中提取某个字段(如 provider.keyword)的所有唯一值时,若采用“遍历每个索引 → 单独执行 terms 聚合 → 合并结果”的方式(即原始代码中的 for 循环),不仅会产生大量 HTTP 请求和网络开销,还会因重复初始化搜索上下文、分片协调及结果归并而严重拖慢响应速度。
更优解:使用跨索引聚合 + 嵌套聚合(Multi-level Aggregation)
Elasticsearch 支持对多个索引(甚至通配符或 _all)一次性执行聚合操作。关键优化点如下:
示例优化代码(Java High-Level REST Client):
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("_all"); // 或更安全的 getIndicesPattern(),如 "myapp-202*-*"
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery()).size(0); // 关键:不返回文档内容
String aggregationIndexName = "by_index";
String aggregationProviderName = "by_provider";
searchSourceBuilder.aggregation(
AggregationBuilders.terms(aggregationIndexName)
.field("_index")
.size(100) // 确保覆盖全部索引(索引数 
≤ 100)
.subAggregation(
AggregationBuilders.terms(aggregationProviderName)
.field("provider.keyword")
.size(1000) // 根据业务预估 provider 去重后数量,建议 ≥ 实际唯一值量级
)
);
searchRequest.source(searchSourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);解析聚合结果(提取全部唯一 provider 值):
Terms indicesAgg = response.getAggregations().get(aggregationIndexName); SetallUniqueProviders = new HashSet<>(); for (Terms.Bucket indexBucket : indicesAgg.getBuckets()) { Terms providerAgg = indexBucket.getAggregations().get(aggregationProviderName); for (Terms.Bucket providerBucket : providerAgg.getBuckets()) { allUniqueProviders.add(providerBucket.getKeyAsString()); } } // allUniqueProviders 即为全量去重后的 provider 列表
⚠️ 注意事项:
综上,将 N 次独立聚合收敛为 1 次嵌套聚合,是提升多索引唯一值提取性能最直接、最有效的方式——既降低集群负载,又大幅缩短端到端延迟。