利用bloom filter演算法處理大規模資料過濾

來源:互聯網
上載者:User

標籤:c   演算法   網路爬蟲   hash   bloom   

Bloom Filter是由Bloom在1970年提出的一種快速尋找演算法,通過多個hash演算法來共同判斷某個元素是否在某個集合內。可以用於網路爬蟲的url重複過濾、垃圾郵件的過濾等等。


它相比hash容器的一個優勢就是,不需要儲存元素的實際資料到容器中去來一個個的比較是否存在。
只需要對應的位段來標記是否存在就行了,所以想當節省記憶體,特別適合海量的資料處理。並且由於省去了儲存元素和比較操作,所以效能也比基於hash容器的高了很多。


但是由於bloom filter沒有去比較元素,只通過多個hash來判斷唯一性,所以存在一定的hash衝突導致誤判。誤判率的大小由hash函數的個數、hash函數優劣、以及儲存的位空間大小共同決定。


並且刪除也比較困難,解決辦法是使用其變種,帶計數的bloom filter,這個這裡就不多說了。


對於bloom filter演算法的實現,相當簡單:
首先分配一塊固定的連續空間,大小是m個位元位(m/8+1個位元組),然後再提供k個不同hash函數,同時對每個元素進行計算位索引。如果每個位索引對應的位都為1,則存在該元素,否則就是不存在。


可以看出,如果判斷為不存在,那麼肯定是不存在的,只有在判斷為存在的時候,才會存在誤判。


bloom filter主要的痛點其實在於估算:
保證指定誤判率的情況下,到底需要多少個hash函數,多少的儲存空間。


首先來看下bloom filter的誤判率計算公式:


假定有k個hash函數,m個位元位的儲存空間,n個集合元素,則有誤判率p:


    p = (1 - ((1 - 1/ m) ^ kn))^k ~= (1 - e^(-kn/m))^k
 
根據這個,官方給出了一個計算k的最優解公式,使其滿足給定p的情況下,儲存空間達到最小:


    k = (m / n) * ln2


把它帶入機率公式得到:


    p = (1 - e ^-((m/nln2)n/m))^(m/nln2)


簡化為:


    lnp = -m/n * (ln2)^2


因此,如果指定p,只需要滿足如果公式,就可以得到最優解:


    s = m/n = -lnp / (ln2 * ln2) = -log2(p) / ln2
    k = s * ln2 = -log2(p)


理論值:


    p < 0.1: k = 3.321928, m/n = 4.79
    p < 0.01: k = 6.643856, m/n = 9.58
    p < 0.001: k = 9.965784, m/n = 14.37
    p < 0.0001: k = 13.287712, m/n = 19.170117


可以看出,這個確實能夠在保證誤判率的前提下,使其儲存空間達到最小,但是使用的hash函數個數k
相對較多,至少也得4個,要滿足p < 0.001,需要10個才行,這個對於字串hash的計算來講,效能損耗相當大的,實際使用中根本沒法接受。


因此我們需要另外一種推到公式,可以認為指定p和k的情況下,來計算空間使用s=m/n的大小,這樣我們在實際使用的時候,靈活性就大大提高了。


下面來看下,我自己推到出來的公式,首先還是依據誤判率公式:


    p = (1 - e^(-kn/m))^k


假定s=m/n,則有


    p = (1 - e^(-k/s))^k


兩邊取導,得到:


    lnp = k * ln(1 - e^(-k/s))


交換k:


    (lnp) / k = ln(1 - e^(-k/s))


重新上e:


    e^((lnp) / k) = 1 - e^(-k/s)


化簡:


    e^(-k/s) = 1 - e^((lnp) / k) = 1 - (e^lnp)^(1/k) = 1 - p^(1/k)


再求導:


    -k/s = ln(1 - p^(1/k))


得出:


    s = -k / ln(1 - p^(1/k))


假定`c = p^(1/k)`:


    s = -k / ln(1 - c)
    
利用泰勒展開式:`ln(1 + x) ~= x - 0.5x^2 while x < 1` 化簡得到:


    s ~= -k / (-c-0.5c^2) = 2k / (2c + c * c)


最後得出公式:


    c = p^(1/k)
    s = m / n = 2k / (2c + c * c)


