(轉)預估大數據量下UV的方法


在實際應用中,我們經常碰到這種情況,即要統計某個對象或者事件獨立出現的次數。對於較小的數據量,這很容易解決,我們可以首先在內存中對序列進行排序,然后掃描有序序列統計獨立元素數目。其中排序時間復雜度為O(n*log(n)),掃描時間復雜度為O(n),所以總的時間復雜度為O(n*log(n))。當內存非常充裕時,我們還可以考慮使用哈希,將時間復雜度降到O(n)。尤其是當元素只能取有限范圍的整數值時,我們還可以使用BitMap節約內存。但是在處理數據流序列時,比如,google的獨立訪問IP統計,由於序列非常長,元素取值范圍可能比較廣,單個元素占用內存可能比較多,導致內存中無法容納整個序列,甚至無法容納整個獨立元素集合。此時,不論是基於排序還是基於哈希的方法都不具備可行性。

Flajolet-Martin(FM)算法能夠較好地解決估算數據流序列中獨立元素數目的問題。

假設我們有1萬個int型數字(可重復的),我們想找出這個數字集合中不重復的數字的個數。怎么辦呢?很簡單,將這1萬個數字讀進內存,存放到hashset中,那么hashset的size就是不重復數字的個數。接下來,問題變得更加的復雜,有100億個數字,怎么辦? 全部讀取到內存中可能會有問題,如果這其中有1億個不重復的數字,那么至少需要內存 100M * sizeof(int),內存也許不夠。 FM算法就是為了解決這個問題。假設n個object,其中有m個唯一的,那么FM算法只需要log(m)的內存占用(實際操作中會是k*log(m)),以及O(n)的運算時間。當然,FM的問題是,它的結果只是一個估計值,不是精確結果。

具體思路如下:

假定哈希函數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即為最終的估計值。

分析FM算法的時間復雜度。假定序列長度為N,哈希函數H(e)的數目為K。初始化K個Max值的時間復雜度為O(K);對N個元素e使用K個哈希函數H(e)計算TailZero(H(e))並更新Max值的時間復雜度為O(N*K);綜合K個Max值給出最終估計值的時間復雜度為O(K)。因此總的時間復雜度為O(N*K)。

分析FM算法的空間復雜度。該算法需要存儲K個Max值,而每個元素e在進行相關計算后就可以丟掉。因此總的空間復雜度為O(K)。

綜上所述,FM算法的時間復雜度為O(N*K),空間復雜度為O(K)。一般來說K比較小,可以認為FM算法的時間復雜度為O(N),空間復雜度為O(1)。

FM算法可以用於估算獨立Cookie數目,獨立URL數目,獨立郵箱地址數目等等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM