如何快速判斷某 URL 是否在 20 億的網(wǎng)址 URL 集合中统刮?

原文地址:https://mp.weixin.qq.com/s/ZpXqneKmV5eAlLq1VpueSQ

假設(shè)遇到這樣一個問題:一個網(wǎng)站有 20 億 url 存在一個黑名單中,這個黑名單要怎么存污抬?若此時隨便輸入一個 url汞贸,你如何快速判斷該 url 是否在這個黑名單中?并且需在給定內(nèi)存空間(比如:500M)內(nèi)快速判斷出印机。

可能很多人首先想到的會是使用 HashSet矢腻,因?yàn)?HashSet基于 HashMap,理論上時間復(fù)雜度為:O(1)射赛。達(dá)到了快速的目的多柑,但是空間復(fù)雜度呢?URL字符串通過Hash得到一個Integer的值楣责,Integer占4個字節(jié)竣灌,那20億個URL理論上需要:20億*4/1024/1024/1024=7.45G的內(nèi)存,不滿足空間復(fù)雜度的要求秆麸。

這里就引出本文要介紹的“布隆過濾器”初嘹。

何為布隆過濾器



百科上對布隆過濾器的介紹是這樣的:

布隆過濾器(Bloom Filter)是1970年由布隆提出的。它實(shí)際上是一個很長的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)沮趣。布隆過濾器可以用于檢索一個元素是否在一個集合中屯烦。它的優(yōu)點(diǎn)是空間效率和查詢時間都比一般的算法要好的多,缺點(diǎn)是有一定的誤識別率和刪除困難兔毒。
是不是描述的比較抽象漫贞?那就直接了解其原理吧!

還是以上面的例子為例:
哈希算法得出的Integer的哈希值最大為:Integer.MAX_VALUE=2147483647育叁,意思就是任何一個URL的哈希都會在0~2147483647之間迅脐。

那么可以定義一個2147483647長度的byte數(shù)組,用來存儲集合所有可能的值豪嗽。為了存儲這個byte數(shù)組谴蔑,系統(tǒng)只需要:2147483647/8/1024/1024=256M豌骏。

比如:某個URL(X)的哈希是2,那么落到這個byte數(shù)組在第二位上就是1隐锭,這個byte數(shù)組將是:000….00000010窃躲,重復(fù)的,將這20億個數(shù)全部哈希并落到byte數(shù)組中钦睡。

判斷邏輯:

如果byte數(shù)組上的第二位是1蒂窒,那么這個URL(X)可能存在。為什么是可能荞怒?因?yàn)橛锌赡芷渌黆RL因哈希碰撞哈希出來的也是2洒琢,這就是誤判。

但是如果這個byte數(shù)組上的第二位是0褐桌,那么這個URL(X)就一定不存在集合中衰抑。

多次哈希:



為了減少因哈希碰撞導(dǎo)致的誤判概率,可以對這個URL(X)用不同的哈希算法進(jìn)行N次哈希荧嵌,得出N個哈希值呛踊,落到這個byte數(shù)組上,如果這N個位置沒有都為1啦撮,那么這個URL(X)就一定不存在集合中谭网。

Guava的BloomFilter



Guava框架提供了布隆過濾器的具體實(shí)現(xiàn):BloomFilter,使得開發(fā)不用再自己寫一套算法的實(shí)現(xiàn)赃春。

創(chuàng)建BloomFilter

BloomFilter提供了幾個重載的靜態(tài) create方法來創(chuàng)建實(shí)例:

public static <T> BloomFilter<T> create(Funnel<? super T> funnel, int expectedInsertions, double fpp);
public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions, double fpp);
public static <T> BloomFilter<T> create(Funnel<? super T> funnel, int expectedInsertions);
public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions);

最終還是調(diào)用:

static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions, double fpp, Strategy strategy);
// 參數(shù)含義:
// funnel 指定布隆過濾器中存的是什么類型的數(shù)據(jù)蜻底,有:IntegerFunnel,LongFunnel聘鳞,StringCharsetFunnel。
// expectedInsertions 預(yù)期需要存儲的數(shù)據(jù)量
// fpp 誤判率要拂,默認(rèn)是0.03抠璃。

BloomFilter里byte數(shù)組的空間大小由 expectedInsertions, fpp參數(shù)決定脱惰,見方法:

static long optimalNumOfBits(long n, double p) {
    if (p == 0) {
        p = Double.MIN_VALUE;
    }
    return (long) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
}

真正的byte數(shù)組維護(hù)在類:BitArray中搏嗡。

使用:

最后通過:putmightContain方法,添加元素和判斷元素是否存在拉一。

算法特點(diǎn)

  1. 因使用哈希判斷采盒,時間效率很高∥等螅空間效率也是其一大優(yōu)勢磅氨。
  2. 有誤判的可能,需針對具體場景使用嫡纠。
  3. 因?yàn)闊o法分辨哈希碰撞烦租,所以不是很好做刪除操作延赌。

使用場景

  1. 黑名單
  2. URL去重
  3. 單詞拼寫檢查
  4. Key-Value緩存系統(tǒng)的Key校驗(yàn)
  5. ID校驗(yàn),比如訂單系統(tǒng)查詢某個訂單ID是否存在叉橱,如果不存在就直接返回挫以。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市窃祝,隨后出現(xiàn)的幾起案子掐松,更是在濱河造成了極大的恐慌,老刑警劉巖粪小,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件大磺,死亡現(xiàn)場離奇詭異,居然都是意外死亡糕再,警方通過查閱死者的電腦和手機(jī)量没,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來突想,“玉大人殴蹄,你說我怎么就攤上這事』#” “怎么了袭灯?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绑嘹。 經(jīng)常有香客問我稽荧,道長,這世上最難降的妖魔是什么工腋? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任姨丈,我火速辦了婚禮,結(jié)果婚禮上擅腰,老公的妹妹穿的比我還像新娘蟋恬。我一直安慰自己,他們只是感情好趁冈,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布歼争。 她就那樣靜靜地躺著,像睡著了一般渗勘。 火紅的嫁衣襯著肌膚如雪沐绒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天旺坠,我揣著相機(jī)與錄音乔遮,去河邊找鬼。 笑死取刃,一個胖子當(dāng)著我的面吹牛申眼,可吹牛的內(nèi)容都是我干的瞒津。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼括尸,長吁一口氣:“原來是場噩夢啊……” “哼巷蚪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起濒翻,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤屁柏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后有送,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淌喻,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年雀摘,在試婚紗的時候發(fā)現(xiàn)自己被綠了裸删。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡阵赠,死狀恐怖涯塔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情清蚀,我是刑警寧澤匕荸,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站枷邪,受9級特大地震影響榛搔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜东揣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一践惑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嘶卧,春花似錦童本、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绑蔫。三九已至运沦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間配深,已是汗流浹背携添。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留篓叶,地道東北人烈掠。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓羞秤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親左敌。 傳聞我的和親對象是個殘疾皇子瘾蛋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360

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