基数估算
基数估算(Cardinality Estimation),也称为 count-distinct problem,一直是大数据领域的重要问题之一,顾名思义,基数估算就是为了估算在一批超级大的数据中,它的不重复元素有多少个。常见的基数估算算法包括Linear 、LogLog、HyperLogLog、HyperLogLog++、MinCount等。
HyperLogLog是什么?
HyperLogLog,是一种概率数据结构,简介HLL,算法来源于伯努利实验。
HyperLogLog使用概率算法来统计集合的近似基数,该算法来源于论文 《HyperLogLog the analysis of a near-optimal cardinality estimation algorithm》,是 LogLog 算法的升级版本,使用HyperLogLog算法,能够在数量级特别大的情况下占用很小的空间。HyperLogLog算法的去重计数方案并不精确,当然也不是特别不精确,标准误差只有0.81%。
动画演示
Sketch of the Day: HyperLogLog — Cornerstone of a Big Data Infrastructure
在这个DEMO中,作者对比了 LogLog 和 HyperLogLog 的区别和运行过程,有助于大家理解整个过程。其中 LogLog 与 HyperLogLog 的区别就在于,它们平均值的处理方式不一样,前者是使用算术平均值,后者是使用调和平均值。
什么是基数?
基数,我理解就是一个数据集中不重复的元素个数,也可以这样理解,基数就是对集合元素的计数。
伯努利实验?
伯努利试验是数学概率论中的一部分内容,它的典故来源于抛硬币。
伯努利试验(Bernoulli experiment)是在同样的条件下重复地、相互独立地进行的一种随机试验,其特点是该随机试验只有两种可能结果:发生或者不发生。假设该项试验独立重复地进行了n次,那么就称这一系列重复独立的随机试验为n重伯努利试验,或称为伯努利概型。
伯努利过程
硬币拥有正反两面,一次抛掷出现正反面的概率都是50%。假设一直抛硬币,直到它出现正面为止,我们记录为一次完整的试验,中间可能抛了第一次就出现了正面,也可能抛了4次才出现正面。无论抛了多少次,只要出现了正面,就记录为一次试验。
那么对于多次的伯努利试验,假设这个多次为n次,就意味着出现了n次的正面。假设每次伯努利试验所经历了的抛掷次数为k,第一次伯努利试验,次数设为k1,以此类推,第n次对应的是kn。
其中,对于这n次伯努利试验中,必然会有一个最大的抛掷次数k,例如抛了12次才出现正面,那么称这个为k_max,代表抛了最多的次数。
第一次试验: 抛了3次才出现正面,此时 k=3,n=1
第二次试验: 抛了2次才出现正面,此时 k=2,n=2
第三次试验: 抛了6次才出现正面,此时 k=6,n=3
第n 次试验:抛了12次才出现正面,此时我们估算, n = 2^12
假设上面例子中实验组数共3组,那么 k_max = 6,最终 n=3,我们放进估算公式中去,明显: 3 ≠ 2^6 。也即是说,当试验次数很小的时候,这种估算方法的误差是很大的。
伯努利试验容易得出有以下结论:
A. n 次伯努利过程的投掷次数都不大于 k_max。
B. n 次伯努利过程,至少有一次投掷次数等于 k_max。
最终结合极大似然估算的方法,发现在n和k_max中存在估算关联:n = 2^(k_max) 。
使用场景
非精准的去重计数估算,如:用户注册IP数、每日访问IP数、页面实时UV(PV肯定字符串就搞定了)、在线用户数等,对准确性要求不是很严格的应用场景。像REDIS、SPARK、FLINK,都提供了基数估算的能力,其目的就是在一定的误差范围内,用最小的空间复杂度来估算一个数据流的基数。其优势就是可以做到只需要 12 kb 的空间大小,就可以实现接近 2^64 量级的基数统计。