布隆過濾器(Bloom Filter)

 

# 下面給出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]

  


什麼狀況下須要布隆過濾器?

先來看幾個比較常見的例子python

  • 字處理軟件中,須要檢查一個英語單詞是否拼寫正確
  • 在 FBI,一個嫌疑人的名字是否已經在嫌疑名單上
  • 在網絡爬蟲裏,一個網址是否被訪問過
  • yahoo, gmail等郵箱垃圾郵件過濾功能

這幾個例子有一個共同的特色: 如何判斷一個元素是否存在一個集合中?算法

常規思路

  • 數組
  • 鏈表
  • 樹、平衡二叉樹、Trie
  • Map (紅黑樹)
  • 哈希表

雖然上面描述的這幾種數據結構配合常見的排序、二分搜索能夠快速高效的處理絕大部分判斷元素是否存在集合中的需求。可是當集合裏面的元素數量足夠大,若是有500萬條記錄甚至1億條記錄呢?這個時候常規的數據結構的問題就凸顯出來了。數組、鏈表、樹等數據結構會存儲元素的內容,一旦數據量過大,消耗的內存也會呈現線性增加,最終達到瓶頸。有的同窗可能會問,哈希表不是效率很高嗎?查詢效率能夠達到O(1)。可是哈希表須要消耗的內存依然很高。使用哈希表存儲一億 個垃圾 email 地址的消耗?哈希表的作法:首先,哈希函數將一個email地址映射成8字節信息指紋;考慮到哈希表存儲效率一般小於50%(哈希衝突);所以消耗的內存:8 * 2 * 1億 字節 = 1.6G 內存,普通計算機是沒法提供如此大的內存。這個時候,布隆過濾器(Bloom Filter)就應運而生。在繼續介紹布隆過濾器的原理時,先講解下關於哈希函數的預備知識。數組

哈希函數

哈希函數的概念是:將任意大小的數據轉換成特定大小的數據的函數,轉換後的數據稱爲哈希值或哈希編碼。下面是一幅示意圖:markdown

能夠明顯的看到,原始數據通過哈希函數的映射後稱爲了一個個的哈希編碼,數據獲得壓縮。哈希函數是實現哈希表和布隆過濾器的基礎。網絡

布隆過濾器介紹

  • 巴頓.布隆於一九七零年提出
  • 一個很長的二進制向量 (位數組)
  • 一系列隨機函數 (哈希)
  • 空間效率和查詢效率高
  • 有必定的誤判率(哈希表是精確匹配)

布隆過濾器原理

布隆過濾器(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,這是誤判率存在的緣由。函數

布隆過濾器添加元素

  • 將要添加的元素給k個哈希函數
  • 獲得對應於位數組上的k個位置
  • 將這k個位置設爲1

布隆過濾器查詢元素

  • 將要查詢的元素給k個哈希函數
  • 獲得對應於位數組上的k個位置
  • 若是k個位置有一個爲0,則確定不在集合中
  • 若是k個位置所有爲1,則可能在集合中
相關文章
相關標籤/搜索