最近在学习如何解决大数据流中的独立元素计数问题。这么讲起来有点抽象,一个很典型的例子是如何实时计算或者估计网站UV。
针对类似问题,很容易想到一个简单的办法:我们可以先对数据排序,然后再统计。可这种方法却无法应对大数据现实,因为在大数据场景下,诸如网站UV的数值,每天可能达到上亿,这就导致计算的时间及空间复杂度很高,因而很难满足实时要求。
Flajolet-Martin算法较好的解决了独立元素计数问题;当然,它是一个估计值,能在极大降低空间复杂度的前提下,提供业务方可接受的估值精度。
简单描述下自己的认识,关于”为什么FM算法估值比较精确“:
首先,我们容易理解:”在一个整数集中,每2^ K个数后就会出现一个尾部K个0组成的比特序列“;
我们将数据流中的每个元素,通过哈希函数映射为一个随机整数;
同时我们针对每个哈希函数的结果集,统计每个随机整数尾部的全0比特序列长度(尾部有多少个连续0),记录该长度最大值,即为R;
这时,我们认为2^R 可以作为数据流中不重复元素个数的估计值。假设数据流中有M个非重复元素,忽略理论证明,可以有如下结论:
当M >> 2^r 时,那么发现一个尾部长度至少为 r 的概率接近1;( 反过来想,我们取了所有r值中的最大值R,则R不会过小。)
当M << 2^r 时,那么发现一个尾部长度至少为 r 的概率接近0;(说明2^R不会过大)
基于上述两条结论,我们可以认为 M的估计值2^R不可能过高或过低。
关于Flajolet-Martin算法,我推荐如下一篇博客文章,觉得讲解的很通俗易懂:
*************************************************************************************************************************************************************************
假定哈希函数H(e)能够把元素e映射到[0, 2^m-1]区间上;再假定函数TailZero(x)能够计算正整数x的二进制表示中末尾连续的0的个数,譬如TailZero(2) = TailZero(0010) = 1,TailZero(8) = TailZero(1000) = 3,TailZero(10) = TailZero(1010) = 1;我们对每个元素e计算TailZero(H(e)),并求出最大的TailZero(H(e))记为Max,那么对于独立元素数目的估计为2^Max。
这种估算的理论依据证明参见 原文。
举例来说,给定序列{e1, e2, e3, e2},独立元素数目N = 3。假设给定哈希函数H(e),有:
H(e1) = 2 = 0010,TailZero(H(e1)) = 1
H(e2) = 8 = 1000,TailZero(H(e2)) = 3
H(e3) = 10 = 1010,TailZero(H(e3)) = 1
第1步,将Max初始化为0;
第2步,对于序列中第1项e1,计算TailZero(H(e1)) = 1 > Max,更新Max = 1;
第3步,对于序列中第2项e2,计算TailZero(H(e2)) = 3 > Max,更新Max = 3;
第4步,对于序列中第3项e3,计算TailZero(H(e3)) = 1 ≤ Max,不更新Max;
第5步,对于序列中第4项e2,计算TailZero(H(e2)) = 3 ≤ Max,不更新Max;
第6步,估计独立元素数目为N’ = 2^Max = 2^3 = 8。
在这个简单例子中,实际值N = 3,估计值N’ = 8,误差比较大。此外,估计值只能取2的乘方,精度不够高。
在实际应用中,为了减小误差,提高精度,我们通常采用一系列的哈希函数H1(e), H2(e), H3(e)……,计算一系列的Max值Max1, Max2, Max3……,从而估算一系列的估计值2^Max1, 2^Max2, 2^Max3……,最后进行综合得到最终的估计值。具体做法是:首先设计A*B个互不相同的哈希函数,分成A组,每组B个哈希函数;然后利用每组中的B个哈希函数计算出B个估计值;接着求出B个估计值的算术平均数为该组的估计值;最后选取各组的估计值的中位数作为最终的估计值。
举例来说,对于序列S,使用3*4 = 12个互不相同的哈希函数H(e),分成3组,每组4个哈希函数,使用12个H(e)估算出12个估计值:
第1组的4个估计值为<2, 2, 4, 4>,算术平均值为(2 + 2 + 4 + 4) / 4 = 3;
第2组的4个估计值为<8, 2, 2, 2>,算术平均值为(8 + 2 + 2 + 2) / 4 = 3.5;
第3组的4个估计值为<2, 8, 8, 2>,算术平均值为(2 + 8 + 8 + 2) / 4 = 5;
3个组的估计值分别为<3, 3.5, 5>,中位数为3.5;
因此3.5 ≈ 4即为最终的估计值。
*************************************************************************************************************************************************************************
另外,也可参考如下文章: