前言
我们都知道 Redis 提供了丰富的数据类型,特殊的有四种:BitMap、HyperLogLog、Geospatial、Stream。
今天我们就来详细的聊聊 Redis 这四种特殊的数据类型之一 HyperLogLog
;
应用场景:海量数据基数统计的场景,比如百万级网页 UV 计数等;
概述简介
Redis HyperLogLog
是 Redis 2.8.9 版本新增的数据类型,是一种用于「统计基数」的数据集合类型,基数统计就是指统计一个集合中不重复的元素个数。但要注意,HyperLogLog
是统计规则是基于概率完成的,不是非常准确,标准误算率是 0.81%。
所以,简单来说 HyperLogLog
提供不精确的去重计数。
HyperLogLog
的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的内存空间总是固定的、并且是很小的。
在 Redis 里面,每个 HyperLogLog
键只需要花费 12 KB 内存,就可以计算接近 264 个不同元素的基数,和元素越多就越耗费内存的 Set
和 Hash
类型相比,HyperLogLog
就非常节省空间。
这什么概念?举个例子给大家对比一下。
用 Java 语言来说,一般 long
类型占用 8 字节,而 1 字节有 8 位,即:1 byte = 8 bit,即 long 数据类型最大可以表示的数是:263-1。对应上面的264个数,假设此时有263-1这么多个数,从 0 ~ 263-1,按照 long
以及1k = 1024 字节的规则来计算内存总数,就是:((2^63-1) * 8/1024)K
,这是很庞大的一个数,存储空间远远超过12k,而 HyperLogLog
却可以用 12K 就能统计完。
内部实现
HyperLogLog
的实现涉及到很多数学问题,太费脑子了,如果你想了解一下,可以看看这个:HyperLogLog (opens new window)。
常见命令
HyperLogLog
命令很少,就三个。
# 添加指定元素到 HyperLogLog 中
# PFADD key [element [element ...]]
127.0.0.1:6379> PFADD mykey1 a b c d e f g h i j
(integer) 1
# 返回给定 HyperLogLog 的基数估算值。
# PFCOUNT key [key ...]
127.0.0.1:6379> PFCOUNT mykey1
(integer) 10
# 将多个 HyperLogLog 合并为一个 HyperLogLog
# PFMERGE destkey sourcekey [sourcekey ...]
127.0.0.1:6379> PFADD mykey2 i j z x c v b n m
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 9
127.0.0.1:6379> PFMERGE mykey3 mykey1 mykey2
OK
127.0.0.1:6379> PFCOUNT mykey3
(integer) 15
应用场景
百万级网页 UV 计数
Redis HyperLogLog
优势在于只需要花费 12 KB 内存,就可以计算接近 264 个元素的基数,和元素越多就越耗费内存的 Set
和 Hash
类型相比,HyperLogLog
就非常节省空间。
所以,非常适合统计百万级以上的网页 UV 的场景。
在统计 UV 时,你可以用 PFADD 命令(用于向 HyperLogLog
中添加新元素)把访问页面的每个用户都添加到 HyperLogLog
中。
127.0.0.1:6379> PFADD page1:uv user1 user2 user3 user4 user5
接下来,就可以用 PFCOUNT 命令直接获得 page1 的 UV 值了,这个命令的作用就是返回 HyperLogLog
的统计结果。
127.0.0.1:6379> PFCOUNT page1:uv
不过,有一点需要你注意一下,HyperLogLog
的统计规则是基于概率完成的,所以它给出的统计结果是有一定误差的,标准误算率是 0.81%。
这也就意味着,你使用 HyperLogLog
统计的 UV 是 100 万,但实际的 UV 可能是 101 万。虽然误差率不算大,但是,如果你需要精确统计结果的话,最好还是继续用 Set
或 Hash
类型。
后记
Redis 四大特殊数据类型之一的 HyperLogLog
就先讲到这里了,后续还会有其他类型的讲解呢,敬请关注!
参考资料:
- 《Redis 核心技术与实战》
- 《Redis 设计与实现》
- Redis 常见数据类型和应用场景