Redis 布隆過濾器


1、布隆過濾器

內容參考:https://www.jianshu.com/p/2104d11ee0a2

1、數據結構

布隆過濾器是一個BIT數組,本質上是一個數據,所以可以根據下標快速找數據

image

2、哈希映射

1、布隆需要記錄見過的數據,這里的記錄需要通過hash函數對數據進行hash操作,得到數組下標並存儲在BIT 數組里記為1。這樣的記錄一個數據只占用1BIT空間

2、判斷是否存在時:給布隆過濾器一個數據,進行hash得到下標,從BIT數組里取數據如果是1 則說明數據存在,如果是0 說明不存在

3、精確度

hash算法存在碰撞的可能,所以不同的數據可能hash為一個下標數據,故為了提高精確度就需要 使用多個hash 算法標記一個數據,和增大BIT數組的大小

也是因為如此,布隆過濾器判斷為【數據存在】 可能數據並不存在,但是如果判斷為【數據不存在】那么數據就一定是不存在的。

4、例子

下圖映射  baidu字樣到布隆過濾器中,用了三個不同的hash函數 3BIT 判斷一個數據,BIT數組大小為8

哈希函數返回 1、4、7

image.

我們現在再存一個值 “tencent”,如果哈希函數返回 3、4、8 的話,圖繼續變為:

以下 4 位置發生了hash碰撞

image

5、如何選擇哈希函數個數和布隆過濾器長度

顯然,過小的布隆過濾器很快所有的 bit 位均為 1,那么查詢任何值都會返回“可能存在”,起不到過濾的目的了。布隆過濾器的長度會直接影響誤報率,布隆過濾器越長其誤報率越小。

另外,哈希函數的個數也需要權衡,個數越多則布隆過濾器 bit 位置位 1 的速度越快,且布隆過濾器的效率越低;但是如果太少的話,那我們的誤報率會變高。

image

k 為哈希函數個數,m 為布隆過濾器長度,n 為插入的元素個數,p 為誤報率。

6、不支持刪除

布隆過濾器只能插入數據判斷是否存在,不能刪除,而且只能保證【不存在】判斷絕對准確

以上不難看出如果給數組的每個BIT位上加一個計數器,插入的時候+1  刪除的時候 –1 就可以實現刪除。

但是加計數器的實現是有問題的:

由於hash碰撞問題,布隆過濾器不能准確判斷數據是否存在,就不能隨意刪除。其次計數器的回繞問題也需要考慮。

2、給redis安裝布隆過濾器模塊

1、下載:

地址:https://github.com/RedisBloom/RedisBloom

下載ZIP  文件,上傳到linux

RedisBloom-master.zip

2、解壓編譯

  命令:

  unzip RedisBloom-master.zip

  cd RedisBloom-master

  make

  掃行完以上命令 后文件夾內生成一個文件名為:redisbloom.so

 

3、啟動redis 時加載該模塊

  命令:

 redis-server redis-6381.conf --loadmodule /zjl/software/RedisBloom-master/redisbloom.so 

3、驗證

1、鏈接redis

  命令:

  redis-cli –a zjl123

 

2、測試布隆過濾

  命令:

  bf.add zjl  123

  bf.exists zjl  123   #返回  1 ,說明存在值

  bf.exists zjl  321   #返回  0, 說明不存在該值

3、准確率

  Redis中有一個命令可以來設置布隆過濾器的准確率:

  bf.reserve zjl  0.01 100

 

bf.reserve 有三個參數,分別是 key, error_rate 和 initial_size 。

錯誤率越低,需要的空間越大。

initial_size 參數表示預計放 入的元素數量,當實際數量超出這個數值時,誤判率會上升。

 

所以需要提前設置一個較大的數值避免超出導致誤判率升高。

如果不使用 bf.reserve,默認的 error_rate 是 0.01,默認的 initial_size 是 100。

 

布隆過濾器的 initial_size 估計的過大,會浪費存儲空間,估計的過小,就會 影響准確率,

用戶在使用之前一定要盡可能地精確估計好元素數量,還需要加上 一定的冗余空間以避免實際元素可能會意外高出估計值很多。

 

布隆過濾器的 error_rate 越小,需要的存儲空間就越大,對於不需要過於精確 的場合, error_rate 設置稍大一點也無傷大雅。

比如在新聞去重上而言,誤判 率高一點只會讓小部分文章不能讓合適的人看到,

文章的整體閱讀量不會因為這 點誤判率就帶來巨大的改變。

4、項目中使用

1、redis布隆過濾器

沒有找到jedis 支持bloom過濾器 命令的版本,只找到了另外一個JAR包的支持,但是也不太好用,沒弄明白如何添加密碼連接

引入包

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

JAR包里只有三個類,對連接方式 和 數據類型 的支持都不夠

代碼:

Client client = new Client(redisProperties.getHost(), redisProperties.getPort(), 10000, 100);
client.add("zjl", "123");
boolean zjl = client.exists("zjl", "123");
System.out.println(zjl);

2、Guava中的BloomFilter

google的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));
}

3、自已實現布隆過濾器

java 有bitSet數組,hash函數可以自己手動實現

自己手寫是可以實現布隆過濾器的,在此不做研究。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM