Java實現(xiàn)布隆過濾器

記得前段時間的文章么?redis使用位圖法記錄在線用戶的狀態(tài)孤里,還是需要自己實現(xiàn)一個IM在線用戶狀態(tài)的記錄捌袜,今天來講講另一方案,布隆過濾器

布隆過濾器

在日常生活工作弄唧,我們會經(jīng)常遇到這的場景霍衫,從一個Excel里面檢索一個信息在不在Excel表中,還記得被CTRL+F支配的恐懼么澄干,不扯了柠傍,軟件開發(fā)中惧笛,一般會使用散列表來實現(xiàn),Hash Table也叫哈希表静檬,哈希表的優(yōu)點是快速準(zhǔn)確并级,缺點是浪費儲存空間侮腹,我們這個場景父阻,儲存登錄的userId到哈希表,當(dāng)用戶規(guī)模十分巨大的時候履婉,哈希表的儲存效率低的問題就顯示出來了斟览,今天介紹一種數(shù)學(xué)工具:布隆過濾器,它只需要哈希表1/8到1/4的大小就能解決同樣的問題已烤。

背書中

布隆過濾器(Bloom Filter)是由伯頓·布隆(Burton Bloom)于1970年提出來的稍计,它實際上是一個很長的二進制向量和一系列隨機映射函數(shù)裕循。

原理

使用我們這個場景剥哑,來講原理吧,假設(shè)我們的個人網(wǎng)站同時在線人數(shù)達(dá)到1億(意淫一下)抢埋,要存儲這一億人的在線狀態(tài)督暂,先構(gòu)建一個16億比特位即兩億字節(jié)的向量逻翁,然后把這16億個比特位都記為0。對于每一個登錄用的userId酷愧,使用8個不同的算法產(chǎn)出8個不同信息指紋缠诅,在用一個算法把這8個信息隱身到這16億個比特位的8個位置上,把這8個位置都設(shè)置成1士败,這樣就構(gòu)建成了一個記錄一億用戶在線狀態(tài)的布隆過濾器褥伴。


1億在線用戶的布隆過濾器

檢索就是同樣的原理重慢,使用相同的算法對要檢索的userId產(chǎn)生8個信息指紋似踱,然后在看這八個信息指紋在這16億比特位對應(yīng)的值是否為1志衣,都為1就說明這個userId在線猛们,下面就用java代碼來實現(xiàn)一個布隆過濾器弯淘。

Java實現(xiàn)布隆過濾器

先實現(xiàn)一個簡單的布隆過濾器

package edu.se;

import java.util.BitSet;

/**
 * @author ZhaoWeinan
 * @date 2018/10/28
 * @description
 */
public class BloomFileter {

    //使用加法hash算法,所以定義了一個8個元素的質(zhì)數(shù)數(shù)組
    private static final int[] primes = new int[]{2, 3, 5, 7, 11, 13, 17, 19};
    //用八個不同的質(zhì)數(shù)假勿,相當(dāng)于構(gòu)建8個不同算法
    private Hash[] hashList = new Hash[primes.length];
    //創(chuàng)建一個長度為10億的比特位
    private BitSet bits = new BitSet(256 << 22);

    public BloomFileter() {
        for (int i = 0; i < primes.length; i++) {
            //使用8個質(zhì)數(shù)态鳖,創(chuàng)建八種算法
            hashList[i] = new Hash(primes[i]);
        }
    }

    //添加元素
    public void add(String value) {
        for (Hash f : hashList) {
            //算出8個信息指紋浆竭,對應(yīng)到2的32次方個比特位上
            bits.set(f.hash(value), true);
        }
    }

    //判斷是否在布隆過濾器中
    public boolean contains(String value) {
        if (value == null) {
            return false;
        }
        boolean ret = true;
        for (Hash f : hashList) {
            //查看8個比特位上的值
            ret = ret && bits.get(f.hash(value));
        }
        return ret;
    }

    //加法hash算法
    public static class Hash {

        private int prime;

        public Hash(int prime) {
            this.prime = prime;
        }

        public int hash(String key) {
            int hash, i;
            for (hash = key.length(), i = 0; i < key.length(); i++) {
                hash += key.charAt(i);
            }
            return (hash % prime);
        }
    }

