代表性面试主题

如何用 HyperLogLog 近似估算海量数据的去重数量?

编程题中等
OfferCC 编辑团队发布 更新

题干

如何在只有几 KB 内存的情况下,实时估算数十亿条标识中的独立数量,并说明误差、分片合并和精确去重边界?

1. 题目

日志系统每天接收数十亿个用户标识,需要实时估算当天的独立用户数。内存预算只有几 KB,结果允许有小幅误差。请设计一个流式算法,并说明误差、合并多个分片的方法,以及它和精确去重的边界。

2. 约束与澄清

  • 输入是持续到达的标识流,要求单次遍历、固定内存。
  • 查询目标是一个时间窗口内的近似基数(distinct count)。
  • 假设哈希函数分布均匀且所有分片使用同一哈希算法、寄存器数量和编码。
  • 题目不要求删除元素;滑动窗口、过期和强一致精确值需要额外结构。

3. 核心思路

HyperLogLog(HLL)把哈希值拆成寄存器索引与剩余比特。设寄存器数量为 m = 2^p:前 p 位选择寄存器,剩余比特中从最高位开始连续零的长度加一记为 rho。每个寄存器只保存见过的最大 rho。

直觉是:某个寄存器观察到很长的前导零,说明样本空间中出现了更多不同元素。用所有寄存器的调和平均估计基数:

E = alpha_m * m^2 / sum(2^(-M[j]))

其中 M[j] 是第 j 个寄存器的值,alpha_m 是与寄存器数有关的校正常数。常用实现还会在小基数时使用线性计数修正,在极大值接近哈希空间上限时使用大范围修正。

4. 参考实现

下面的伪代码展示更新、估算和合并。真实实现应使用固定宽度整数、明确的哈希函数,并处理 rho 的上限。

text
init(p):
  m = 1 << p
  M = array(m, fill=0)

add(x):
  h = hash64(x)
  j = high_bits(h, p)
  w = remaining_bits(h, p)
  r = leading_zero_count(w) + 1
  M[j] = max(M[j], r)

estimate():
  z = sum over j of 2^(-M[j])
  e = alpha(m) * m * m / z
  if e <= small_range_threshold(m) and zero_registers(M) != 0:
    e = m * log(m / zero_registers(M))
  return large_range_correction_if_needed(e)

merge(other):
  require same p, hash function, and register encoding
  for j in 0..m-1:
    M[j] = max(M[j], other.M[j])

5. 复杂度与正确性

每个元素只做一次哈希、一次寄存器更新,时间复杂度是 O(1);空间复杂度是 O(m),与流中元素总数无关。标准 HLL 的相对标准误差约为 1.04 / sqrt(m):例如 m = 16,384 时约为 0.81%,这是概率保证意义上的估计误差,不是每次查询都严格落在固定区间。

寄存器更新取最大值,因此重复加入同一元素不会继续增大状态,满足幂等性。多个分片可以逐寄存器取最大值后合并,前提是哈希函数、p 和编码完全一致;否则统计分布不兼容,结果没有可靠含义。

6. 追问与陷阱

  • HLL 返回近似值,不能替代需要逐用户准确名单、审计或计费的精确集合。
  • 清空寄存器只能表示全新窗口。滑动窗口需要按时间分桶、多个 HLL 或可删除的变体,并处理桶边界和存储成本。
  • 哈希碰撞和输入分布偏差会影响估计;应选择质量稳定的 64 位或更宽哈希,并在系统边界统一实现。
  • 小基数时直接使用原始调和平均会有偏差,线性计数修正利用零寄存器数量降低偏差。

7. 延伸阅读

  • Redis 的 PFCOUNT 命令与 HyperLogLog 数据类型文档。
  • Snowflake 的 approximate cardinality 文档。
  • Meta Engineering 关于 Presto HyperLogLog 的介绍。

8. 面试评分点

能说明状态结构

候选人应说清楚 m = 2^p 个寄存器、索引和 rho 的来源,以及寄存器只保留最大值的原因。

能推导误差与修正

应给出 1.04 / sqrt(m) 的量级,解释小范围线性计数和大范围修正,并区分概率误差与精确保证。

能处理分布式合并

应指出合并是逐寄存器取最大值,并明确所有分片必须共享哈希函数、精度和编码。

能识别产品边界

应主动区分近似分析指标与精确名单、滑动窗口、删除和计费场景,说明这些需求为何需要额外设计。

公开来源

同类题目

资源

产品对比

每份对比均基于官方资料,并标注复核日期。

查看完整对比

相关面试工具

用 Screenshot 处理算法题

截图题目后,按顺序看约束、解法、代码、边界条件和复杂度。

查看工具