统计计数和HyperLogLog数据类型


最近还是想好好打下基础,先看看redis,参考gitbook上面的《Redis开发运维实践指南》。看到HyperLogLog类型,有点懵逼,看了书里面推荐的文章,大概是一知半解了,mark一下。

简介

HyperLogLog是一种可以实现计数问题的方案或者说算法,redis实现了HyperLogLog,把HyperLogLog作为一种数据类型/结构。

解决问题:计数问题(计算集合的基数)

优点:占用空间小,1.5K可以对十亿级的数据进行计数(2%的误差)

缺点:基于hash的统计计数(我这么翻译的,英文叫probabilistic counters),有误差

 

计数问题

给定一个值空间S,有N个元素,给定一个行为,会决定一个/批元素是否进入一个该空间的子集Sub,我们需要计算出经过任意次行为后这个子集Sub中包含的元素个数C。

PS:我也不知道原始的问题是怎么定义,自己瞎比定义一下

 

计数方案

方案一:使用hash表或者集合(set)

N个元素,需要k=ceil(log2N)位来表达,存满N个元素,需要kN位,量级是0(kN)。将问题具体一下,一个系统有1亿用户,每个用户的标识至少是27bit,就是4B。至少需要4B*227 = 229B≈500M。同理10亿用户约为4B*230=4G。考虑到大多数系统的用户id,都是留了很多冗余空间的,再加上,数据结构本身占用的空间,一个Set或者Hash表保存十亿用户id占用的空间往往是几十G。

优点:计数精确。

缺点:占用空间较大。数据量大时,几乎不可行。

 

方案二:使用bitmap

使用bitmap,需要一个合适的hash函数配合。可以大幅降低占用空间,但是十亿数据,大概也要百M(10亿/8B≈128M)级别的空间。

优化:使用稀疏bitmap,可以使占用的空间随C的大小变化。

优点:十亿数据占用空间在0M~100M间波动,随C越大,占用空间越大。

    方便进行位操作

缺点:计数量大时还是占用了100M空间,而且依赖Hash算法,存在少量冲突。

 

方案三:使用统计计数

通过以上描述,计数问题的难点也差不多说明白了。这个问题在很多应用中都存在,比如点赞统计,比如点击(观看、访问)XX的用户数统计等等。

幸运的是,我们有统计计数方案,来作为以上方案的补充。我们回到一道小学数学题。

问:一个池塘里有很多鱼,随机抓100条,打上标记,放回去。再随机捞100条,有N条带标记的鱼,请问池塘里大概有多少条鱼。

解:100/x = n/100,x=100*100/n。

如果有一种隐射方式将N个数随机映射到M个数上(M<<N),我们随机把这C个数也隐射一下,数量记为MC,C≈N*MC/M。由于M远小于N,所以这个隐射肯定是无法做到1对1映射,所以肯定有误差。

 

小结

本质上,三种方案都使用了映射。方案一将一个数据映射成了log2Nbit,方案二将一条数据映射为了1bit,而方案三将多条数据映射为了1bit。亿级数据情况下,三种方案的比较如下。

  Hash/Set Bitmap

probabilistic counters

空间 G级(10G) M级(100M) K级(10K)
误差 0 极低(可忽略) 百分位
可行性 几乎不可行 可行 条件可行

条件可行意为,是否能接受百分位的误差,如果接受就可行,不接受就不可行。

 

统计计数probabilistic counters

上面提到统计计数方案,只是用了一种最简单的统计方法,是本人自行理解的一种方案。大神们肯定有更优化的方案,主要有线性统计计数(Linear Probabilistic Counter)、HyperLogLog。参考http://highscalability.com/blog/2012/4/5/big-data-counting-how-to-count-a-billion-distinct-objects-us.html。

当然了,如果有兴趣,可以翻一翻相关的文章,应该会有收获。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM