📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

在使用 Easysearch 做统计分析时,很多人都会遇到一个似曾相识的问题:

“我这条聚合写得没问题,但结果总感觉不太对。”

文档数对不上、排行榜顺序异常、同一份数据在不同时间查询结果略有差异……
这些现象往往不是 Bug,而是聚合本身的计算特性在起作用。

本文将从 Easysearch 的聚合机制出发,系统讲清楚聚合精度与近似这一经常被忽略、却非常关键的话题,帮助你在“结果不对”时,知道该从哪里排查。


一、Easysearch 简介:不只是搜索,更是实时分析引擎 #

Easysearch 是由 INFINI Labs 推出的国产自研的分布式搜索与分析引擎,衍生自 Elasticsearch ,广泛应用于:

  • 日志分析
  • 业务指标统计
  • 排行榜与趋势分析
  • 实时监控看板

在 Easysearch 中,Aggregations(聚合) 是构建统计报表的核心能力。
但与传统数据库的 GROUP BY 不同,Easysearch 的聚合是分布式、并行、近实时计算的,这也决定了它在“精度”上的一些天然取舍。


二、为什么聚合结果会“看起来不对”? #

在讨论具体问题之前,先明确一个重要前提:

Easysearch 的聚合结果,并不总是“绝对精确”的。

这不是缺陷,而是设计选择。

原因很简单:

  • 数据量可能非常大
  • 数据分布在多个分片、多个节点
  • 聚合需要在有限时间内返回结果

为了在性能、资源、延迟之间取得平衡,Easysearch 在部分场景下会采用近似计算分阶段合并的方式。

理解这一点,是正确使用聚合的第一步。


三、最常见的精度与近似场景解析 #

下面我们结合实际使用中最容易踩坑的几个聚合场景,逐一拆解“为什么结果会不一样”。


3.1 terms 聚合:排行榜为什么不稳定? #

terms 是最常用的桶聚合,用于做排行榜、分类统计,例如:

  • Top N 用户
  • Top N 商品
  • Top N 接口

但它也是**最容易产生“精度误解”**的聚合之一。

3.1.1 问题表现 #

  • Top 10 排行榜顺序偶尔变化
  • 某些边缘值忽隐忽现
  • 实际类别很多,但返回结果有限

3.1.2 根本原因 #

terms 聚合的执行过程是:

  1. 每个分片先统计自己的 Top N
  2. 再由协调节点进行合并
  3. 最终返回全局 Top N

为了避免分片返回过多数据,Easysearch 默认会:

  • 限制每个分片返回的桶数量 size * 1.5 + 10
  • 对低频项进行裁剪

这意味着:分片级别的“候选集”本身就是近似的。

如果想提高精度,可以通过调大 shard_size 来让分片返回更多候选桶。

3.1.3 这是 Bug 吗? #

不是。这是为了避免在高基数场景下,聚合直接拖垮集群。


3.2 文档数量对不上:doc_count 为什么不等于真实行数? #

很多初学者会用聚合结果去“对账”,例如:

  • 按状态聚合后,doc_count 总和 ≠ 索引文档数
  • 某些桶的数量明显偏少

3.2.1 常见原因 #

  1. 查询条件过滤了部分数据
  2. 时间范围与字段值不一致
  3. 嵌套字段未使用 nested 聚合
  4. 刷新(refresh)尚未发生

其中,第 3 点尤其常见。

如果字段是 nested 类型,却使用了普通聚合方式:

  • Easysearch 统计的是“父文档”
  • 而不是嵌套对象本身

结果自然会“看起来不对”。


3.3 Cardinality(去重统计):为什么永远不是精确值? #

cardinality 聚合用于统计去重后的数量,例如:

  • UV(独立用户数)
  • 去重 IP 数

它的特点只有一个:快,但不保证绝对精确

3.3.1 为什么? #

因为 cardinality 使用的是概率算法(如 HyperLogLog):

  • 内存占用固定
  • 计算速度快
  • 允许极小误差,默认误差率通常在 5% 左右(取决于配置)

这种设计非常适合趋势分析,但并不适合财务级别对账

如果你发现:

  • 不同时间查询结果略有波动
  • 与数据库精确统计存在小差异

这通常是正常现象

如果您想提高去重计数的准确度,可以调高 precision_threshold 参数。该参数允许在增加内存消耗的前提下,提升基数估算的精度。当唯一值数量不超过 precision_threshold 时,Easysearch 可提供高度精确的近似结果;该参数最大可设置为约 40000,超过此数值的去重计数将转为估算,精度会有所下降。


3.4 浮点数聚合:avg / sum 为什么有小数误差? #

在做金额、时长等指标统计时,有些人会注意到:

  • avg 结果出现非常长的小数
  • 累加结果存在微小误差

这是浮点数计算的固有特性,并非 Easysearch 特有问题。

在分布式环境中:

  • 多分片分别计算
  • 多次合并中存在舍入误差

这类误差通常在业务可接受范围内。


四、如何判断“不对”到底是不是问题? #

一个非常实用的判断原则是:

先区分“统计口径不一致”和“计算误差”

可以从以下几个维度自查:

  1. 是否使用了正确的字段类型
  2. 是否涉及嵌套对象
  3. 是否使用了近似聚合(如 cardinality
  4. 是否存在时间窗口、刷新延迟
  5. 是否把 Easysearch 当成了“强一致数据库”
  6. Deleted Documents(已删除文档):在分片合并(Segment Merge)之前,已删除的文档仍然占用存储,且在某些底层的计数逻辑中可能产生微小干扰(虽然聚合通常会过滤掉它们,但在极高并发更新场景下会有瞬间差异)。

如果这些都明确了,80% 的“看起来不对”都会变得合理。


五、什么时候应该追求“绝对精确”? #

Easysearch 非常适合:

  • 运营分析
  • 趋势判断
  • 实时监控
  • 排行榜展示

并不适合

  • 财务结算
  • 强一致对账
  • 精确计费系统

一个常见的实践是:用 Easysearch 做分析,用数据库做结算, 各司其职,反而更稳定。


六、小结:理解近似,才能用好聚合 #

聚合结果“看起来不对”,往往不是写法错误,而是:

  • 没理解分布式计算的取舍
  • 没意识到近似算法的存在
  • 把分析引擎当成了事务系统

只要记住一句话:

Easysearch 聚合追求的是“可用、快速、趋势可信”,而不是“逐条精确”

你就能在使用聚合时,既放心,又不纠结。