bigywater.tech
Elasticsearch · 90

聚合结果为什么不能直接当搜索结果

真实用size=2限制命中结果数量,验证terms聚合依然精确统计全部5篇匹配文档不受分页影响,并打印聚合桶的原始JSON结构证明它只是key和doc_count的统计摘要,不携带任何可直接展示的文档身份信息。

size=2只返回2条hits
真实聚合桶依然统计出了全部5篇文档
聚合桶原始结构
真实只有key和doc_count,没有_id和_source
本质区别
真实聚合是统计摘要,查询hits才是可展示的文档列表

做的事:真实索引5篇文档,把size设成2,同时跑一个按cat分组的terms聚合,看聚合是不是也只统计了那2条

代码真实索引5篇文档: cat=a的3篇 / cat=b的2篇 POST /agr_test/_search {"size":2,"query":{"match_all":{}},"aggs":{"by_cat":{"terms":{"field":"cat"}}}}

验证:聚合桶真实精确统计出了全部5篇文档(a:3,b:2),完全不受size=2这个分页参数的限制

实测 · 本机 Elasticsearch 8.15.0 执行输出
hits返回: 2条(真实被size=2截断)
hits.total: 5(真实匹配总数)

聚合桶by_cat:
→ a: doc_count=3
→ b: doc_count=2
(真实3+2=5,精确等于全部匹配文档数,不是只统计了那2条被返回的文档)

这组真实结果是理解聚合本质的第一个关键点:聚合真实是在查询匹配到的全部文档集合上独立计算的,跟size/from这些控制"最终展示给用户多少条命中结果"的分页参数真实完全没有关系——哪怕size设成0(本系列很多实验都这么用),聚合依然会真实在全部匹配文档上跑完整的统计。这说明一次请求里,hits(要展示的文档列表)和aggregations(统计摘要)真实是两条独立的产出管线,只是共享同一次查询匹配的结果集合作为输入。

真实打印出聚合桶的原始JSON结构,看它到底携带了哪些信息

代码POST /agr_test/_search {"size":0,"aggs":{"by_cat":{"terms":{"field":"cat"}}}}

验证:每个桶真实只有key和doc_count两个字段,没有_id、没有_source,没有任何可以回链到具体文档的信息

实测 · 本机执行输出
{
  "by_cat": {
    "doc_count_error_upper_bound": 0,
    "sum_other_doc_count": 0,
    "buckets": [
      { "key": "a", "doc_count": 3 },
      { "key": "b", "doc_count": 2 }
    ]
  }
}
这组真实的原始结构直接回答了标题的问题:聚合桶{"key":"a","doc_count":3}真实只是一条统计摘要——"值为a的文档有3篇",它本身真实不携带任何一篇具体文档的信息,没有_id、没有_source、没有能让前端直接渲染成一条可点击结果条目的数据。如果真实想要"按分类分组,并展示每组的代表文档",必须真实像本系列第81篇验证过的那样,在聚合里显式嵌套top_hits子聚合,专门把具体文档重新捞回来——聚合本身从设计上就是为了回答"有多少""平均值是多少""哪个最多"这类统计性问题,而不是为了产出一份可以直接当成搜索结果页面展示的文档列表。这也是为什么聚合和查询在ES里真实被设计成两个独立但可以在同一次请求里共存的产出:查询负责"哪些文档匹配、该展示哪一页",聚合负责"对匹配到的全部文档做一次统计总结",两者的职责和产出形态真实从根上就不同,不能把其中一个的产出直接套用成另一个的用途。

分步演示:从聚合不受size限制到桶结构本身不携带文档信息的完整验证

每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。

聚合是独立于分页之外的统计摘要,桶本身不携带任何文档身份信息
这一步新验证的聚合特性

    本文用到的工具

    • 本机真实部署的 Elasticsearch 8.15.0(单节点,tar包直接启动)
    • 真实的 terms 聚合与查询 hits 结构对比
    京ICP备2026067502号-1京公网安备11010502063487号