日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

bloomfilter的java实现,BloomFilter(布隆过滤器)原理及实战详解

發(fā)布時(shí)間:2023/12/2 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 bloomfilter的java实现,BloomFilter(布隆过滤器)原理及实战详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

什么是 BloomFilter(布隆過濾器)

布隆過濾器(英語:Bloom Filter)是 1970 年由布隆提出的。它實(shí)際上是一個(gè)很長的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)。主要用于判斷一個(gè)元素是否在一個(gè)集合中。通常我們會(huì)遇到很多要判斷一個(gè)元素是否在某個(gè)集合中的業(yè)務(wù)場景,這個(gè)時(shí)候往往我們都是采用 Hashmap,Set 或者其他集合將數(shù)據(jù)保存起來,然后進(jìn)行對比判斷,但是如果元素很多的情況,我們?nèi)绻捎眠@種方式就會(huì)非常浪費(fèi)空間。這個(gè)時(shí)候我們就需要 BloomFilter 來幫助我們了。

BloomFilter 原理

BloomFilter 是由一個(gè)固定大小的二進(jìn)制向量或者位圖(bitmap)和一系列(通常好幾個(gè))映射函數(shù)組成的。布隆過濾器的原理是,當(dāng)一個(gè)變量被加入集合時(shí),通過 K 個(gè)映射函數(shù)將這個(gè)變量映射成位圖中的 K 個(gè)點(diǎn),把它們置為 1。查詢某個(gè)變量的時(shí)候我們只要看看這些點(diǎn)是不是都是 1 就可以大概率知道集合中有沒有它了,如果這些點(diǎn)有任何一個(gè) 0,則被查詢變量一定不在;如果都是 1,則被查詢變量很可能在。注意,這里是可能存在,不一定一定存在!這就是布隆過濾器的基本思想。

如下圖所示,字符串 “ziyou” 在經(jīng)過四個(gè)映射函數(shù)操作后在位圖上有四個(gè)點(diǎn)被設(shè)置成了 1。當(dāng)我們需要判斷 “ziyou” 字符串是否存在的時(shí)候只要在一次對字符串進(jìn)行映射函數(shù)的操作,得到四個(gè) 1 就說明 “ziyou” 是可能存在的。

為什么說是可能存在,而不是一定存在呢?那是因?yàn)橛成浜瘮?shù)本身就是散列函數(shù),散列函數(shù)是會(huì)有碰撞的,意思也就是說會(huì)存在一個(gè)字符串可能是 “ziyou01” 經(jīng)過相同的四個(gè)映射函數(shù)運(yùn)算得到的四個(gè)點(diǎn)跟 “ziyou” 是一樣的,這種情況下我們就說出現(xiàn)了誤算。另外還有可能這四個(gè)點(diǎn)位上的 1 是四個(gè)不同的變量經(jīng)過運(yùn)算后得到的,這也不能證明字符串 “ziyou” 是一定存在的,如下圖框出來的 1 也可能是字符串“張三”計(jì)算得到,同理其他幾個(gè)位置的 1 也可以是其他字符串計(jì)算得到。

1.2 特性

所以通過上面的例子我們就可以明確

一個(gè)元素如果判斷結(jié)果為存在的時(shí)候元素不一定存在,但是判斷結(jié)果為不存在的時(shí)候則一定不存在。

布隆過濾器可以添加元素,但是不能刪除元素。因?yàn)閯h掉元素會(huì)導(dǎo)致誤判率增加。

02、使用場景

2.1、網(wǎng)頁 URL 去重

我們在使用網(wǎng)頁爬蟲的時(shí)候(爬蟲需謹(jǐn)慎),往往需要記錄哪些 URL 是已經(jīng)爬取過的,哪些還是沒有爬取過,這個(gè)時(shí)候我們就可以采用 BloomFilter 來對已經(jīng)爬取過的 URL 進(jìn)行存儲(chǔ),這樣在進(jìn)行下一次爬取的時(shí)候就可以判斷出這個(gè) URL 是否爬取過。

2.2、黑白名單存儲(chǔ)

工作中經(jīng)常會(huì)有一個(gè)特性針對不同的設(shè)備或者用戶有不同的處理方式,這個(gè)時(shí)候可能會(huì)有白名單或者黑名單存在,所以根據(jù) BloomFilter 過濾器的特性,我們也可以用它來存在這些數(shù)據(jù),雖然有一定的誤算率,但是在一定程度上還是可以很好的解決這個(gè)問題的。

2.3、小結(jié)

除了上面說的兩種場景,其實(shí)還有很多場景,比如熱點(diǎn)數(shù)據(jù)訪問,垃圾郵件過濾等等,其實(shí)這些場景的統(tǒng)一特性就是要判斷某個(gè)元素是否在某個(gè)集合中,原理都是一樣的。

03、代碼實(shí)踐

3.1、自己實(shí)現(xiàn)

