海量數(shù)據(jù)下的去重和查重(二):布隆過濾器

在上篇文章海量數(shù)據(jù)下的去重和查重(一):BitMap位圖法的最后海渊,我們說到位圖法缺點汁胆,是其所占空間隨集合內(nèi)最大元素的增大而增大怠益。這就會帶來一個問題,如果查找的元素數(shù)量少但其中某個元素的值很大忧换,比如數(shù)字范圍是 1 到 1000 億恬惯,那消耗的空間不容樂觀。

針對這個缺點亚茬,有一種改進(jìn)是布隆過濾器酪耳。

布隆過濾器

所謂布隆過濾器,實際上就是一個位圖bitMap刹缝,我們現(xiàn)在假設(shè)有一個長度為m的bit類型的數(shù)組碗暗,以及 K 個互相獨立的優(yōu)秀的哈希函數(shù),且這k個哈希函數(shù)的輸出域都大于或等于 m梢夯。

當(dāng)一個元素加入布隆過濾器中的時候言疗,會進(jìn)行如下操作:

  • 使用 K 個哈希函數(shù)對元素值進(jìn)行 K 次計算,得到 K 個哈希值颂砸,我們將這K個值對m模運算噪奄,得到的 k 個值都在 0~m之間
  • 根據(jù)得到的哈希值,在位數(shù)組中把對應(yīng)下標(biāo)的值置為 1人乓。

當(dāng)要判斷一個值是否在布隆過濾器中勤篮,對元素再次進(jìn)行哈希計算,得到值之后判斷位數(shù)組中的每個元素是否都為 1色罚,如果值都為 1叙谨,那么說明這個值在布隆過濾器中,如果存在一個值不為 1保屯,說明該元素不在布隆過濾器中。

image.png

布隆過濾器最大的用處涤垫,就是可以用來判斷一個元素是否在一個集合中姑尺,很常用的一個功能是用來去重。比如可以用來解決下面的需求

需求一:不安全網(wǎng)頁的黑名單包含100億個黑名單網(wǎng)頁蝠猬,每個網(wǎng)頁的URL最多占用64B切蟋,現(xiàn)在要實現(xiàn)一個網(wǎng)頁過濾系統(tǒng),根據(jù)網(wǎng)頁的URL判斷該網(wǎng)頁是否在黑名單上榆芦。我們可以把黑名單url加載到數(shù)據(jù)庫或者redis中柄粹,但是數(shù)據(jù)庫存在效率問題喘鸟,redis存在內(nèi)存問題。

需求二:在爬蟲中驻右,目標(biāo)網(wǎng)站 URL 千千萬什黑,怎么判斷某個 URL 爬蟲是否寵幸過?簡單點可以爬蟲每采集過一個 URL堪夭,就把這個 URL 存入數(shù)據(jù)庫中愕把,每次一個新的 URL 過來就到數(shù)據(jù)庫查詢下是否訪問過。
但是隨著爬蟲爬過的 URL 越來越多森爽,每次請求前都要訪問數(shù)據(jù)庫一次恨豁,并且對于這種字符串的 SQL 查詢效率并不高。除了數(shù)據(jù)庫之外爬迟,使用 Redis 的 set 結(jié)構(gòu)也可以滿足這個需求橘蜜,并且性能優(yōu)于數(shù)據(jù)庫。而Redis 也存在一個問題:耗費過多的內(nèi)存付呕。

對于上述兩個問題计福,相比于數(shù)據(jù)庫和 Redis,使用布隆過濾器可以很好的避免性能和內(nèi)存占用的問題凡涩。

特點——寧可錯殺三千棒搜,絕不放過一個

從上面的介紹中可以看出,當(dāng)插入的元素越來越多活箕,位數(shù)組中被置為 1 的位置就越多力麸,當(dāng)一個不在布隆過濾器中的元素,經(jīng)過哈希計算之后育韩,得到的值在位數(shù)組中查詢克蚂,有可能這些位置也都被置為 1。這樣一個不存在布隆過濾器中的也有可能被誤判成在布隆過濾器中筋讨。但是如果布隆過濾器判斷說一個元素不在布隆過濾器中埃叭,那么這個值就一定不在布隆過濾器中。簡單來說:

布隆過濾器說某個元素在悉罕,可能會被誤判赤屋。
布隆過濾器說某個元素不在,那么一定不在壁袄。

這個布隆過濾器的缺陷放到上面爬蟲的需求中类早,可能存在某些沒有訪問過的 URL 可能會被誤判為訪問過,但是如果是訪問過的 URL 一定不會被誤判為沒訪問過嗜逻。在黑名單需求中涩僻,一個正常url可能會被誤判為是黑名單url,從而被攔截,但是一個黑名單url是肯定會被攔截的逆日。

雖然存在這個問題嵌巷,但是在這兩種需求中,相對于性能和內(nèi)存來說室抽,一點點的誤判率是可以接受的搪哪。

常見的補救辦法是建立白名單,存儲那些可能被誤判的元素狠半。 比如你苦等的offer 可能被系統(tǒng)丟在郵件垃圾箱(白名單)了噩死。

使用場景

