Elasticsearch Percentile百分位聚合计算返回错误结果求助
异常结果产生原因
- 核心原因1:Elasticsearch默认的
percentiles聚合使用TDigest近似算法计算分位值,并非100%精确计算。该算法通过聚类压缩数据点实现高性能、低内存占用的分位统计,天生存在计算误差,在数据量越小(比如你仅23条测试数据)的场景下,误差会越明显。 - 核心原因2:分位值本身就不需要是原始数据中存在的值。不管是精确计算还是近似计算,分位结果都是基于排序后数据点的插值得到的:比如75分位落在排序后两个相邻数据点之间时,会按权重计算出两个点之间的一个数值作为结果,这个值自然可能不存在于原始字段的存储值中。你看到的
100002.73249999998就是插值结果,末尾的超长小数是double类型浮点数计算的精度损耗,属于正常现象。 - 核心原因3:
missing参数的生效逻辑会直接改变计算样本集。你配置的missing: 300005.00会把所有缺失目标double字段的文档,统一以300005.00作为字段值加入分位计算,这个值远大于你现有数据的10万级数值,会改变总样本量、以及75分位对应的排序位置,如果你手算时没有把缺失字段的文档按300005纳入计算,手算结果和ES返回结果自然会不一致。
对应解决方法
- 如果你需要更高精度的近似分位结果:调整TDigest算法的
compression参数,默认值为100,参数值越大,算法保留的聚类中心点越多,计算精度越高,内存消耗也越高。对于你这种小数据量场景,把该值设置为200甚至更高,就能把误差控制在可忽略的范围,配置示例:
{ "aggs": { "p75_value": { "percentiles": { "field": "your_double_field", "percents": [75], "missing": 300005.00, "tdigest": { "compression": 500 } } } } }
- 如果你需要完全无近似的精确分位结果:对于小数据量场景,可以将
execution_hint设置为direct(适用于数据量低于1万的场景),该模式会直接读取所有匹配文档的字段值做全量排序后精确计算分位,没有近似误差,配置示例:
{ "aggs": { "p75_value": { "percentiles": { "field": "your_double_field", "percents": [75], "missing": 300005.00, "execution_hint": "direct" } } } }
- 校验手算逻辑:手算预期值时,需要把所有缺失字段的文档按你配置的300005.00纳入样本集,同时确认你使用的分位插值规则和ES一致——ES默认采用线性插值法计算分位点位置,和部分统计工具使用的其他分位计算规则(比如就近取整、加权规则不同)得到的结果会有差异。
内容的提问来源于stack exchange,提问作者Prabhu Lingappa A S
相关产品推荐
相关产品推荐

