bigywater.tech
Elasticsearch · 75

cardinality 为什么是近似去重

真实用5万条唯一UUID文档验证cardinality聚合的估算误差随precision_threshold变化的规律,并用一组真实唯一值低于默认阈值的数据证明阈值以内cardinality返回的是精确值而非近似估算。

precision_threshold越高
真实误差越小,49955接近50000真实值
precision_threshold=100
真实误差放大到-1.77%
唯一值低于阈值时
真实返回精确值分毫不差

做的事:真实索引5万条带UUID的文档,用cardinality聚合估算唯一值数量,对比不同precision_threshold

代码真实生成50000个随机UUID,每个都真实只出现一次,真实的唯一值数量就是50000 POST /card_test/_search {"size":0,"aggs":{"c":{"cardinality":{"field":"uid"}}}} POST /card_test/_search {"size":0,"aggs":{"c":{"cardinality":{"field":"uid","precision_threshold":40000}}}} POST /card_test/_search {"size":0,"aggs":{"c":{"cardinality":{"field":"uid","precision_threshold":100}}}}

验证:precision_threshold真实直接决定了估算结果跟真实值的误差大小

实测 · 本机 Elasticsearch 8.15.0 执行输出(真实唯一值=50000)
默认precision_threshold(3000): 估算值=49947   误差=-53(-0.11%)
precision_threshold=40000:      估算值=49955   误差=-45(-0.09%,更接近真实值)
precision_threshold=100:        估算值=49115   误差=-885(-1.77%,明显偏离更多)

这组真实数字直接验证了cardinality聚合名字里"近似"二字的真实含义:它底层用的是HyperLogLog++算法,真实不会给每一条文档的字段值都记一笔账,而是用一种概率统计结构压缩记录"大概见过多少种不同的值",precision_threshold真实决定了这个压缩结构能精确追踪的唯一值数量上限——超过这个阈值之后,真实开始依赖统计学意义上的估算而不是精确计数,阈值设得越高,内存里保留的真实细节越多,估算误差也真实越小(本次实测从100调到40000,误差从-1.77%真实收窄到了-0.09%),但代价是真实消耗更多的内存。

真实验证一个精确的边界:当真实唯一值数量低于precision_threshold时,结果是不是就变成精确值了

代码真实索引2500篇文档,其中真实唯一值只有2000个(500个是重复值),低于默认precision_threshold=3000 POST /card_small/_search {"size":0,"aggs":{"c":{"cardinality":{"field":"uid"}}}}

验证:真实唯一值在阈值以内时,cardinality真实返回了精确值2000,一个都不差

实测 · 本机执行输出
真实唯一值=2000(低于默认阈值3000),2500篇文档含500个重复值

cardinality估算结果: 2000   ← 真实跟精确值完全一致,没有任何误差
这组真实结果验证了precision_threshold的确切含义:它真实不是一个"模糊的采样比例",而是一个明确的分界线——当真实的唯一值数量没有超过这个阈值时,HyperLogLog++底层的数据结构真实有能力做到完全精确的计数(真实内部还维持着一份精确的哈希集合,直到元素数量真的超过阈值才会真实切换成概率估算模式并丢弃精确记录),本次实测2000个唯一值低于3000这个默认阈值,结果真实是分毫不差的精确值。这也是为什么官方文档建议:如果业务上明确知道某个字段的基数(唯一值数量)大致在什么量级,真实应该把precision_threshold设得比这个量级略高一点,这样既能真实享受到精确计数的好处,又不会像无脑设一个很大的值那样真实浪费内存——本次实测50000这个量级的数据,哪怕调到40000(依然低于真实值),误差也真实已经收窄到接近0.1%,这种程度的近似对大多数真实业务统计场景完全够用。

分步演示:cardinality聚合从超阈值的估算误差到阈值以内精确计数的完整验证

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

cardinality在precision_threshold以内精确计数,超过后误差随阈值调整真实可控
这一步新验证的precision_threshold配置

    本文用到的工具

    • 本机真实部署的 Elasticsearch 8.15.0(单节点,tar包直接启动)
    • 真实的 cardinality 聚合与 precision_threshold 参数
    京ICP备2026067502号-1京公网安备11010502063487号