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

Rails使用Searchkick如何实现Elasticsearch分组获取各分组文章ID

Elasticsearch按status分组返回对应文章ID实现方案

现有索引结构

索引中存储的文章文档格式如下:

{
  "id": 1011,
  "title": "abcd",
  "author": "author1",
  "status": "published"
}

需求说明

按status字段对所有文章分组,返回格式如下:

{
  "published": [1011, 1012, ....],
  "draft": [2011],
  "deleted": [3011]
}

之前使用Article.search('*',aggs: [:status], load: false).aggs的简化聚合写法,仅能返回各状态分组的文档计数,无法获取分组下的文章ID列表。

正确实现方式

普通terms聚合默认仅返回分桶计数,要获取桶内的文档字段,需要使用terms分桶聚合 + 嵌套子聚合的方式实现,以下是基于Ruby on Rails生态常用Elasticsearch客户端的实现代码:

  1. 自定义聚合查询DSL,通过top_hits子聚合拉取每个分桶下的文章ID:
# size:0 代表不返回原始命中文档,仅返回聚合结果,减少不必要的性能开销
search_result = Article.search(
  "*",
  body: {
    size: 0,
    query: { match_all: {} },
    aggs: {
      group_by_status: {
        terms: {
          field: :status,
          size: 10 # 按实际status枚举值数量调整,确保覆盖所有状态
        },
        aggs: {
          article_ids: {
            top_hits: {
              size: 10000, # 按单状态下最大文章数调整,确保返回全量ID,默认top_hits仅返回10条
              _source: [:id] # 仅返回id字段,降低数据传输量
            }
          }
        }
      }
    }
  },
  load: false
)
  1. 遍历聚合结果,组装成目标格式:
grouped_article_ids = {}
search_result.aggs["group_by_status"]["buckets"].each do |bucket|
  current_status = bucket["key"]
  current_ids = bucket["article_ids"]["hits"]["hits"].map { |hit| hit["_source"]["id"] }
  grouped_article_ids[current_status] = current_ids
end

优化方案&注意事项

  • 如果使用Elasticsearch 7.10及以上版本,且不需要获取文档其他字段,可以用terms子聚合替代top_hits,性能更优,子聚合部分替换为如下写法即可:
    aggs: {
      article_ids: {
        terms: {
          field: :id,
          size: 10000 # 和top_hits的size规则一致,需大于单组最大文档数
        }
      }
    }
    
    对应结果提取逻辑调整为:current_ids = bucket["article_ids"]["buckets"].map { |id_bucket| id_bucket["key"] }
  • 必须确保status字段映射为keyword类型,否则会因为分词导致分桶结果不符合预期。
  • 如果单状态下的文章量超过1万,不建议单次聚合拉取全量数据,可以使用composite聚合做分批游标拉取,避免ES内存压力过大。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 18:54:22