我们可能会遇到这样一个统计场景:基数统计。
基数统计就是指统计一个集合中不重复的元素个数。比如说统计网页的 UV(访问用户量)。
网页 UV 的统计有个独特的地方,就是需要去重,一个用户一天内的多次访问只能算作一次。在 Redis 的集合类型中,Set 类型默认支持去重,所以看到有去重需求时,我们可能第一时间就会想到用 Set 类型。
但是!如果一个网站用户数非常多,使用set类型来记录用户数,会造成大量的内存浪费。而HyperLogLog可以很好的满足这个要求。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
PFADD命令,向指定的HyperLogLog添加指定的元素。
基本语法:
PFADD key element [element ...]
基本用法:
127.0.0.1:6379> pfadd pfkey1 a b c d e f g h
(integer) 1
返回HyperLogLog在键处观察到的集合的近似基数。
基本语法:
PFCOUNT key [key ...]
基本用法:
127.0.0.1:6379> pfcount pfkey1
(integer) 8
# 我们多设置几个key
127.0.0.1:6379> pfadd pfkey2 i j k
(integer) 1
# pfcount也可以计算多个key的总和
127.0.0.1:6379> pfcount pfkey1 pfkey2
(integer) 11
# 计算总数时,会进行去重
127.0.0.1:6379> pfadd pfkey3 j k l
(integer) 1
127.0.0.1:6379> pfcount pfkey1 pfkey2 pfkey3
(integer) 12
# 对单个key也会进行去重
127.0.0.1:6379> pfadd pfkey4 a b a c
(integer) 1
127.0.0.1:6379> pfcount pfkey4
(integer) 3
将N个不同的hyperlogglog合并为一个。
基本语法:
PFMERGE destkey sourcekey [sourcekey ...]
基本用法:
# 合并并去重
127.0.0.1:6379> pfmerge mergekey pfkey1 pfkey2 pfkey3 pfkey4
OK
127.0.0.1:6379> pfcount mergekey
(integer) 12
HyperLogLog 的统计规则是基于概率完成的,所以它给出的统计结果是有一定误差的,标准误算率是 0.81%。这也就意味着,你使用 HyperLogLog 统计的 UV 是 100 万,但实际的 UV 可能是 101 万。虽然误差率不算大,但是,如果你需要精确统计结果的话,最好还是继续用 Set 或 Hash 类型。