You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Elasticsearch Terms聚合查询CPU飙升与响应过慢问题求助

问题背景与疑问

索引与存储信息

  • 索引包含约12亿文档,分布在14个分片上,总数据量350GB,每个分片数据量25-30GB
  • 包含keyword类型字段product_id,每个product_id最多关联100个文档,唯一product_id约1.5亿个
  • 未设置eager_global_ordinals: true

查询语句

GET product_items/_search 
{
  "size": 0,
  "query": {
    "terms": {
      "product_id": ["485d2000-d3a6f5088c1c", "acf82780-b7cbdeb350ad"]
    }
  },
  "aggs": {
    "group_by_products": {
      "terms": {
        "field": "product_id", 
        "size": 2
      }, 
      "aggs": {
        "top_documents": {
          "top_hits": {
            "size": 5, 
            "sort": [
              {"item_updated_at": {"order": "desc"}}
              ]
          }
        }
      }
    }
  }
}

遇到的问题

首次执行查询时节点CPU飙升,最终请求超时,推测是构建全局序数导致;CPU峰值下降后,请求响应仍需1秒以上。需要解决:

  1. 消除CPU飙升现象
  2. 缩短查询执行时间

疑问

  1. 考虑到唯一product_id数量庞大,设置eager_global_ordinals: true是否安全?
  2. 设置execution_hint: map能否解决问题?
  3. 还有哪些其他优化方法可缩短查询执行时间?

解决方案与分析

1. 设置eager_global_ordinals: true是否安全?

完全安全,但得先算好内存开销:

  • 1.5亿个唯一product_id的全局序数,每个条目大概占16字节(包含long型序数和对象引用),总内存开销约2.4GB,分摊到14个分片,每个分片仅占170MB左右——这个规模在常规Elasticsearch集群的堆内存配置下完全可控。
  • 开启后,全局序数会在索引刷新后异步后台预构建,不会等到查询时临时构建,直接根治首次查询的CPU飙升和超时问题。
  • 唯一需要注意的是:如果索引写入/刷新频繁,预构建会带来少量平稳的后台CPU开销,但比起查询时突然炸CPU的情况,这种可控的开销根本不算事。

2. 设置execution_hint: map能否解决问题?

能缓解首次查询的CPU飙升,但没法彻底解决响应慢的问题:

  • execution_hint: map会让terms聚合直接用内存哈希表统计,不用依赖全局序数。你的查询只指定了2个product_id,map模式会直接过滤匹配文档,在内存里统计这两个值,不会触发全量全局序数构建,自然不会炸CPU。
  • 但每次查询还是要遍历匹配的文档做内存统计,要是匹配的文档数量多,响应时间还是会偏高,属于治标不治本的方案。

3. 其他优化方法

(1)重构查询逻辑,砍掉冗余聚合

你的查询已经用terms过滤了指定的product_id,外层的group_by_products聚合完全是重复统计,直接用collapse替代terms+top_hits的组合,性能能提一大截:

GET product_items/_search
{
  "size": 0,
  "query": {
    "terms": {
      "product_id": ["485d2000-d3a6f5088c1c", "acf82780-b7cbdeb350ad"]
    }
  },
  "collapse": {
    "field": "product_id",
    "inner_hits": {
      "name": "top_documents",
      "size": 5,
      "sort": [{"item_updated_at": {"order": "desc"}}]
    }
  }
}

collapse会直接按product_id折叠结果,返回每个匹配id的最新5条文档,不需要做全量聚合统计,速度比原来的写法快得多。

(2)给排序字段做针对性优化

  • 确保item_updated_at的doc_values是开启状态(默认就是开的),避免查询时在内存里排序,直接用磁盘上的有序结构取数据。
  • 如果经常要查每个产品的最新文档,可以在写入时就维护好——比如给每个product_id单独存最新的5条数据到一个小索引里,查询时直接查这个小索引,不用每次都从12亿文档里捞。

(3)分片与路由优化

  • 当前每个分片25-30GB偏大,推荐分片大小是10-20GB,拆成20-28个分片能降低单个分片的查询压力,提升并行查询效率。
  • 给product_id设置routing,让同一个product_id的文档都落在同一个分片上,查询时只访问对应分片,不用遍历所有14个分片,能省不少资源。

(4)内存与缓存调优

  • 堆内存别超过物理内存的50%,也别超过32GB,留足够空间给文件系统缓存,让常用的分片数据能缓存到内存里,减少磁盘IO。
  • 开启eager_global_ordinals后,全局序数会被缓存起来,后续查询直接复用,不用重复构建。

内容的提问来源于stack exchange,提问作者Aditya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 11:50:06