最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布隆過(guò)濾器

 更新時(shí)間:2023年12月28日 10:13:34   作者:一個(gè)風(fēng)輕云淡  
這篇文章主要介紹了用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布隆過(guò)濾器,布隆過(guò)濾器是1970年由布隆提出的,它實(shí)際上是一個(gè)很長(zhǎng)的二進(jìn)制向量和一系列隨機(jī)映射函數(shù),布隆過(guò)濾器可以用于檢索一個(gè)元素是否在一個(gè)集合中,需要的朋友可以參考下

設(shè)計(jì)初衷

在實(shí)際開(kāi)發(fā)中,會(huì)遇到很多要判斷一個(gè)元素是否在某個(gè)集合中的業(yè)務(wù)場(chǎng)景,類似于垃圾郵件的識(shí)別,惡意ip地址的訪問(wèn),緩存穿透等情況。類似于緩存穿透這種情況,有許多的解決方法,如:redis存儲(chǔ)null值等,而對(duì)于垃圾郵件的識(shí)別,惡意ip地址的訪問(wèn),我們也可以直接用 HashMap 去存儲(chǔ)惡意ip地址以及垃圾郵件,然后每次訪問(wèn)時(shí)去檢索一下對(duì)應(yīng)集合中是否有相同數(shù)據(jù)。

但是對(duì)于大數(shù)據(jù)量的項(xiàng)目,如,垃圾郵件出現(xiàn)有十幾二十萬(wàn),惡意ip地址出現(xiàn)有上百萬(wàn),或者從幾十億電話中檢索出指定的電話是否在等操作,那么這十幾億的數(shù)據(jù)就會(huì)占據(jù)大幾G的空間,這個(gè)時(shí)候就可以考慮一下布隆過(guò)濾器了。

?網(wǎng)頁(yè)URL的去重,垃圾郵件的判別,集合重復(fù)元素的判別,查詢加速(比如基于key-value的存儲(chǔ)系統(tǒng))、數(shù)據(jù)庫(kù)防止查詢擊穿, 使用BloomFilter來(lái)減少不存在的行或列的磁盤查找 

布隆過(guò)濾器定義 

布隆過(guò)濾器(Bloom Filter)是1970年由布隆提出的。它實(shí)際上是一個(gè)很長(zhǎng)的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)。布隆過(guò)濾器可以用于檢索一個(gè)元素是否在一個(gè)集合中。

 由一個(gè)初始值為零的bit數(shù)組和多個(gè)哈希函數(shù)構(gòu)成,用來(lái)快速判斷集合中是否存在某個(gè)元素。 

布隆過(guò)濾器可以用于查詢一個(gè)元素是否存在于一個(gè)集合當(dāng)中,查詢結(jié)果為以下二者之一:

  • 這個(gè)元素可能存在于這個(gè)集合當(dāng)中。
  • 這個(gè)元素一定不存在于這個(gè)集合當(dāng)中。

進(jìn)行數(shù)據(jù)插入時(shí):使用多個(gè)hash函數(shù)對(duì)key進(jìn)行hash運(yùn)算得到多個(gè)整數(shù)索引值,對(duì)位數(shù)組長(zhǎng)度進(jìn)行取模運(yùn)算得到多個(gè)位置,每個(gè)hash函數(shù)都會(huì)得到一個(gè)不同的位置,將這幾個(gè)位置都置1就完成了add操作。 

進(jìn)行數(shù)據(jù)查詢時(shí):將這個(gè)key的多個(gè)位置上的值取出來(lái),只要有其中一位是零就表示這個(gè)key不存在,但如果都是1,則不一定存在對(duì)應(yīng)的key。(也就是有,不一定有,無(wú),就一定無(wú)) 

java實(shí)現(xiàn) 

基于上面理解介紹 ,我們現(xiàn)在基于java手?jǐn)]一個(gè)簡(jiǎn)單布隆過(guò)濾器

  • bitSize:位圖的大小,即位圖中的位數(shù)。
  • bits:位圖對(duì)象,用于存儲(chǔ)元素的映射結(jié)果。
  • seeds:用于哈希函數(shù)的種子數(shù)組。
  • hashIterations:哈希函數(shù)的迭代次數(shù)。
