先來看幾個比較常見的例子python
這幾個例子有一個共同的特色: 如何判斷一個元素是否存在一個集合中?git
雖然上面描述的這幾種數據結構配合常見的排序、二分搜索能夠快速高效的處理絕大部分判斷元素是否存在集合中的需求。可是當集合裏面的元素數量足夠大,若是有500萬條記錄甚至1億條記錄呢?這個時候常規的數據結構的問題就凸顯出來了。數組、鏈表、樹等數據結構會存儲元素的內容,一旦數據量過大,消耗的內存也會呈現線性增加,最終達到瓶頸。有的同窗可能會問,哈希表不是效率很高嗎?查詢效率能夠達到O(1)。可是哈希表須要消耗的內存依然很高。使用哈希表存儲一億 個垃圾 email 地址的消耗?哈希表的作法:首先,哈希函數將一個email地址映射成8字節信息指紋;考慮到哈希表存儲效率一般小於50%(哈希衝突);所以消耗的內存:8 * 2 * 1億 字節 = 1.6G 內存,普通計算機是沒法提供如此大的內存。這個時候,布隆過濾器(Bloom Filter)就應運而生。在繼續介紹布隆過濾器的原理時,先講解下關於哈希函數的預備知識。github
哈希函數的概念是:將任意大小的數據轉換成特定大小的數據的函數,轉換後的數據稱爲哈希值或哈希編碼。下面是一幅示意圖:算法
能夠明顯的看到,原始數據通過哈希函數的映射後稱爲了一個個的哈希編碼,數據獲得壓縮。哈希函數是實現哈希表和布隆過濾器的基礎。數組
布隆過濾器(Bloom Filter)的核心實現是一個超大的位數組和幾個哈希函數。假設位數組的長度爲m,哈希函數的個數爲k網絡
以上圖爲例,具體的操做流程:假設集合裏面有3個元素{x, y, z},哈希函數的個數爲3。首先將位數組進行初始化,將裏面每一個位都設置位0。對於集合裏面的每個元素,將元素依次經過3個哈希函數進行映射,每次映射都會產生一個哈希值,這個值對應位數組上面的一個點,而後將位數組對應的位置標記爲1。查詢W元素是否存在集合中的時候,一樣的方法將W經過哈希映射到位數組上的3個點。若是3個點的其中有一個點不爲1,則能夠判斷該元素必定不存在集合中。反之,若是3個點都爲1,則該元素可能存在集合中。注意:此處不能判斷該元素是否必定存在集合中,可能存在必定的誤判率。能夠從圖中能夠看到:假設某個元素經過映射對應下標爲4,5,6這3個點。雖然這3個點都爲1,可是很明顯這3個點是不一樣元素通過哈希獲得的位置,所以這種狀況說明元素雖然不在集合中,也可能對應的都是1,這是誤判率存在的緣由。數據結構
下面給出python的實現,使用murmurhash算法函數
import mmh3 from bitarray import bitarray # zhihu_crawler.bloom_filter # Implement a simple bloom filter with murmurhash algorithm. # Bloom filter is used to check wether an element exists in a collection, and it has a good performance in big data situation. # It may has positive rate depend on hash functions and elements count. BIT_SIZE = 5000000 class BloomFilter: def __init__(self): # Initialize bloom filter, set size and all bits to 0 bit_array = bitarray(BIT_SIZE) bit_array.setall(0) self.bit_array = bit_array def add(self, url): # Add a url, and set points in bitarray to 1 (Points count is equal to hash funcs count.) # Here use 7 hash functions. point_list = self.get_postions(url) for b in point_list: self.bit_array[b] = 1 def contains(self, url): # Check if a url is in a collection point_list = self.get_postions(url) result = True for b in point_list: result = result and self.bit_array[b] return result def get_postions(self, url): # Get points positions in bit vector. point1 = mmh3.hash(url, 41) % BIT_SIZE point2 = mmh3.hash(url, 42) % BIT_SIZE point3 = mmh3.hash(url, 43) % BIT_SIZE point4 = mmh3.hash(url, 44) % BIT_SIZE point5 = mmh3.hash(url, 45) % BIT_SIZE point6 = mmh3.hash(url, 46) % BIT_SIZE point7 = mmh3.hash(url, 47) % BIT_SIZE return [point1, point2, point3, point4, point5, point6, point7]
源碼地址:https://github.com/cpselvis/zhihu-crawler/blob/master/bloom_filter.pypost