內容參考:https://www.jianshu.com/p/2104d11ee0a2java
一、數據結構
布隆過濾器是一個BIT數組,本質上是一個數據,因此能夠根據下標快速找數據linux
二、哈希映射
一、布隆須要記錄見過的數據,這裏的記錄須要經過hash函數對數據進行hash操做,獲得數組下標並存儲在BIT 數組裏記爲1。這樣的記錄一個數據只佔用1BIT空間git
二、判斷是否存在時:給布隆過濾器一個數據,進行hash獲得下標,從BIT數組裏取數據若是是1 則說明數據存在,若是是0 說明不存在github
三、精確度
hash算法存在碰撞的可能,因此不一樣的數據可能hash爲一個下標數據,故爲了提升精確度就須要 使用多個hash 算法標記一個數據,和增大BIT數組的大小redis
也是由於如此,布隆過濾器判斷爲【數據存在】 可能數據並不存在,可是若是判斷爲【數據不存在】那麼數據就必定是不存在的。算法
四、例子
下圖映射 baidu字樣到布隆過濾器中,用了三個不一樣的hash函數 3BIT 判斷一個數據,BIT數組大小爲8數組
哈希函數返回 一、四、7服務器
咱們如今再存一個值 「tencent」,若是哈希函數返回 三、四、8 的話,圖繼續變爲:函數
如下 4 位置發生了hash碰撞
五、如何選擇哈希函數個數和布隆過濾器長度
顯然,太小的布隆過濾器很快全部的 bit 位均爲 1,那麼查詢任何值都會返回「可能存在」,起不到過濾的目的了。布隆過濾器的長度會直接影響誤報率,布隆過濾器越長其誤報率越小。
另外,哈希函數的個數也須要權衡,個數越多則布隆過濾器 bit 位置位 1 的速度越快,且布隆過濾器的效率越低;可是若是太少的話,那咱們的誤報率會變高。
k 爲哈希函數個數,m 爲布隆過濾器長度,n 爲插入的元素個數,p 爲誤報率。
六、不支持刪除
布隆過濾器只能插入數據判斷是否存在,不能刪除,並且只能保證【不存在】判斷絕對準確
以上不難看出若是給數組的每一個BIT位上加一個計數器,插入的時候+1 刪除的時候 –1 就能夠實現刪除。
可是加計數器的實現是有問題的:
因爲hash碰撞問題,布隆過濾器不能準確判斷數據是否存在,就不能隨意刪除。其次計數器的迴繞問題也須要考慮。
一、下載:
地址: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函數能夠本身手動實現
本身手寫是能夠實現布隆過濾器的,在此不作研究。