class BloomFilter {
    private int bitSize;
    private BitSet bits;
    private int[] seeds;
    private int hashIterations;
    /**
     * @param size          預(yù)計(jì)元素?cái)?shù)量
     * @param falsePositive 期望誤判率
     */
    public BloomFilter(int size, double falsePositive) {
        this.bitSize = (int) Math.ceil((size * Math.log(falsePositive)) / Math.log(1.0 / (Math.pow(2.0, Math.log(2.0)))));
        this.bits = new BitSet(bitSize);
        this.hashIterations = (int) Math.round(Math.log(2.0) * bitSize / size);
        this.seeds = new int[hashIterations];
        for (int i = 0; i < hashIterations; i++) {
            seeds[i] = i + 1;
        }
    }
    /**
     * 添加一個(gè)元素
     *
     * @param element 元素
     */
    public void add(String element) {
        for (int seed : seeds) {
            int hash = MurmurHash.hash(element.getBytes(), seed);
            bits.set(Math.abs(hash % bitSize), true);
        }
    }
    /**
     * 判斷一個(gè)元素是否存在
     *
     * @param element 元素
     * @return 是否存在
     */
    public boolean contains(String element) {
        for (int seed : seeds) {
            int hash = MurmurHash.hash(element.getBytes(), seed);
            if (!bits.get(Math.abs(hash % bitSize))) {
                return false;
            }
        }
        return true;
    }
    /**
     * MurmurHash算法
     */
    static class MurmurHash {
        public static int hash(byte[] data, int seed) {
            int m = 0x5bd1e995;
            int r = 24;
            int h = seed ^ data.length;
            int len = data.length;
            int pos = 0;
            while (len >= 4) {
                int k = data[pos] & 0xff;
                k |= (data[pos + 1] & 0xff) << 8;
                k |= (data[pos + 2] & 0xff) << 16;
                k |= (data[pos + 3] & 0xff) << 24;
                k *= m;
                k ^= k >>> r;
                k *= m;
                h *= m;
                h ^= k;
                pos += 4;
                len -= 4;
            }
            switch (len) {
                case 3:
                    h ^= (data[pos + 2] & 0xff) << 16;
                case 2:
                    h ^= (data[pos + 1] & 0xff) << 8;
                case 1:
                    h ^= data[pos] & 0xff;
                    h *= m;
            }
            h ^= h >>> 13;
            h *= m;
            h ^= h >>> 15;
            return h;
        }
    }
}

BloomFilter 類表示布隆過(guò)濾器,提供了 add 和 contains 方法用于添加元素和判斷元素是否存在。

在構(gòu)造函數(shù)中,根據(jù)預(yù)計(jì)元素?cái)?shù)量和期望誤判率計(jì)算出位數(shù)組的大小、哈希函數(shù)個(gè)數(shù)和哈希種子。

添加元素時(shí),使用多個(gè)哈希函數(shù)對(duì)元素進(jìn)行哈希,并將對(duì)應(yīng)的位設(shè)置為 1;判斷元素是否存在時(shí),同樣使用多個(gè)哈希函數(shù)對(duì)元素進(jìn)行哈希,并檢查對(duì)應(yīng)的位是否都為 1。

注意,上述代碼中的哈希函數(shù)使用了 MurmurHash 算法,該算法的性能比較高,適合用于布隆過(guò)濾器中。同時(shí),布隆過(guò)濾器的誤判率隨著元素?cái)?shù)量的增加而增加,因此在實(shí)際使用中需要根據(jù)誤判率和元素?cái)?shù)量的情況來(lái)選擇合適的參數(shù)。

測(cè)試

public class test {
    public static void main(String[] args) {
        BloomFilter bloomFilter = new BloomFilter(1000,0.01);
        bloomFilter.add("xyz");
        boolean xyz = bloomFilter.contains("xyz");
        System.out.println("xyz查詢結(jié)果:"+xyz);
        boolean xyzk = bloomFilter.contains("xyzk");
        System.out.println("xyz查詢結(jié)果:"+xyzk);
    }
}

測(cè)試結(jié)果:

xyz查詢結(jié)果:true

xyz查詢結(jié)果:false 

到此這篇關(guān)于用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布隆過(guò)濾器的文章就介紹到這了,更多相關(guān)Java實(shí)現(xiàn)布隆過(guò)濾器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring AOP的幾種實(shí)現(xiàn)方式總結(jié)

    Spring AOP的幾種實(shí)現(xiàn)方式總結(jié)

    本篇文章主要介紹了Spring AOP的幾種實(shí)現(xiàn)方式總結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • idea中創(chuàng)建新類時(shí)自動(dòng)添加注釋的實(shí)現(xiàn)

    idea中創(chuàng)建新類時(shí)自動(dòng)添加注釋的實(shí)現(xiàn)

    在每次使用idea創(chuàng)建一個(gè)新類時(shí),過(guò)了一段時(shí)間發(fā)現(xiàn)看不懂這個(gè)類是用來(lái)干嘛的,為了解決這個(gè)問(wèn)題,我們可以設(shè)置在創(chuàng)建一個(gè)新類時(shí)自動(dòng)添加注釋,幫助我們理解這個(gè)類的用處,本文主要介紹了在idea中創(chuàng)建新類時(shí)自動(dòng)添加注釋的實(shí)現(xiàn),感興趣的可以了解一下
    2025-03-03
  • Spring Data JPA 設(shè)置字段默認(rèn)值方式

    Spring Data JPA 設(shè)置字段默認(rèn)值方式

    這篇文章主要介紹了Spring Data JPA設(shè)置字段默認(rèn)值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 分析ZooKeeper分布式鎖的實(shí)現(xiàn)

    分析ZooKeeper分布式鎖的實(shí)現(xiàn)

    在分布式的情況下,sychornized 和 Lock 已經(jīng)不能滿足我們的要求了,那么就需要使用第三方的鎖了,這里我們就使用 ZooKeeper 來(lái)實(shí)現(xiàn)一個(gè)分布式鎖
    2021-06-06
  • IDEA查看所有的斷點(diǎn)(Breakpoints)并關(guān)閉的方式

    IDEA查看所有的斷點(diǎn)(Breakpoints)并關(guān)閉的方式

    我們?cè)谑褂肐DEA開(kāi)發(fā)Java應(yīng)用時(shí),基本上都需要進(jìn)行打斷點(diǎn)的操作,這方便我們排查BUG,也方便我們查看設(shè)計(jì)的是否正確,不過(guò)有時(shí)候,我們不希望進(jìn)入斷點(diǎn),所以我們需要快速關(guān)閉所有斷點(diǎn),故本文給大家介紹了IDEA查看所有的斷點(diǎn)(Breakpoints)并關(guān)閉的方式
    2024-10-10
  • Java中通過(guò)Class類獲取Class對(duì)象的方法詳解

    Java中通過(guò)Class類獲取Class對(duì)象的方法詳解

    這篇文章主要給大家介紹了關(guān)于Java中通過(guò)Class類獲取Class對(duì)象的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • 基于ThreadLocal 的用法及內(nèi)存泄露(內(nèi)存溢出)

    基于ThreadLocal 的用法及內(nèi)存泄露(內(nèi)存溢出)

    這篇文章主要介紹了基于ThreadLocal 的用法及內(nèi)存泄露(內(nèi)存溢出),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java中StringUtils工具類的一些用法實(shí)例

    Java中StringUtils工具類的一些用法實(shí)例

    這篇文章主要介紹了Java中StringUtils工具類的一些用法實(shí)例,本文著重講解了isEmpty和isBlank方法的使用,另外也講解了trim、strip等方法的使用實(shí)例,需要的朋友可以參考下
    2015-06-06
  • zookeeper服務(wù)優(yōu)化的一些建議

    zookeeper服務(wù)優(yōu)化的一些建議

    今天小編就為大家分享一篇關(guān)于zookeeper服務(wù)優(yōu)化的一些建議,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03
  • Java中操作Redis的詳細(xì)方法

    Java中操作Redis的詳細(xì)方法

    基于Jedis實(shí)現(xiàn)對(duì)redis中字符串的操作,文中通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),包括連接池JedisPool應(yīng)用的實(shí)例代碼,對(duì)Java操作Redis的相關(guān)知識(shí)感興趣的朋友一起看看吧
    2021-11-11

最新評(píng)論

高邑县| 墨竹工卡县| 屏东市| 宣化县| 内江市| 万荣县| 承德县| 米林县| 潞城市| 定西市| 凤庆县| 珠海市| 丰城市| 大同市| 读书| 冕宁县| 泸溪县| 方正县| 六安市| 拜城县| 新野县| 涿州市| 北流市| 开鲁县| 新蔡县| 富川| 潜江市| 松桃| 庆云县| 平凉市| 怀宁县| 林州市| 都匀市| 肥东县| 金华市| 红安县| 会理县| 普格县| 麻栗坡县| 界首市| 托克托县|