一句话定义
HyperLogLog(简称 HLL)是一种概率型基数估计算法:用极小的内存,估算一个集合里有多少个不同的元素(基数,cardinality),而不需要把元素本身存下来。
原理:从抛硬币说起
假设你一直抛硬币,记录“连续出现正面”的最长纪录是 10 次。你会怎么反推自己大概抛了多少次?答案是量级上的 2^10 次——因为连出 10 个正面本身就是小概率事件,抛得次数不够多,根本遇不上。
HyperLogLog 借的就是这个直觉。它先把每个元素哈希(hash)成一串随机的二进制位,再分两步用:
- 一部分位当作“桶号”,把元素分到 2^p 个桶里;
- 剩下的位用来数“前导零”有多长(从最高位起连续 0 的个数),每个桶只记录自己见过的最长纪录。
前导零越长,说明这种“稀有事件”越罕见,也就间接说明见过的元素越多。最后把所有桶的读数做一次调和平均再乘系数,就得到基数估计。用调和平均而不是普通平均,是为了让个别桶的极端值不至于把结果整体拉偏。
它和几个容易混淆的结构
| 结构 | 回答的问题 | 内存开销 | 能否列出元素 |
|---|---|---|---|
| 精确去重(HashSet) | 到底有多少个不同元素 | 与基数成正比 | 能 |
| 布隆过滤器(Bloom filter) | 某元素在不在集合里 | 固定,通常几 KB 起 | 不能 |
| HyperLogLog | 大约有多少个不同元素 | 固定,几 KB | 不能 |
| Count-Min Sketch | 某元素出现了多少次 | 固定 | 不能 |
一句话区分:布隆过滤器答“在不在”,Count-Min Sketch 答“几次”,HyperLogLog 答“有多少种”。它的相对标准误差约为 1.04/√m(m 为桶数),桶数越多越准、内存也越多;对极小的基数会有明显偏差,所以实现里通常带小基数修正。
对从业者的意义
在数据量动辄上亿的场景里,精确去重的内存开销会直接压垮机器,而 HyperLogLog 的内存是常数级别的:精度够用的配置下通常只占几 KB 到十几 KB,就能把误差控制在 1% 上下。典型用途包括日活/UV 统计、埋点与日志去重、推荐系统曝光去重、语料里不同词或不同用户规模的估计等。Redis 等常见组件都内置了它(对应命令如 PFADD、PFCOUNT),具体内存与误差以官方文档为准。
用的时候记住三条边界:它只给数量、不给成员名单;两个 HLL 可以合并求并集(逐桶取最大值即可),但求交集不直接支持;结果的误差是概率性的,不适合当账目一类必须精确的数字。
