精确去重与近似去重
统计独立访客这类去重需求有两条路线:Set 精确记录每个成员,内存随基数线性增长;HyperLogLog 用固定约 12KB 的空间做概率估算,标准误差约 0.81%。选择依据不是哪个更先进,而是业务能否接受误差,以及是否需要在事后列出具体成员。
基本信息
| 适用平台 | Redis 2.8.9+ 支持 HyperLogLog |
|---|---|
| Set 命令 | SADD、SCARD、SUNIONSTORE |
| HLL 命令 | PFADD、PFCOUNT、PFMERGE |
| HLL 空间 | 每键不超过约 12KB(小基数用稀疏编码更省) |
| HLL 误差 | 标准误差约 0.81% |
典型使用场景
- 日活、周活、月活统计:基数大且只关心数字,适合 HLL
- 需要列出具体用户名单的场景:抽奖名单、白名单校验,必须用 Set
- 多天数据合并出周期去重值:HLL 的 PFMERGE 比多个 Set 求并集省得多
- 精确对账场景:金额相关的去重统计不能用近似值
- 接口级去重与限流:Set 可以直接判断成员是否存在
精确与近似两种写法
精确与近似两种写法
# 精确:集合成员可列举,内存随基数增长
SADD uv:day:20261012 uid1 uid2 uid3
SISMEMBER uv:day:20261012 uid2 # 1:可判断成员是否存在
SCARD uv:day:20261012 # 3:精确计数
# 近似:固定空间,只给数字
PFADD hll:uv:20261012 uid1 uid2 uid3
PFCOUNT hll:uv:20261012 # 约 3
# 合并多天得到一个周期去重值
PFMERGE hll:uv:week hll:uv:20261011 hll:uv:20261012
PFCOUNT hll:uv:week
# Set 的合并需要显式生成结果键
SUNIONSTORE uv:week 3 uv:day:20261011 uv:day:20261012选型对照
| 维度 | Set | HyperLogLog |
|---|---|---|
| 精确性 | 精确 | 约 0.81% 标准误差 |
| 内存占用 | 随基数线性增长 | 每键固定约 12KB 上限 |
| 能否列出成员 | 可以 | 不能,只能给基数 |
| 能否判断元素存在 | 可以(SISMEMBER) | 不能 |
| 合并方式 | SUNIONSTORE | PFMERGE |
| 删除单个元素 | 可以(SREM) | 不支持 |
小基数用 HLL 反而更贵:稀疏编码虽省空间,但固定开销仍高于几个成员的 Set,量级没上来之前用 Set 更直观。
HLL 不支持删除单个元素:一旦需要「移除某个用户」就必须整键重算,因此它对数据修正类需求很不友好,选型前先确认是否有删改诉求。
PFCOUNT 同时传入多个键时会先做内部临时合并再计数,开销高于单键查询:周期性报表建议先用 PFMERGE 落一个汇总键,日常查询只读这个汇总键,避免每次报表都重新合并。