超简单解释:Redis的HyperLogLog

10 阅读5分钟

什么是HyperLogLog?

HyperLogLog 是 Redis 提供的一种概率数据结构,专门用于估算海量数据中不同元素的数量。它用固定的12KB内存,就能估算最多184亿亿(2^64)个不同元素,误差率仅0.81%。

1. 格式

# 基础语法
PFADD key value1 value2 ...

# 示例
PFADD video:views:123 "user1" "user2" "user3"

2. 特点

  • 元素类型不限:value支持中文、英文、数字、长文本等任意类型
  • 理论容量极大:每个key最多估算约184亿亿个不同元素
  • 存储方式特殊:元素被哈希成64位二进制,不存储原始数据
  • 内存占用固定:每个key固定约12KB,与元素数量无关
  • 结果是估算值:基于概率算法,不是精确计数

简单的比喻

HyperLogLog就像

  • 看沙滩上的脚印估算来了多少人
  • 看停车场停了多少车估算商场客流量
  • 看朋友圈点赞头像数估算你的朋友数量

看具体命令怎么用

假设你是抖音,要统计某个视频,比如视频888,视频999的观看人数,

# 1. 记录用户观看(用户张三看了视频888)
PFADD video:views:888 "user_zhangsan"

# 2. 再记录几个用户(李四、王五)也看了视频888
PFADD video:views:888 "user_lisi"
PFADD video:views:888 "user_wangwu"
PFADD video:views:888 "user_zhangsan"  # 同一个人又看了一次

# 3. 问:这个视频有多少不同的人看过??
PFCOUNT video:views:888
# 返回:3 (user_lisi,user_wangwu各1次,user_zhangsan看了2次但只算1次)

# 4. 另一个视频999的数据
PFADD video:views:999 "user_zhangsan"
PFADD video:views:999 "user_999"

# 5. 问:视频888和999一共被多少不同的人看过?
PFMERGE total_views video:views:888 video:views:999
PFCOUNT total_views
# 返回:4(user_zhangsan,user_lisi,user_wangwu,user_999)

为什么要用HyperLogLog?

情况1:用普通方法(Set集合)

# 记录1亿用户观看
SADD video:views:888 "user1" "user2" ... "user100000000"
# 内存占用:约800MB!
# 统计:SCARD video:views:888 (精确)

# 问题:一个视频就占800MB,100个视频就80GB,太贵了!

情况2:用HyperLogLog

# 记录同样的1亿用户观看
PFADD video:views:888 "user1" "user2" ... "user100000000"
# 内存占用:永远只需要12KB!
# 统计:PFCOUNT video:views:888 (估算)

# 优势:1个视频12KB,100个视频也才1.2MB!

什么时候该用它?

✅ 适合用的场景:

  1. 网站统计UV(独立访客)

    • 每天有100万人访问,你只想知道大概人数
    • 不关心具体是谁访问了
  2. APP的日活用户

    • 想知道今天大概有多少人打开了APP
    • 差几百人的误差没关系
  3. 广告点击去重

    • 一个用户点了10次广告,只算1次有效点击
    • 广告主接受少量误差

❌ 不适合用的场景:

  1. 银行账户统计

    • 不能说"您账户大概有10000元,误差±81元"
  2. 选举投票统计

    • 不能说"候选人A大概得了10000票,误差±81票"
  3. 需要知道具体有哪些人的场景

    • 比如发优惠券给所有参与的用户

误差到底有多大?

# 例子:
PFADD mydata 几百万个用户ID...
PFCOUNT mydata

# 可能结果:
真实人数:1,000,000人
HyperLogLog返回:992,000 ~ 1,008,000人
误差率:0.81%

# 也就是说:
100万人 → 可能少算8100人或多算8100人
1000万人 → 可能少算8.1万人或多算8.1万人

实际应用对比

场景:统计公众号文章阅读人数

方法内存消耗精确度能否知道谁读了
记录所有用户ID很大(用户越多越大)100%精确可以,知道每个读者
HyperLogLog固定12KB约99.19%精确不能,只知道大概人数

一句话总结

HyperLogLog就是:

用很小的固定空间(12KB),快速估算超大数据集中有多少个不同的东西,牺牲一点精确度(0.81%误差),换来巨大的内存节省。

那么问题来了

为什么我刚刚举例的视频888,视频999的观看人数,pfcount之后得到的结果是精准的,并没有0.81%的误差?

这是理解HyperLogLog的关键点,数据量小的时候,HyperLogLog可能是准确的!

为什么小数据量时准确?

原因1:小数据时HyperLogLog会自动使用精确算法

  • Redis的HyperLogLog在数据量小时使用精确计数
  • 数据量超过某个阈值(约30000)才切换为概率估算
  • 这是优化策略,避免"大炮打蚊子"

原因2:0.81%是最大误差,不是每次都有误差

  • 误差是概率性的,不是固定的,好比投硬币,正面朝上的概率50%,不代表每投2回就有一回是正面朝上

记住这个选择:

  • 数据量大,只要大概数量,不关心具体是谁 → 用HyperLogLog

再看一个完整例子

# 假设你是微博,要统计热搜话题的阅读人数

# 方法1:精确统计(太占内存)
# 每个阅读用户都记录:user1, user2, user3...
# 1000万人阅读 → 可能需要几百MB内存

# 方法2:用HyperLogLog(省内存)
# 同样1000万人阅读 → 只需要12KB内存
# 结果:"这个话题大约有992万~1008万人阅读"

# 选择:
# - 如果是给广告商看数据 → 用HyperLogLog(可以接受误差)
# - 如果是给财务算钱 → 不能用HyperLogLog(必须精确)

HyperLogLog就是估算神器,专门解决"大概有多少个不同的东西"这个问题,特别省内存