hyperloglog

一、核心思想

HLL 基于两个关键观察:

均匀分布的哈希值:好的哈希函数能将输入均匀映射到二进制串

前导零的数量:可以反映基数大小(基数越大,出现更多前导零的概率越低)

二、计算步骤详解

  1. 初始化阶段
    创建 m 个计数器桶(Redis 默认 m=16384)

每个桶初始值为 0

  1. 添加元素过程(PFADD)
    对于每个元素:
    计算哈希值:
    使用 64 位哈希函数(如 MurmurHash64)
    例如元素 "user123" → 哈希值 01100010...(64位)
    确定桶索引:
    取哈希值前 14 位(因为 2^14 = 16384)
    桶索引 = hash[0:13](转为十进制,范围 0-16383)
    计算前导零数量:
    取哈希值剩余 50 位(hash[14:63])
    计算从右到左第一个 1 出现的位置
    例如 ...00010010 → 前导零数量 ρ = 3
    更新桶值:
    比较当前桶值和 ρ

如果 ρ > 当前桶值:桶[索引] = ρ

  1. 估算基数(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}}\)

posted @ 2025-05-05 16:08  不报异常的空指针  阅读(23)  评论(0)    收藏  举报