基數估計
緣起
項目中遇到的問題,考慮如下場景:
A,B,C,…..N個集合,這裏的集合不是嚴格意義上的集合,只是指一個list,裏面有重複元素。
然後我要統計這些集合的交集,並集的集合(這裏的交集並集爲嚴格意義上的集合,無重複元素)的數量,即先做 inner join 後,再 count(distinct())。
這些集合的大小從十萬到十億不等,大概有幾百個這樣的集合。
目前是通過mapreduce來進行計算。
下一個任務,又會重複計算這些交集
問題
1.內存資源緊張,磁盤IO消耗主要時間。
2.重複計算某些集合之間的join。
改進
1.避免大集合之間做join
2.避免重複任務
新方法
1.對每個集合進行基數統計。
2.保存各個集合的基數統計的中間結果,每個大概爲幾k到幾十k。
3.對中間結果進行交集和並集的計算,估計基數值。
基本的概念我就不寫了,基本上這篇博客介紹的很清楚:
另外原作者的論文我覺得寫得非常好,谷歌的改進算法原論文也寫得很好
從簡單到複雜
Linear Counting
Linear Counting(簡稱LC)是最基本的概率模型的基數統計方法,之後的LogLogCounting(簡稱LLC)和HyperLogLog Counting(HLLC)的統計思想都是來源於這個統計方法進行的改進。
以下直接摘自上面說的那篇博客:
LC的基本思路是:設有一哈希函數H,其哈希結果空間有m個值(最小值0,最大值m-1),並且哈希結果服從均勻分佈。使用一個長度爲m的bitmap,每個bit爲一個桶,均初始化爲0,設一個集合的基數爲n,此集合所有元素通過H哈希到bitmap中,如果某一個元素被哈希到第k個比特並且第k個比特爲0,則將其置爲1。當集合所有元素哈希完成後,設bitmap中還有u個bit爲0。則:
爲n的一個估計,且爲最大似然估計(MLE)。
誤差分析:
LC原理圖:
具體推導就不寫了,感興趣參見原博客。
下面分析複雜度:
其實LC算法和bitmap算法很相似,都是一個bit存儲一個信息,故空間複雜度爲O(Nmax)
誤差控制:
從上面那個公式可以反推出:
LogLog Counting
LogLogCounting ,顧名思義,空間複雜度只有O(loglogN)了,這也太牛了吧。
公式,推導,還在整理,目前我只整理了測試報告,包含實現基本步驟,和性能測試結果。
算法基本說明:
設:
元素名稱 | 說明 |
---|---|
N | 基數上限值 |
a | A集合中某一元素 |
b | B集合中某一元素 |
Hash() | 某種hash函數 |
L | 某BitMap |
E | 估計的基數值 |
m | BitMap的長度 |
u | Bitmap中0的數量 |
f(L) | Bitmap中,從左到右第一個1出現的位置 |
BitMap:非概率算法。
算法步驟:
1.生成長度爲N的BitMap:L。
2.hash(a)到L中某一位,並置爲1.
3.將輸入集合重複第2步。
4.估計值E 等於L中1的個數。
LinearCounting:概率算法。
算法步驟:
生成長度爲m的BitMap:L。
hash(a)到L中某一位,並置爲1.
將輸入集合重複第2步.
統計BitMap中0的數量爲u,則估計值E = -mlog(u/m)
LogLogCounting: 概率算法。
算法步驟:
生成長度爲m的BitMap:L。其中m=32,並生成2^k個寄存器M,k
AdaptiveCounting: 概率算法。
算法步驟:
採用LogLogCounting 計算,然後計算空桶率b.
如果b<0.051,則採用LogLogCounting估計公式,否則採用LinearCounting估計公式.
HyperLogLogCounting: 概率算法。
算法步驟:
前四步和LogLogCounting前四步相同。
估計值變爲E = ,其中 ,即將算數平均替換爲調和平均。
分段偏差修正:
E ≤ 5/2 m , 使用LC估計.
5/2 m < E ≤1/30 2^32 , 使用E估計.
E > 1/30 2^32 , 使用 E = -2^32 log(1-E/2^32 ) 估計.
HyperLogLog++: 概率算法。
算法步驟:
將HyperLogLog中32位bitmap變爲64位。
增加M的稀疏表示,用鍵值對替代M。
分段偏差修正:
E ≤ 5m , E’=(E-bias(E,p)).
E > 5m , E’ = E
V ≠0, 使用LC估計,H = LC(m,V)
V = 0, H = E’
H ≤Threshold(p) return H
H >Threshold(p) return E’
MinHash: 概率算法。
算法步驟:
將Hash(A),hash(B),最小的k個值分別放入集合S1,S2。
求Jaccard Index : J = y/k, 其中,y= |S1∩S2|
HyperLogLog++&Inclusion-exculsion principle: 概率算法。
算法步驟:
利用HyperLogLog++分別計算|A|,|B|, |A∪B| 的基數
利用 Inclusion-exculsion principle : |A∩B| = |A| + |B| - |A∪B|
HyperLogLog++&MinHash: 概率算法。
算法步驟:
利用HyperLogLog++計算兩個集合並集的基數x=|A∪B|
利用MinHash計算 Jaccard Index:J
由J=(|A∩B|)/(|A∪B|) , 得到實際基數y = |A∩B|= J * x