HyperLogLog数据结构
提供一种不精确的去重技术方案,主要用于大型互联网网站每天的UV数量(每天统计每个页面的独立的去重访客);说是不精确,其实也没有那么不精确,官网说的误差是在1%左右,标准误差应在0.83%,基本也可以满足UV统计需求了。
通俗来说就是,HyperLogLog存储的是每个key中不重复元素的个数,使用者只需要来一个元素就往这个key中插入ID或者name都行,HyperLogLog会根据元素名称自己去重。
HyperLogLog的优点
如果以集合的方式存储的话,可以看出所占内存是HyperLogLog的5000多倍,至于为什么说HyperLogLog的内存是15k会在后面具体讲解。
HyperLogLog原理解析
HyperLogLog是基于概率论中的伯努利实验并结合了极大似然估算方式,并做了分桶优化;
伯努利实验
两个人抛硬币,假设反面是0,正面是1,一个人抛了两次就拿到了正面,那得到这个结果有0-1,1-0,1-1,0-0四种情形,同理,另外一个人可能抛了7次才得到一次正面,就是0000001,那么可以算出这个人抛到这个结果最多会有2的7次方次,那么肯定第二个人的数据更有说服力,所以伯努利实验就是取这些结果中最晚出现1(假设第n次)的那条数据(其他都不管),就能得到2的n次方。
调和平均算法
A工资1000,B工资10000,如果用普通平均算法,那么两个人的平均工资就是5500,无论距离A还是距离B都是很远的,调和平均算法就是2/(1/1000+1/10000),这样算下来是1800多,这样肯定是更合理一点。
分桶优化
一个人做实验的可信度不高,如果同时有很多人做实验那么最终的结果肯定可信度大得多;分桶的意义就在于每个桶得到自己的数,最后将这些数做调和平均算法即可。
本人的浅显理解
通过hash算法将一个元素转换成64bit的二进制,从低位到高位(从右往左)取14个数算在哪个桶(总共有2的14次方个桶-16384,算成10进制,是哪个数就是在哪个桶),然后剩下50位从低位到高位看第一个1出现在第几位,然后把这个几放到前14位算出来的桶里,如果桶里已经有值了就比大小,留下大的(用抛银币的思路来讲,数越大说明做的次数越多 0000001 第7次抛到正面,那做到这个结果按照伯努利算法最多做了2的7次方次实验,所以桶里面每个值N代表是2的N次方),因为剩下的只有50位,所以这个值最大也就50 所以桶里放一个6位的二进制就够了,最后用调和平均算法算出来总数 肯定有误差 但是误差在0.83%以内。桶数/1/(2的每一个桶里面数字次方)之和。
最后附上HyperLogLog所占内存的估值算法:
16384*6/8/1024 = 12k
16384就是分了2的14次方个桶,每个桶中存了个6位的二进制数据,一位二进制占1/8个字节,1K占1024个字节,所以就是(16384个桶*每个桶的二进制位数/8位二进制占1字节/1024个字节代表1K)。