Redis 命令及数据类型 -- Hyperloglog

摘要

Hyperloglog 数据类型

  • Redis HyperLogLog 是专门用于做基数统计的高级数据类型,核心优势是用极小的内存(固定约 12KB)就能统计海量数据的基数,误差率仅 0.81%,无需存储全部数据本身。

基数:指集合中不重复元素的数量(比如统计 UV,就是不重复访客的数量)。

  • Redis Hyperloglog 并非独立数据类型,而是基于 String 类型的位操作扩展

核心使用方式(3个核心命令)

  • HyperLogLog 命令极简,只有 3 个核心操作

PFADD

  • 向 HyperLogLog 中添加1个或多个元素,成功添加(元素未存在)返回1,否则返回0。

1
PFADD key [element [element ...]]

PFCOUNT

  • 统计单个/多个 HyperLogLog 的基数(去重总数),多 key 传入时会计算所有 key 的并集基数。

1
PFCOUNT key [key ...]

PFMERGE

  • 将多个源 HyperLogLog 合并为1个目标 HyperLogLog,适用于跨维度汇总统计(比如合并今日、昨日的 UV 得到两日总 UV)。

1
PFMERGE destkey [sourcekey [sourcekey ...]]

实操示例

示例1:单 key 基础统计(统计网站 UV)

1
2
3
4
5
6
7
8
9
# 1. 模拟3个访客访问,其中用户A重复访问
127.0.0.1:6379> PFADD uv:20251218 userA userB userC
(integer) 1
127.0.0.1:6379> PFADD uv:20251218 userA
(integer) 0

# 2. 统计当日UV(去重后是3,忽略重复的userA)
127.0.0.1:6379> PFCOUNT uv:20251218
(integer) 3

示例2: 多 key 合并与汇总统计

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 分别统计12.17和12.18的UV
127.0.0.1:6379> PFADD uv:20251217 userA userD
(integer) 1
127.0.0.1:6379> PFADD uv:20251218 userA userB userC
(integer) 1

# 2. 合并两日UV到 uv:20251217_18
127.0.0.1:6379> PFMERGE uv:20251217_18 uv:20251217 uv:20251218
OK

# 3. 统计两日总UV(并集去重,结果为4:userA、B、C、D)
127.0.0.1:6379> PFCOUNT uv:20251217_18
(integer) 4

核心应用场景(精准落地场景)

  • HyperLogLog 只关注 “去重数量”,不关注“具体元素是谁”,适合以下高频场景,也是企业级常用方案:

  1. 网站/APP UV 统计:替代传统的 Set 存储(Set 存海量 UV 内存占用极高),单 key 仅 12KB,轻松统计百万/千万级 UV。

  2. 业务场景去重计数:比如统计单日/单月的独立支付用户数、独立下单用户数、独立点击商品的用户数。

  3. 海量数据去重统计:比如统计某接口的独立调用 IP 数、某直播间的独立观看人数、某广告的独立曝光数。

  4. 跨维度汇总统计:比如合并不同渠道(APP、小程序、H5)的独立访客数,得到全渠道总访客数。

关键注意事项(避坑重点)

  1. 不存储具体元素,仅存统计结果:无法像 Set 那样获取集合中的具体元素(比如无法通过 HyperLogLog 查到具体是哪些用户访问了网站),只关心“有多少个”,不关心“是谁”。

  2. 误差不可避免,可控不影响大部分场景:固定误差率 0.81%,数据量越大误差越稳定,UV、独立用户数等场景对精度要求不高,完全够用;若需 100% 精准(比如统计核心交易用户数),需用 Set 或 Hash 实现。

  3. 内存占用固定,与数据量无关:无论统计 10 个还是 1 亿个元素,单个 HyperLogLog 占用内存约 12KB,这是其核心优势,也是区别于 Set 的关键。

  4. 元素支持字符串类型:PFADD 传入的元素必须是字符串/字节类型,不支持其他数据类型(如数字、列表等,需手动转为字符串)。

  5. 过期时间支持:HyperLogLog 本身不自带过期机制,但可通过 EXPIRE key seconds 给其设置过期时间(比如 UV 统计按日过期,避免内存堆积)。

  6. PFADD 幂等性:重复添加同一元素,不会改变基数结果,也不会额外占用内存,可放心重复调用。

与 Set 统计基数的对比(选型参考)

对比维度 HyperLogLog Set
数据结构类型 基数统计结构 无序集合
内存占用 固定约 12KB,与数据量无关 随元素数量线性增长,海量数据内存占用极高
统计结果精度 非精准,标准误差约 0.81% 100% 精准
是否支持获取具体元素 不支持 支持(如 SMEMBERS
是否支持去重 支持(基数去重) 支持(元素级去重)
统计性能 极快(固定计算逻辑,O(1)) 数据量越大,统计与遍历成本越高
适合数据规模 超大规模(百万 / 千万 / 亿级) 中小规模集合
常见使用场景 UV / DAU 统计、独立 IP 数、访问用户数 好友列表、标签集合、关注列表
是否可做集合运算 不支持 支持(SUNION / SINTER / SDIFF
是否可序列化/持久化 可(Redis 内部结构)
选型结论 低成本 + 海量数据 + 可接受误差的基数统计 精准统计 + 需要元素明细的场景

HyperLogLog 命令

  • SpringBoot 的 StringRedisTemplate.opsForHyperLogLog() 中 HyperLogLog 数据类型 的操作方法与 Redis 原生命令的对应关系如下:

注意这里一定要用 StringRedisTemplate 来操作 HyperLogLog

方法功能 方法 Redis 原始命令 备注 / 使用建议
添加元素 Long add(K key, V... values) PFADD key element [element ...] 返回 1 表示 HLL 结构发生变化
获取基数(去重数) Long size(K... keys) PFCOUNT key [key ...] 支持多 key 合并统计
合并 HLL Long union(K destination, K... sourceKeys) PFMERGE destkey sourcekey [sourcekey ...] 合并后写入 destkey
删除 HLL void delete(K key) DEL key 直接删除整个 HLL