如何用hll()与tdigest()确保全局与日度分层分位数结果一致?
KQL分位数计算一致性问题及hll/tdigest正确用法
需求说明
需要完成三类分位数计算,核心要求是基于日度预计算的分布信息再聚合得到的全局分位数,与直接计算的全局分位数结果完全一致:
- 直接计算全日期范围的全局分位数
- 按日期维度计算每日的分布摘要信息
- 基于每日的分布摘要聚合,计算全局分位数,结果需与第一种方式一致
当前问题
直接先计算日度中位数,再对这些中位数求全局中位数,结果与直接全局分位数差异明显(示例中直接全局中位数为40,二次计算的中位数为35)。这是因为仅保留日度中位数丢失了原始数据的分布细节,无法还原全局完整分布。
正确解决方案:使用tdigest()合并分布信息
tdigest()是KQL中用于存储数值分布的近似数据结构,支持合并操作——可以先按日度生成每个分组的tdigest,再合并所有tdigest得到全局分布,最后计算分位数,结果与直接全局计算一致。
示例代码:基于tdigest实现一致性分位数计算
let MySourceTable = datatable(col1:int, col2:int, Value:int, EventUTCDateTime:datetime) [ 1,2,10,'2022-01-01 01:00:01', 1,2,20,'2022-01-01 02:01:01', 1,2,15,'2022-01-02 03:05:01', 1,2,40,'2022-01-03 01:30:01', 1,2,20,'2022-01-03 02:30:01', 1,2,50,'2022-01-04 07:30:01', 1,2,70,'2022-01-05 06:30:01', 1,2,45,'2022-01-05 07:30:01', 1,2,90,'2022-01-05 07:30:01', 1,2,40,'2022-01-06 07:30:01' ]; -- 1. 直接计算全局中位数 MySourceTable | summarize GlobalMedian = percentile(Value, 50) -- 2. 按日生成tdigest,再合并计算全局中位数(结果与上面一致) MySourceTable | extend EventUTCDate = bin(EventUTCDateTime, 1d) | summarize daily_dist = tdigest(Value) by col1, col2, EventUTCDate | summarize global_dist = merge_tdigests(daily_dist) | summarize GlobalMedian_FromDailyTDigest = percentile_tdigest(global_dist, 50)
代码说明
tdigest(Value):为每日的Value列生成压缩的分布摘要,保留分位数计算所需的核心信息merge_tdigests(daily_dist):将所有日度的tdigest合并为一个全局分布摘要percentile_tdigest(global_dist, 50):基于合并后的全局tdigest计算中位数,结果与直接全局计算完全一致
hll()的适用场景说明
hll()是用于基数估计(统计唯一值数量)的近似数据结构,不适合分位数计算。如果你的场景涉及唯一值计数的分层聚合,可以用hll()+dcount_hll(),但分位数场景必须使用tdigest()系列函数。
内容的提问来源于stack exchange,提问作者Brahmaiah Takkellapati
相关产品推荐
相关产品推荐

