hyperloglog
一、核心思想
HLL 基于两个关键观察:
均匀分布的哈希值:好的哈希函数能将输入均匀映射到二进制串
前导零的数量:可以反映基数大小(基数越大,出现更多前导零的概率越低)
二、计算步骤详解
- 初始化阶段
创建 m 个计数器桶(Redis 默认 m=16384)
每个桶初始值为 0
- 添加元素过程(PFADD)
对于每个元素:
计算哈希值:
使用 64 位哈希函数(如 MurmurHash64)
例如元素 "user123" → 哈希值 01100010...(64位)
确定桶索引:
取哈希值前 14 位(因为 2^14 = 16384)
桶索引 = hash[0:13](转为十进制,范围 0-16383)
计算前导零数量:
取哈希值剩余 50 位(hash[14:63])
计算从右到左第一个 1 出现的位置
例如 ...00010010 → 前导零数量 ρ = 3
更新桶值:
比较当前桶值和 ρ
如果 ρ > 当前桶值:桶[索引] = ρ
- 估算基数(PFCOUNT)
计算调和平均数:
Z = ∑(2^(-桶值)) # 对所有桶的2的负桶值次方求和
α = 0.7213/(1 + 1.079/m) # 修正因子(m=桶数)
E = α * m² / Z # 初步估计值
修正偏差:
小范围修正(当 E < 5m/2):
统计空桶数量 V
如果 V ≠ 0: E = m * log(m/V)
大范围修正(当 E > 2^32/30):
E = -2^32 * log(1 - E/2^32)
返回整数值:
最终结果取整:floor(E + 0.5)
假设你有 4 个桶(m=4),记录如下:
M = [3, 4, 3, 5]
→ 转换为:2^(-M[i]) = [1/8, 1/16, 1/8, 1/32]
→ 和 = 1/8 + 1/16 + 1/8 + 1/32 = 0.390625
→ 倒数 = 2.56
→ m² = 16
→ α₄ ≈ 0.673
→ E = 0.673 * 16 * 2.56 ≈ 27.5
\(\alpha_m \approx \frac{0.7213}{1 + \frac{1.079}{m}}\)

浙公网安备 33010602011771号