項目簡介
包含一個基於Redis的布隆過濾器的實現,以及應用到Scrapy中的Demo。
地址:BloomFilterRedis 布隆過濾器
網上有很多介紹,推薦《數學之美》,介紹的很詳盡,此處不再贅述。 雜湊函數
布隆過濾器中需要n個雜湊函數,我使用的是Arash Partow提供的常見雜湊函數。 建立在Redis上的布隆過濾器
Redis中有一個資料結構叫做Bitmap(下方有官網詳解),它提供一個最大長度為512MB(2^32)的位元組。我們可以把它提供給布隆過濾器做位元組。
根據《數學之美》中給出的資料,在使用8個雜湊函數的情況下,512MB大小的位元組在誤判率萬分之五的情況下可以對約兩億的url去重。而若單純的使用set()去重的話,以一個url64個位元組記,兩億url約需要128GB的記憶體空間,不敢想象。
我使用的策略是使用雜湊函數算出的雜湊值對2^32模數,填入bitmap中。 Reids之Bitmap
以下內容翻譯自官網http://www.redis.cn/topics/data-types-intro.html#bitmaps,
英語水平有限,有些地方選擇了意譯,大佬路過還請不吝賜教,先行謝過~
Bitmap不是一個確切的資料類型,而是基於String類型定義的一系列面向位操作的方法。因為String是二進位安全的並且它們的最大長度是512MB,
所以String類型很合適去作為一個2^32長度的位元組。
位操作方法可以被分為兩組:一、對單一位的操作,比如設定某一位為1或0,或者得到這一位的值;二、對一組位的操作,比方說計算一定範圍內的1的個數(比如計數)
bitmap一個最大的優勢是它通常能在儲存資訊的時候節省大量空間。比方說一個用增量ID來辨別使用者的系統,可以用僅僅512MB的空間來標識40億個使用者是否想要接受通知。
使用SETBIT和GETBIT命令來對位進行置數和檢索:
> setbit key 10 1(integer) 1> getbit key 10(integer) 1> getbit key 11(integer) 0
SETBIT 如上所示,意思是將第10位置位為1,第二個參數可為0或1。如果設定的位超出了當前String的長度,那麼會自動成長。(最長2^32,下同)
GETBIT 如上所示,返回第10位和第11位的資料,分別是1和0。如果尋找的位超出了當前String的長度,那麼會返回0。
接下來是三個對一組位進行操作的命令:
BITOP 執行不同字串之間的逐位操作。所提供的操作有AND,OR,XOR和NOT。BITCOUNT
BITCOUNT 計數,返回bitmap裡值為1的位的個數.
BITPOS 返回第一個0或1的位置
BITPOS和BITCOUNT不僅可以作用於整個bitmap,還可以作用於一定的範圍,下面是一個BITCOUNT的例子:
> setbit key 0 1(integer) 0> setbit key 100 1(integer) 0> bitcount key(integer) 2
應用執行個體略…… 整合進Scrapy
Scrapy中可以在settings.py中通過DUPEFILTER_CLASS配置過濾器,github上給出了樣本工程。 驗證
起初的驗證策略是:使用scrapy架構從一個百度百科頁面出發,提取頁面內其它百科詞條的連結,在過濾器內將過濾掉的url記錄在本地檔案
filted.txt中,將正確請求的到的結果存入mongoDB。
在起初測試時發現filted.txt中記錄的過濾掉的url中百分之九十九都不在mongoDB內,注意到已過濾掉約1萬條url,而mongoDB中僅有300條,
使用bitcount key命令查看redis中的bitmap中的值為1的位的個數,發現有約10萬。而mongoDB中的300條資料至多置位300*8=2400位,顯
然哪裡出了問題。經分析,這是因為大量經過過濾器的請求尚存在於scrapy的請求隊列中,未被發出,所以mongoDB裡也不會有相應記錄。
所以為了驗證布隆過濾器的可靠性,在過濾器過濾前將所有的url都存入allurl.txt檔案,等檔案內url達到一定規模後,與filted.txt進行
相應處理——編寫指令碼計算誤判率。經驗證,在對百度百科約70萬條url進行處理後,過濾約40萬條,誤判量為0。此驗證規模甚小,但筆者近期無具體大
規模去重需求,歡迎有需求或有興趣的同仁使用並反饋。