假定有n=10000000的資料量,則有理論值:


    p < 0.1 and k = 1: s = m/n = 9.523810
    p < 0.1 and k = 2: s = m/n = 5.461082
    p < 0.1 and k = 3: s = m/n = 5.245850, space ~= 6.3MB
    p < 0.1 and k = 4: s = m/n = 5.552045, space ~= 6.6MB


    p < 0.01 and k = 1: s = m/n = 99.502488
    p < 0.01 and k = 2: s = m/n = 19.047619
    p < 0.01 and k = 3: s = m/n = 12.570636, space ~= 15MB
    p < 0.01 and k = 4: s = m/n = 10.922165, space ~= 13MB


    p < 0.001 and k = 1: s = m/n = 999.500250
    p < 0.001 and k = 2: s = m/n = 62.261118
    p < 0.001 and k = 3: s = m/n = 28.571429, space ~= 34MB
    p < 0.001 and k = 4: s = m/n = 20.656961, space ~= 24.6MB


    p < 0.0001 and k = 1: s = m/n = 9999.500025
    p < 0.0001 and k = 2: s = m/n = 199.004975
    p < 0.0001 and k = 3: s = m/n = 63.167063, space ~= 75.3MB
    p < 0.0001 and k = 4: s = m/n = 38.095238, space ~= 45.4MB
    p < 0.0001 and k = 5: s = m/n = 29.231432, space ~= 24.8MB


可以看到,在k=3的情況下,其實已經可以達到我們平常使用所能的接受範圍內了,沒必要非得
使用最優解,除非在空間使用極為苛刻的情況下,而且這個公式,針對程式空間使用的調整,更加的靈活智能。


特別提下,經過實測,如果每個hash的實現非常優質,分布很均勻的情況下,其實際的誤判率比理論值低很多:


就拿TBOX的bloom filter的實現做測試,n=10000000:


    p < 0.01 and k = 3的情況下,其實際誤判率為:0.004965
    p < 0.001 and k = 3的情況下,其實際誤判率為:0.000967


所以好的hash函數演算法也是尤為的重要。


下面來看下TBOX提供的bloom filter的使用,用起來也是相當的方便:

 
   // 總的元素個數    tb_size_t count = 10000000;    /* 初始化bloom filter     *     * TB_BLOOM_FILTER_PROBABILITY_0_01: 預定義的誤判率,接近0.01     * 註:由於內部使用位移數來表示:1 / 2^6 = 0.015625 ~= 0.01     * 所以實際傳入的誤判率,有可能稍微大一點,但是還是相當接近的     *     * 3:為k值,hash函數的個數,最大不超過15個     *     * count:指定的元素規模數     *     * tb_item_func_long():容器的元素類型,主要是用其內定的hash函數,如果要自訂hash函數,可以替換:     *     * tb_size_t tb_xxxxxx_hash(tb_item_func_t* func, tb_cpointer_t data, tb_size_t mask, tb_size_t index)     * {     *      // mask為hash掩碼,index為第index個hash演算法的索引     *      return compute_hash(data, index) & mask;     * }     *     * tb_item_func_t func = tb_item_func_long();     * func.hash = tb_xxxxxx_hash;     *     * 來進行     */    tb_bloom_filter_ref_t filter = tb_bloom_filter_init(TB_BLOOM_FILTER_PROBABILITY_0_01, 3, count, tb_item_func_long());    if (filter)    {        tb_size_t i = 0;        for (i = 0; i < count; i++)        {            // 產生隨機數            tb_long_t value = tb_random();                        // 設定值到filter內,如果不存在,則返回tb_true表示設定成功            if (tb_bloom_filter_set(filter, (tb_cpointer_t)value))            {                 // 添加元素成功,之前元素不存在                 // 不會存在誤判            }            else            {                 // 添加失敗,添加的元素已經存在                 // 這裡可能會存在誤判            }                        // 僅僅判斷元素是否存在            if (tb_bloom_filter_get(filter, (tb_cpointer_t)data)            {                 // 元素已經存在                 // 這裡可能會存在誤判            }            else            {                 // 元素不存在                 // 不會存在誤判            }        }                // 退出filter        tb_bloom_filter_exit(filter);    }    // 常用預定義的誤判率,也可以指定其他值,註:必須是位移數,而不是實際值    typedef enum __tb_bloom_filter_probability_e    {        TB_BLOOM_FILTER_PROBABILITY_0_1         = 3 ///!< 1 / 2^3 = 0.125 ~= 0.1    ,   TB_BLOOM_FILTER_PROBABILITY_0_01        = 6 ///!< 1 / 2^6 = 0.015625 ~= 0.01    ,   TB_BLOOM_FILTER_PROBABILITY_0_001       = 10 ///!< 1 / 2^10 = 0.0009765625 ~= 0.001    ,   TB_BLOOM_FILTER_PROBABILITY_0_0001      = 13 ///!< 1 / 2^13 = 0.0001220703125 ~= 0.0001    ,   TB_BLOOM_FILTER_PROBABILITY_0_00001     = 16 ///!< 1 / 2^16 = 0.0000152587890625 ~= 0.00001    ,   TB_BLOOM_FILTER_PROBABILITY_0_000001    = 20 ///!< 1 / 2^20 = 0.00000095367431640625 ~= 0.000001                }tb_bloom_filter_probability_e;


----------


TBOX項目詳情:http://www.oschina.net/p/tbox
TBOX項目源碼:https://github.com/waruqi/tbox
TBOX項目文檔:https://github.com/waruqi/tbox/wiki/%E7%9B%AE%E5%BD%95

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.