package com.test.pkg;

import java.util.BitSet;

/**

*

* Function:

* Author:@author ziyou

* Date:2019-10-23 23:21

* Desc:無

*/

public class BloomFilterTest {

/**

* 初始化布隆過濾器的 bitmap 大小

*/

private static final int DEFAULT_SIZE = 2 << 24;

/**

* 為了降低錯(cuò)誤率,這里選取一些數(shù)字作為基準(zhǔn)數(shù)

*/

private static final int[] seeds = {3, 5, 7, 11, 13, 31, 37, 61};

/**

* 設(shè)置 bitmap

*/

private static BitSet bitset = new BitSet(DEFAULT_SIZE);

/**

* 設(shè)置 hash 函數(shù)數(shù)量

*/

private static HashFunction[] functions = new HashFunction[seeds.length];

/**

* 添加數(shù)據(jù)

*

* @param value 需求加入的值

*/

public static void put(String value) {

if (value != null) {

for (HashFunction f : functions) {

//計(jì)算 hash 值并修改 bitmap 中相應(yīng)位置為 true

bitset.set(f.hash(value), true);

}

}

}

/**

* 判斷相應(yīng)元素是否存在

*

* @param value 需要判斷的元素

* @return 結(jié)果

*/

public static boolean check(String value) {

if (value == null) {

return false;

}

boolean ret = true;

for (HashFunction f : functions) {

ret = bitset.get(f.hash(value));

//一個(gè) hash 函數(shù)返回 false 則跳出循環(huán)

if (!ret) {

break;

}

}

return ret;

}

public static void main(String[] args) {

String value = "test";

for (int i = 0; i < seeds.length; i++) {

functions[i] = new HashFunction(DEFAULT_SIZE, seeds[i]);

}

put(value);

System.out.println(check("value"));

}

}

class HashFunction {

private int size;

private int seed;

public HashFunction(int size, int seed) {

this.size = size;

this.seed = seed;

}

public int hash(String value) {

int result = 0;

int len = value.length();

for (int i = 0; i < len; i++) {

result = seed * result + value.charAt(i);

}

int r = (size - 1) & result;

return (size - 1) & result;

}

}

上面我們自己寫了一個(gè)簡單的 BloomFilter ,通過 put 方法錄入數(shù)據(jù),通過 check 方法判斷元素是否存在,基本能實(shí)現(xiàn)功能,代碼中注釋也寫的很清楚,但是自己實(shí)現(xiàn)必定效率不高,所以下面我們看下業(yè)內(nèi)大佬幫我們已經(jīng)實(shí)現(xiàn)好的 BloomFilter。

2.4、Guava 中的 BloomFilter

package com.test.pkg;

import com.google.common.hash.BloomFilter;

import com.google.common.hash.Funnels;

/**

*

* Function:

* Author:@author ziyou

* Date:2019-10-24 00:17

* Desc:無

*/

public class BloomFilterTest02 {

public static void main(String[] args) {

BloomFilter bloomFilter = BloomFilter.create(Funnels.integerFunnel(), 100000, 0.01);

for (int i = 0; i < 100000; i++) {

bloomFilter.put(i);

}

System.out.println(bloomFilter.mightContain(1));

System.out.println(bloomFilter.mightContain(2));

System.out.println(bloomFilter.mightContain(3));

System.out.println(bloomFilter.mightContain(100001));

}

}

Guava 中已經(jīng)幫我們實(shí)現(xiàn)好了 BloomFilter 的代碼,我們只需要在使用的地方調(diào)用就好。

這里我們簡單解釋一下構(gòu)造方法中的后面兩個(gè)參數(shù),一個(gè)是預(yù)計(jì)包含的數(shù)據(jù)量,一個(gè)是允許的誤差值。代碼中會(huì)根據(jù)我們填入的這兩個(gè)值,自動(dòng)幫我們計(jì)算出數(shù)組的大小,以及需要的散列函數(shù)個(gè)數(shù),如下圖。更多詳細(xì)的內(nèi)容,讀者可以自行去查看源碼,我們這里就不介紹了。

04、總結(jié)

這篇文章給大家介紹了 BloomFilter,一個(gè)用來判斷元素是否存在與某個(gè)集合的高效方法,可以在我們?nèi)粘5墓ぷ髦羞\(yùn)用起來,結(jié)合日常工作的場景,可以進(jìn)行選擇。

原文發(fā)于:《Java極客技術(shù)》公眾號,作者:ziyou

關(guān)注公眾號:程序新視界,一個(gè)讓你軟實(shí)力、硬技術(shù)同步提升的平臺(tái)

除非注明,否則均為程序新視界原創(chuàng)文章,轉(zhuǎn)載必須以鏈接形式標(biāo)明本文鏈接

總結(jié)

以上是生活随笔為你收集整理的bloomfilter的java实现,BloomFilter(布隆过滤器)原理及实战详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。