一、 Bloom-Filter演算法簡介。
Bloom-Filter,即布隆過濾器,1970年由Bloom中提出。它可以用於檢索一個元素是否在一個集合中,其優點是空間效率和查詢時間都遠遠超過其他演算法,其不足在於Bloom-Filter存在著誤判。
二、 Bloom-Filter的基本思想。
Bloom-Filter演算法的核心思想就是利用多個不同的Hash函數來解決“衝突”。
計算某元素x是否在一個集合中,首先能想到的方法就是將所有的已知元素儲存起來構成一個集合R,然後用元素x跟這些R中的元素一一比較來判斷是否存在於集合R中;我們可以採用鏈表等資料結構來實現。但是,隨著集合R中元素的增加,其佔用的記憶體將越來越大。試想,如果有幾千萬個不同網頁需要下載,所需的記憶體將足以佔用掉整個進程的記憶體位址空間。即使用MD5,UUID這些方法將URL轉成固定的短小的字串,記憶體佔用也是相當巨大的。
於是,我們會想到用Hash table的資料結構,運用一個足夠好的Hash函數將一個URL映射到二進位位元組(位元影像數組)中的某一位。如果該位已經被置為1,那麼表示該URL已經存在。
Hash存在一個衝突(碰撞)的問題,用同一個Hash得到的兩個URL的值有可能相同。為了減少衝突,我們可以多引入幾個Hash,如果通過其中的一個Hash值我們得出某元素不在集合中,那麼該元素肯定不在集合中。只有在所有的Hash函數告訴我們該元素在集合中時,才能確定該元素存在於集合中。這便是Bloom-Filter的基本思想。
正如前面提及的,Bloom-Filter有可能會誤判,也就是說會將一個並不存在於集合中的元素誤認為已存在於集合中。但是另一方面,它絕對不可能會將一個已經存在於集合中的元素誤認為是不存在於集合中。正所謂“寧可錯殺一千,也不放過一個”。實驗證明,位元影像數組長度越大,元素的數量越小,則Bloom-Filter誤判的機率越小。
三、 Bloom-Filter的應用。
Bloom-Filter一般用於在大資料量的集合中判定某元素是否存在。例如郵件伺服器中的垃圾郵件過濾器。在搜尋引擎領域,Bloom-Filter最常用於網路蜘蛛(Spider)的URL過濾,網路蜘蛛通常有一個URL列表,儲存著將要下載和已經下載的網頁的URL,網路蜘蛛下載了一個網頁,從網頁中提取到新的URL後,需要判斷該URL是否已經存在於列表中。此時,Bloom-Filter演算法是最好的選擇。
四、 Bloom-Filter的具體實現。
這裡的實現使用兩個hash函數。
1. 資料結構。
/** bitmap array of bloom-filter */
struct bitmap_bloomfilter_t
{
u32_t * bitmap1; /* 第一個hash可映射到這裡 */
u32_t * bitmap2; /* 第二個hash可映射到這裡 */
long max_size; /*
};
2.函數。
bitmap_bloomfilter_t結構用於儲存元素是否存在的位元組,我們需要相關的函數分別建立和釋放它。
(1)bitmap_bloomfilter_t * create_bitmap_bloomfilter( long max_size ),建立bitmap_bloomfilter_t對象,參數max_size表示位元影像數組中最大容納的元素數。
(2)void free_bitmap_bloomfilter( bitmap_bloomfilter_t ** bbf ),釋放一個bitmap_bloomfilter_t對象,該對象同時被銷毀。
bloom-filter過濾函數,判斷一個元素是否在集合中。
(3)int bloomfilter_filter( const bitmap_bloomfilter_t * bbf, const void * data, long len )
以下是幾個內建函式。我們還需要兩個函數,一個用來來判斷位元影像數組中某一位的值是否為1,另一個用於將位元影像數組中的某一位設定為1。
(4)static __INLINE__ BOOL get_bitmap_bit( const u32_t * bitmap, u32_t offset ), 判斷位元影像數組中某一位的值是否為1。
(5)static __INLINE__ void set_bitmap_bit( const u32_t * bitmap, u32_t offset ),將位元影像數組中的某一位設定為1。
我們使用的兩個hash函數。
(6)static u32_t hash_f1( const void * data, long len )
(7)static u32_t hash_f2( const void * data, long len )
2. 樣本程式。
long * url[10] = {
“http://www.baidu.com/”,
“http://www.google.com/”,
“http://www.rising.com.cn”,
“http://www.yahoo.com/”,
“http://www.microsoft.com/”,
“http://www.baidu.com/”,
“http://www.baidu.com.cn”,
“http://www.baidu.com”,
“http://www.baidu.com/index.html”,
“http://www.firefox.org/”
};
int main( int argc, char ** argv )
{
int i;
bitmap_bloomfilter_t * bbf = create_bitmap_bloomfilter( 10000 );/*建立位元影像數組結構*/
for ( i=0; i<10;>分別對url中的10元素進行過濾操作*/
{
fprintf( stdout, “%ld->filtered(%d).\n”, data[i], bloomfilter_filter(bbf, (void*)(data+i), strlen(url[i])) );
}
free_bitmap_bloomfilter( &bbf );/*釋放位元影像數組結構*/
return 0;
}