海量数据的非精确去重利器——从HyperLogLog到布谷鸟过滤器

背景

非精确:牺牲一定准确度换取空间效率和时间效率。

  • 统计网站的UV(独立访客数):当用户数量非常多时,比如几千万甚至上亿,那么使用普通的哈希表去重将会占用可怕的巨大内存空间。引用吴军博士的《数学之美》中所言,这是因为哈希表的空间效率不够高,哈希表的存储效率一般只有50%。如果用哈希表存储一亿个userId,每个userId对应 8bytes,那么一个id就需要占用16bytes。因此一亿个userId占用1.6GB,如果存储几十亿个userId则需要上百GB的内存。而内存又是非常宝贵的资源,单单为了统计普通页面的UV就需要这么多内存无疑非常浪费。并且在实际中我们也不需要非常精确的数据,不需要精确到个位数。

[初试牛刀]HyperLogLog

HyperLogLog 是一种基数估算算法。也就是估算在一批数据中,不重复元素的个数有多少。基数估计的结果是一个带有 0.81% 标准误差的近似值。是可接受的范围。思路是通过给定 n 个的元素集合,记录集合中数字的比特串第一个1出现位置的最大值k,也可以理解为统计二进制低位连续为零(前导零)的最大个数。通过k值可以估算集合中不重复元素的数量N,N近似等于 2^k。
在这里插入图片描述
下面编写一个实验来观察一下K和N的关系:
在这里插入图片描述
可以发现K和N的对数之间存在显著的线性相关性(输出分别是 随机数数量N,N的对数,K值):
在这里插入图片描述
使用了SPSS分析,可以看的更清晰
在这里插入图片描述
但是这种预估方法存在较大误差,为了改善误差情况,HyperLogLog中引入分桶平均的概念,计算 m 个桶(多个BitKeeper)的调和平均值。
Redis 中 HyperLogLog 一共分了 2^14 个桶,也就是 16384 个桶。每个桶中是一个 6 bit 的数组,如下图所示。
在这里插入图片描述
HyperLogLog 将上文所说的 64 位比特串的低 14 位单独拿出,它的值就对应桶的序号,然后将剩下 50 位中第一次出现 1 的位置值设置到桶中。50位中出现1的位置值最大为50,所以每个桶中的 6 位数组正好可以表示该值。

在设置前,要设置进桶的值是否大于桶中的旧值,如果大于才进行设置,否则不进行设置。
在这里插入图片描述
其实Redis也对HyperLogLog存储进行了优化,当计数比较少时,使用的是稀疏矩阵进行存储,占用的空间很小,当计数逐渐变大,超过了稀疏矩阵的阈值时,才会转变成稠密矩阵,占用(2^14)*6/8=12KB的空间,却可以记录2^50个不同的64位长度的数值。

使用

pfadd 添加

时间复杂度O(1)

> pfadd m1 1 2 3 4 1 2 3 2 2 2 2
(integer) 1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值