HyperLogLog使用及原理

目录

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

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值