如何在OpenSearch中并行执行Term聚合查询?
在OpenSearch 2.17中实现单个查询内的多聚合并行执行
问题背景
我们有一个用于统计多字段词项数量的OpenSearch查询,DSL如下:
{ "query": { "bool": { "filter": [ { "term": { "your_filter_field": "your_filter_value" } } ] } }, "aggs": { "aggregation_1": { "terms": { "field": "field_1" } }, "aggregation_2": { "terms": { "field": "field_2" } }, ... "aggregation_50": { "terms": { "field": "field_3" } } } }
在OpenSearch 2.17版本中,这些顶级terms聚合会串行执行,导致查询速度较慢。目前采用multisearch将每个聚合拆分为单独请求的临时方案,虽然速度有所提升,但重复执行相同过滤器存在明显的资源浪费。需要找到在单个查询内并行执行多个聚合的方法。
解决方案
1. 验证聚合执行模式
首先通过profile API确认聚合是否真的串行执行,这有助于排查问题根源:
{ "profile": true, "query": { "bool": { "filter": [ { "term": { "your_filter_field": "your_filter_value" } } ] } }, "aggs": { "aggregation_1": { "terms": { "field": "field_1" } }, ... } }
查看返回的profile数据,重点关注聚合阶段的线程分配和执行顺序。
2. 调整并发分片请求配置
OpenSearch的search.max_concurrent_shard_requests参数控制单个搜索请求中并发分片请求的数量,默认值为5,可能不足以支撑多聚合并行。可以通过两种方式调整:
- 全局配置:在
opensearch.yml中修改参数(需重启节点生效):search.max_concurrent_shard_requests: 10 - 请求级配置:在查询URL中添加参数,仅对当前请求生效:
注意:该值不宜过高,避免给集群带来过大负载,建议根据节点数和硬件配置调整(比如设置为节点数的2-3倍)。GET /your_index/_search?search_max_concurrent_shard_requests=10
3. 重构聚合结构
将所有terms聚合嵌套在一个filter聚合下,确保过滤器仅执行一次,同时子聚合可以并行处理:
{ "query": { "match_all": {} }, "aggs": { "filtered_dataset": { "filter": { "term": { "your_filter_field": "your_filter_value" } }, "aggs": { "aggregation_1": { "terms": { "field": "field_1" } }, "aggregation_2": { "terms": { "field": "field_2" } }, ... "aggregation_50": { "terms": { "field": "field_3" } } } } } }
这种结构下,过滤器会先对数据集进行一次过滤,然后所有子聚合基于过滤后的数据集并行执行,避免了重复过滤的开销。
4. 优化聚合参数
- 为
terms聚合设置合理的size值,避免不必要的计算和数据传输; - 如果字段是高基数字段,可启用
show_term_doc_count_error来平衡性能和精度,但仅在必要时使用。
效果对比
采用上述方案后,单个查询内的多聚合会并行执行,既避免了multisearch的重复过滤开销,又能获得接近拆分请求的执行速度,同时降低了集群的请求负载。
内容的提问来源于stack exchange,提问作者Lukáš Křečan
相关产品推荐
相关产品推荐

