当前位置: 首页 > 工具软件 > HyperLogLog > 使用案例 >

HyperLogLog使用及原理

林和煦
2023-12-01

目录

1.使用方法

2.注意事项

3.实现原理


在介绍HyperLogLog之前,我们先思考一个常见的业务问题:如果开发一个大型网站,要记录每个网页每天的UV数据,我们应该如何实现呢?

如果统计PV那非常容易,给每个网页一个独立的Redis计数器就可以了,这个计数器的key后缀加上当天的日期。这样来一个请求,incrby一次,最终就可以统计出所有的PV数据。但是UV不一样,它要去重,也许我们可以想到一个简单的方案,为每个网页创建一个set集合来存储当天访问过此页面的用户ID。但是如果我们的页面非常巨大,比如一个爆款页面几千万的UV,需要一个很大的set集合来统计,这样就非常浪费空间了。

Redis提供了HyperLogLog数据结构用来解决这种统计问题。HyperLogLog提供了不准确的去重计数功能,虽然不准确但也不是非常不准确,标准误差为0.81%,这样的精确度已经可以满足UV统计需求了。

1.使用方法

HyperLogLog提供了两个指令pfadd(增加计数)和pfcount(获取计数)。pfadd用法和set集合的sadd是一样的,pfcount则类似于scard。实例代码如下:

MyRedis:0>pfadd uv user1
1
MyRedis:0>pfadd uv user2
1
MyRedis:0>pfadd uv user3
1
MyRedis:0>pfcount uv
3
MyRedis:0>pfadd uv user3
0
MyRedis:0>pfcount uv
3
MyRedis:0>pfadd uv user4 user5 user5
1
MyRedis:0>pfcount uv
5

目前为止,UV统计还是非常准确的。下面我们使用脚本,插入更多的数据,看看能否继续准确:

import my_tools

client = my_tools.get_redis()
for i in range(1000):
    client.pfadd('uv2', 'user%d' % i)
    total = client.pfcount('uv2')
    if total != i + 1:
        print(total, i + 1)
        break

输出结果为:
99 100

从输出结果可以看出,当我们输入第100个元素的时候,结果出现了不一致。继续增加数据到2W,看一下差距有多大:

import my_tools

client = my_tools.get_redis()
for i in range(20000):
    client.pfadd('uv4', 'user%d' % i)

total = client.pfcount('uv4')
print(total, 20000)


输出结果为:
20082 20000

差了82个,误差率为0.41%,对于UV的统计需求来说,误差率还不算太高。

HyperLogLog除了pfadd和pfcount之外,还提供了pfmerge指令,用于将多个pf的计数值累加在一起形成一个新的pf值。比如我们的网站中有多个页面,需要将这几个页面的数据进行合并,其中页面的UV访问量也需要合并,那这个时候就需要使用pfmerge命令了。

2.注意事项

HyperLogLog在计数比较小时,它的存储空间是采用稀疏矩阵空间占用较小,当计数慢慢变大的时候,稀疏矩阵占用的空间逐渐超过了阈值时会一次性转变为稠密矩阵,占用空间大概是12K。由于HyperLogLog占用的空间相对比较大,所以不适合统计单个用户相关的数据。

3.实现原理

实现原理参考代码:https://juejin.im/post/6844903785744056333

 类似资料: