海量數據處理問題


海量數據的處理在互聯網行業一直是很受關注的一類問題。面對如此龐大的數據量,要在它們當中進行查找、找最值、統計等操作,不難想象,這是一件比較困難的事情。而實際處理當中,通常是會利用  布隆過濾器哈希兩種數據結構來解決這類問題。

布隆過濾器(Bloom Filter)

Bloom Filter(BF)是一種空間效率很高的隨機數據結構,它底層利用位數組很簡潔地表示一個集合,並能判斷一個元素是否屬於這個集合。它是一個能快速判斷元素是否存在集合的一種概率算法。之所以說是概率的是因為Bloom Filter有可能會出現錯誤判斷 (即如果判斷元素存在集合中,有一定的概率判斷錯誤);但它不會漏判,如Bloom Filter判斷元素不在集合,那肯定不在。因此,Bloom Filter不適合那些“零錯誤”的應用場合。

構成:一個位圖和多個哈希函數

原理:

(1)基於位圖:位圖底層是一個位數組,每一位就有0和1 兩種狀態,那么通過這兩種狀態便可以標識一個數據是否存在;同時根據不同的需求我們還可以用多個比特位來標識數據的狀態(如后面的應用)。

(2)設置多個獨立hash函數

      我們知道當進行哈希映射時,是會產生哈希沖突的。譬如處理字符串“sort”和“srot”時很有可能得到相同的哈希值,而實際應用當中,這便造成大量的沖突。為了減少沖突,Bloom Filter使用m個相互獨立的哈希函數(Hash Function), 通過 m個哈希函數將其轉成不同的整型 進而得到m個哈希值,然后在位數組中所有對應的比特位都設置為1。當一個元素的這m個位置都為1時,便可以大致確定它存在於集合了,這便大大減少了沖突 注意,如果一個位置多次被置為1,那么只有第一次會起作用,后面幾次將沒有任何效果。在下圖中,3個哈希函數,且有兩個哈希函數選中同一個位置(下標4)

            

 

總結下來就分這么幾個步驟:

  1. 一數據元素使用m個哈希函數得到m個哈希值
  2. 判斷是否所有哈希值對應的位置都被置為1(1≤i≤m)
  3. 如果所有位置都已置成了‘1’,該元素可大致確定為集合中的元素;只要有一個位置上是‘0’,那該元素一定不是集合中的元素。

注意:.布隆過濾器除了存在誤判以外 還不能刪除元素。刪除一個元素就要把m個位置置為‘0’,這樣就會影響其他元素。(不過可以改進)

#pragma once #include "BitMap.h" typedef const char* KeyType; typedef size_t (*HASH_FUNC)(KeyType);  //計算哈希值的函數指針
 typedef struct BloomFilter { BitMap _bm; //size_t* _bm; //Reset時將一個query用一個32位一個數據項保存信息,如此可以表示更大的引用計數
    HASH_FUNC _hashfunc1;   //計算字符串的哈希值函數
 HASH_FUNC _hashfunc2; HASH_FUNC _hashfunc3; }BloomFilter; void BloomFilterInit(BloomFilter* bf, size_t range); void BloomFilterSet(BloomFilter* bf, KeyType key); //void BloomFilterReset(BloomFilter* bf, KeyType key); //優化后可實現
int BloomFilterTest(BloomFilter* bf, KeyType key); size_t BKDRHash(KeyType str) { register size_t hash = 0; while(size_t ch = (size_t)*str++) { hash = hash * 131 + ch;// 也可以乘以31、131、1313、13131、131313.. 
 } return hash; } size_t SDBMHash(KeyType str) { register size_t hash =0; while(size_t ch = (size_t)*str++) { hash = 65599 * hash + ch;//hash =(size_t)ch + (hash <<6) + (hash << 16) - hash; 
 } return hash; } size_t RSHash(KeyType str) { register size_t hash = 0; size_t magic = 63689; while(size_t ch = (size_t)*str++) { hash = hash * magic + ch; magic*= 378551; } return hash; } void BloomFilterInit(BloomFilter* bf, size_t range) { assert(bf); BitMapInit(&bf->_bm, range); bf->_hashfunc1 = BKDRHash; bf->_hashfunc2 = SDBMHash; bf->_hashfunc3 = RSHash; } void BloomFilterSet(BloomFilter* bf, KeyType key) { assert(bf); //假如sort 123 
    size_t hash1 = bf->_hashfunc1(key);  //得到字符串的size_t類型的一個哈希值
    size_t hash2 = bf->_hashfunc2(key); size_t hash3 = bf->_hashfunc2(key); BitMapSet(&bf->_bm, hash1%bf->_bm._range);  //算得的hash 可能比 range大,產生越界訪問;故取模運算
    BitMapSet(&bf->_bm, hash2%bf->_bm._range); BitMapSet(&bf->_bm, hash3%bf->_bm._range); } int BloomFilterTest(BloomFilter* bf, KeyType key) //驗證實現
{ assert(bf); size_t hash1 = bf->_hashfunc1(key);  //得到字符串的size_t類型的一個哈希值
    if(BitMapTest(&bf->_bm, hash1%bf->_bm._range) == -1) return -1; size_t hash2 = bf->_hashfunc2(key); if(BitMapTest(&bf->_bm, hash2%bf->_bm._range) == -1) return -1; size_t hash3 = bf->_hashfunc2(key); if(BitMapTest(&bf->_bm, hash3%bf->_bm._range)) return -1; return 0; }
位圖實現布隆過濾

 注:里面的字符串轉整型算法詳細介紹參考http://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html

 

Bloom Filter改進

布隆底層是一個位圖(其實就是一個位數組在保持數據),刪除一個元素就要把m個位置都置為‘0’,這樣就會影響其他元素。那就不妨用多個bit位來存儲元素的一個哈希映射位(相當於增添計數)。比如用8個比特位(即1字節)來存儲

              

                                                                   8位進行映射

這里為了計算方便,不妨直接用32個bit來存儲一個哈希映射位(可以表示所有整型)。只是這樣的改進一定程度上加大了對內存的消耗。

大致知道了布隆過濾器,就可以來看看它是如何來應用的了。

 

應用

 題目給兩個文件,分別有100億個query(查詢),我們只有1G內存,如何找到兩個文件交集?分別給出近似算法和精確算法

 

近似算法:上布隆過濾器
1. 將第一個文件中每個query通過字符串算法轉換成整型。

  2. 通過多個哈希函數把每個query映射到布隆過濾器中。

  3. 把第二個文件中的query也利用字符串轉換算法轉換位整型,然后一個一個在布隆過濾器中查找,看是否存在。

布隆過濾器以其良好的空間和時間效率能夠較快的找這兩個文件的交集。但因為布隆過濾器判斷一個元素是否存在是不准確的,所以這只是一個近似算法。

精確算法哈希切分  如下圖

 

   

由於布隆過濾器存在誤判的現象,所以它的應用通常是用來進行大致的判斷。而針對那種要求零誤差的情形,它便不適用了,想要精確的判斷,通常會先利用哈希進行切分,切分為許多的小文件,然后對小文件進行操作。以此來解決內存不夠的問題。

對於哈希切分,還有很多與上面類似的問題,如在一個很大的日志文件中找出出現次數最多的IP, 找出出現次數前K位的IP等,解決它們的思路都大同小異,借助空間效率很高的位圖 配合着哈希切分來解決就ok了。

 


免責聲明!

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



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