    public static void main(String[] args) {

        BloomFileter bloomFileter = new BloomFileter();
        System.out.println(bloomFileter.contains("5324512515"));
        bloomFileter.add("5324512515");

        //維護1億個在線用戶
        for (int i = 1 ; i < 100000000 ; i ++){
            bloomFileter.add(String.valueOf(i));
        }

        long begin = System.currentTimeMillis();
        System.out.println(begin);
        System.out.println(bloomFileter.contains("5324512515"));
        long end = System.currentTimeMillis();
        System.out.println(end);
        System.out.println("判斷5324512515是否在線使用了:" + (begin - end));
    }
}

這段代碼是構(gòu)建了一個10億位的bitSet邦泄,然后把一億個userId加入到了我們的布隆過濾器中顺囊,最近判斷5324512515這個userId是否登錄,打出代碼的執(zhí)行時間


維護了1億個userId以后檢索5324512515是否登錄诚亚,代碼執(zhí)行時間很短

在讓我們來看看內(nèi)存占用的情況


jvm整個的內(nèi)存情況

再來看看BloomFileter這個類的實例站宗,就占用了100多MB
實例的大小

看來布隆過濾器對于儲存的效率確實很高

布隆過濾器的誤識別問題

布隆過濾器的好處在于快速硅瞧、省空間份乒,但是有一定的誤識別率恕汇,這個概率很小腕唧,要計算出現(xiàn)誤識別的概率并不難,下面貼一段書上的話
假定布隆過濾器有m比特瘾英,里面有n個元素枣接,每個元素對應(yīng)k個信息指紋的hash函數(shù),在這個布隆過濾器插入一個元素缺谴,那么比特位被設(shè)置成1的概率為1/m但惶,它依然為0的概率為1-1/m,那么k個哈希函數(shù)都沒有把他設(shè)置成1的概率為1-1/m的k次方,一個比特在插入了n個元素后膀曾,被設(shè)置為1的概率為1減1-1/m的kn次方,最后書上給出了一個公式添谊,在這里就不貼了财喳,就貼一個表吧,是m/n比值不同斩狱,以及K分別為不同的值得情況下的假陽性概率:


書上的表耳高,直接拍下來的
書上的表,直接拍下來的

布隆過濾器就為大家說到這里所踊,歡迎大家來交流泌枪,指出文中一些說錯的地方,讓我加深認(rèn)識秕岛。
最近開了一個微信公眾號畴蒲,IT知識貓攒驰,歡迎大家來投稿交流。
謝謝大家!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞬逊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子箩张,更是在濱河造成了極大的恐慌堕伪,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诈皿,死亡現(xiàn)場離奇詭異林束,居然都是意外死亡,警方通過查閱死者的電腦和手機稽亏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門壶冒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人截歉,你說我怎么就攤上這事胖腾。” “怎么了瘪松?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵咸作,是天一觀的道長。 經(jīng)常有香客問我宵睦,道長记罚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任壳嚎,我火速辦了婚禮桐智,結(jié)果婚禮上末早,老公的妹妹穿的比我還像新娘。我一直安慰自己说庭,他們只是感情好然磷,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著刊驴,像睡著了一般样屠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缺脉,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天痪欲,我揣著相機與錄音,去河邊找鬼攻礼。 笑死业踢,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的礁扮。 我是一名探鬼主播知举,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼太伊!你這毒婦竟也來了雇锡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤僚焦,失蹤者是張志新(化名)和其女友劉穎锰提,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芳悲,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡立肘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了名扛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谅年。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖肮韧,靈堂內(nèi)的尸體忽然破棺而出融蹂,到底是詐尸還是另有隱情,我是刑警寧澤弄企,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布超燃,位于F島的核電站,受9級特大地震影響桩蓉,放射性物質(zhì)發(fā)生泄漏淋纲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一院究、第九天 我趴在偏房一處隱蔽的房頂上張望洽瞬。 院中可真熱鬧,春花似錦业汰、人聲如沸伙窃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽为障。三九已至,卻和暖如春放祟,著一層夾襖步出監(jiān)牢的瞬間鳍怨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工跪妥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鞋喇,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓眉撵,卻偏偏與公主長得像侦香,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子纽疟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

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