布隆過濾器的最大的用處就是,能夠迅速判斷一個元素是否在一個集合中神年。因此它有如下三個使用場景:

  • 網(wǎng)頁爬蟲對 URL 的去重已维,避免爬取相同的 URL 地址
  • 進(jìn)行垃圾郵件過濾:反垃圾郵件,從數(shù)十億個垃圾郵件列表中判斷某郵箱是否垃圾郵箱(同理已日,垃圾短信)
  • 有的黑客為了讓服務(wù)宕機垛耳,他們會構(gòu)建大量不存在于緩存中的 key 向服務(wù)器發(fā)起請求,在數(shù)據(jù)量足夠大的情況下飘千,頻繁的數(shù)據(jù)庫查詢可能導(dǎo)致 DB 掛掉堂鲜。布隆過濾器很好的解決了緩存擊穿的問題,通過布隆過濾器
    將所有的可用的key放入緩存护奈,當(dāng)請求進(jìn)來時缔莲,先去過濾器中校驗是否存在,如果不存在直接返回null霉旗。

項目中使用

1痴奏、redis布隆過濾器

<dependency>
        <groupId>com.redislabs</groupId>
        <artifactId>jrebloom</artifactId>
        <version>1.0.2</version>
</dependency>

public class RedisBloomDemo {
    public static void main(String[] args) {
        String userIdBloomKey = "userid";
        // 創(chuàng)建客戶端,jedis實例
        Client client = new Client("localhost", 6378);
        // 創(chuàng)建一個有初始值和出錯率的過濾器
        client.createFilter(userIdBloomKey,100000,0.01);
        // 新增一個<key,value>
        boolean userid1 = client.add(userIdBloomKey,"101310222");
        System.out.println("userid1 add " + userid1);

        // 批量新增values
        boolean[] booleans = client.addMulti(userIdBloomKey, "101310111", "101310222", "101310222");
        System.out.println("add multi result " + booleans);

        // 某個value是否存在
        boolean exists = client.exists(userIdBloomKey, "101310111");
        System.out.println("101310111 是否存在" + exists);

        //某批value是否存在
        boolean existsBoolean[] = client.existsMulti(userIdBloomKey, "101310111","101310222", "101310222","11111111");
        System.out.println("某批value是否存在 " + existsBoolean);
    }
}

2厌秒、Guava中的BloomFilter

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>22.0</version>
</dependency>


private static int size = 1000000;
private static BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), size, 0.0001);

public void test2() {
    String aa = "zjl";
    bloomFilter.put(aa);
    System.out.println(bloomFilter.mightContain(aa));
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末读拆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鸵闪,更是在濱河造成了極大的恐慌檐晕,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚌讼,死亡現(xiàn)場離奇詭異辟灰,居然都是意外死亡,警方通過查閱死者的電腦和手機篡石,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門芥喇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人夏志,你說我怎么就攤上這事。” “怎么了沟蔑?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵湿诊,是天一觀的道長。 經(jīng)常有香客問我瘦材,道長厅须,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任食棕,我火速辦了婚禮朗和,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘簿晓。我一直安慰自己眶拉,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布憔儿。 她就那樣靜靜地躺著忆植,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谒臼。 梳的紋絲不亂的頭發(fā)上朝刊,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機與錄音蜈缤,去河邊找鬼拾氓。 笑死,一個胖子當(dāng)著我的面吹牛底哥,可吹牛的內(nèi)容都是我干的咙鞍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼叠艳,長吁一口氣:“原來是場噩夢啊……” “哼奶陈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起附较,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤吃粒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拒课,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徐勃,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年早像,在試婚紗的時候發(fā)現(xiàn)自己被綠了僻肖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡卢鹦,死狀恐怖臀脏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤揉稚,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布秒啦,位于F島的核電站,受9級特大地震影響搀玖,放射性物質(zhì)發(fā)生泄漏余境。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一灌诅、第九天 我趴在偏房一處隱蔽的房頂上張望芳来。 院中可真熱鬧,春花似錦猜拾、人聲如沸即舌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侥涵。三九已至,卻和暖如春宋雏,著一層夾襖步出監(jiān)牢的瞬間芜飘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工磨总, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嗦明,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓蚪燕,卻偏偏與公主長得像娶牌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子馆纳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 使用 HyperLogLog 數(shù)據(jù)結(jié)構(gòu)來進(jìn)行估數(shù)诗良,它非常有價值,可以解決很多精確度不高的統(tǒng)計需求鲁驶。 但是如果我們想...
    要不再等等閱讀 980評論 0 1
  • 上一節(jié)我們學(xué)會了使用 HyperLogLog 數(shù)據(jù)結(jié)構(gòu)來進(jìn)行估數(shù)鉴裹,它非常有價值,可以解決多精確度不高的統(tǒng)計需求钥弯。 ...
    天的安排閱讀 674評論 0 0
  • 前提 網(wǎng)上大部分python實現(xiàn)的布隆過濾器庫如:pybloomfilter径荔、pybloom 但都是基于py2且哈...
    SMEB_閱讀 3,832評論 3 5
  • 在日常生活中,包括在設(shè)計計算機軟件時脆霎,我們經(jīng)常要判斷一個元素是否在一個集合中总处。比如在字處理軟件中,需要檢查一個英語...
    jackcooper閱讀 837評論 0 4
  • 畚箕běn jī 用木睛蛛,竹鹦马,鐵片做成的撮垃圾胧谈,糧食等的器具 瘊hóu 瘊子 皮膚上長的小瘤子 柞木 zuò 洇yī...
    藍(lán)道閱讀 114評論 0 0