Redis 提供了 HyperLogLog 数据结构就是 用来解决这种统计问题的。HyperLogLog 提供不精确的去重计数方案,虽然不 精确但是也不是非常不精确,标准误差是 0.81%,这样的精确度已经可以满足上 面的 UV 统计需求了。
使用方式
HyperLogLog 提供了两个指令 pfadd 和 pfcount,根据字面意义很好理解,一 个是增加计数,一个是获取计数。
pfadd 用法和 set 集合的 sadd 是一样的,来 一个用户 ID,就将用户 ID 塞进去就是。
pfcount 和 scard 用法是一样的,直接 获取计数值。
127.0.0.1:6379> pfadd codehole user1
(integer) 1
127.0.0.1:6379> pfcount codehole
(integer) 1
127.0.0.1:6379> pfadd codehole user2
(integer) 1
127.0.0.1:6379> pfcount codehole
(integer) 2
127.0.0.1:6379> pfadd codehole user3
(integer) 1
127.0.0.1:6379> pfcount codehole
(integer) 3
127.0.0.1:6379> pfadd codehole user4
(integer) 1
127.0.0.1:6379> pfcount codehole
(integer) 4
127.0.0.1:6379> pfadd codehole user5
(integer) 1
127.0.0.1:6379> pfcount codehole
(integer) 5
127.0.0.1:6379> pfadd codehole user6
(integer) 1
127.0.0.1:6379> pfcount codehole
(integer) 6
127.0.0.1:6379> pfadd codehole user7 user8 user9 user10
(integer) 1
127.0.0.1:6379> pfcount codehole
(integer) 10
注: 当数据量大的时候, 用户数值会有偏差!!!!!!!!!!!!!!!!!!!!!!
pfmerge,用于将多个 pf 计数值累加在一起形成一个新的 pf 值。
注意事项
HyperLogLog 这个数据结构不是免费的,不是说使用这个数据结构要花钱,它 需要占据一定 12k 的存储空间,
所以它不适合统计单个用户相关的数据。
如果 你的用户上亿,可以算算,这个空间成本是非常惊人的。但是相比 set 存储方 案,
HyperLogLog 所使用的空间那真是可以使用千斤对比四两来形容了。
不过你也不必过于当心,因为 Redis 对 HyperLogLog 的存储进行了优化,在计 数比较小时,
它的存储空间采用稀疏矩阵存储,空间占用很小,仅仅在计数慢慢 变大,
稀疏矩阵占用空间渐渐超过了阈值时才会一次性转变成稠密矩阵,才会占 用 12k 的空间。
Hyperloglog 实现原理
这张图的意思是,给定一系列的随机整数,我们记录下低位连续零位的最大长 度 K,
这个参数就是图中的 maxbit, 通过这个 K 值可以估算出随机数的数量 N。
具体算法,太复杂,有时间再研究..........