Redis 布隆過濾器

一、布隆過濾器

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

一、數據結構

布隆過濾器是一個BIT數組,本質上是一個數據,因此能夠根據下標快速找數據linux

image

二、哈希映射

一、布隆須要記錄見過的數據,這裏的記錄須要經過hash函數對數據進行hash操做,獲得數組下標並存儲在BIT 數組裏記爲1。這樣的記錄一個數據只佔用1BIT空間git

二、判斷是否存在時:給布隆過濾器一個數據,進行hash獲得下標,從BIT數組裏取數據若是是1 則說明數據存在,若是是0 說明不存在github

三、精確度

hash算法存在碰撞的可能,因此不一樣的數據可能hash爲一個下標數據,故爲了提升精確度就須要 使用多個hash 算法標記一個數據,和增大BIT數組的大小redis

也是由於如此,布隆過濾器判斷爲【數據存在】 可能數據並不存在,可是若是判斷爲【數據不存在】那麼數據就必定是不存在的。算法

四、例子

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

哈希函數返回 一、四、7服務器

image.數據結構

咱們如今再存一個值 「tencent」,若是哈希函數返回 三、四、8 的話,圖繼續變爲:函數

如下 4 位置發生了hash碰撞

image

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

顯然,太小的布隆過濾器很快全部的 bit 位均爲 1,那麼查詢任何值都會返回「可能存在」,起不到過濾的目的了。布隆過濾器的長度會直接影響誤報率,布隆過濾器越長其誤報率越小。

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

image

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

六、不支持刪除

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

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

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

因爲hash碰撞問題,布隆過濾器不能準確判斷數據是否存在,就不能隨意刪除。其次計數器的迴繞問題也須要考慮。

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

一、下載:

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

下載ZIP  文件,上傳到linux

RedisBloom-master.zip

二、解壓編譯

  命令:

  unzip RedisBloom-master.zip

  cd RedisBloom-master

  make

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

 

三、啓動redis 時加載該模塊

  命令:

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

三、驗證

一、連接redis

  命令:

  redis-cli –a zjl123

 

二、測試布隆過濾

  命令:

  bf.add zjl  123

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

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

三、準確率

  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 設置稍大一點也無傷大雅。

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

文章的總體閱讀量不會由於這 點誤判率就帶來巨大的改變。

四、項目中使用

一、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);

二、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));
}

三、自已實現布隆過濾器

java 有bitSet數組,hash函數能夠本身手動實現

本身手寫是能夠實現布隆過濾器的,在此不作研究。

相關文章
相關標籤/搜索