首先,HyperLogLog與布隆過濾器都是針對大數據統計存儲應用場景下的知名算法。html
HyperLogLog是在大數據的狀況下關於數據基數的空間複雜度優化實現,布隆過濾器是在大數據狀況下關於檢索一個元素是否在一個集合中的空間複雜度優化後的實現。git
在傳統的數據量比較低的應用服務中,咱們要實現數據基數和數據是否存在分析的功能,一般是簡單的把全部數據存儲下來,直接count一下就是基數了,而直接檢索一個元素是否在一個集合中也很簡單。github
但隨着數據量的急劇增大,傳統的方式已經很難達到工程上的需求。過大的數據量不管是在存儲仍是在查詢方面都存在巨大的挑戰,不管咱們是用位存儲仍是樹結構存儲等方式來優化,都無法達到大數據時代的要求或者是性價比過低。redis
因而HyperLogLog與布隆過濾器這兩個算法就很好的派上了用場。他們的使用能夠極大的節約存儲空間,做爲代價,則是犧牲了一個小几率的準確性,這能夠很好的達到工程上的需求,對於那些要求準確度沒那麼高,但數據量巨大的需求是很是合適的。算法
HyperLogLog原理數組
最直白的解釋是,給定一個集合 S,對集合中的每個元素,咱們作一個哈希,假設生成一個 16 位的比特串,從全部生成的比特串中挑選出前面連續 0 次數最多的比特串,假設爲 0000000011010110,連續 0 的次數爲 8,所以咱們能夠估計該集合 S 的基數爲 2^9。固然單獨用這樣的單一估計偶然性較大,致使偏差較大,所以在實際的 HyperLogLog 算法中,採起分桶平均原理了來消除偏差。(這段話引用了 HyperLogLog 原理 中的描述,還有一些細節實現 感興趣可閱讀 https://blockchain.iethpay.com/hyperloglog-theory.html)函數
特色:實現犧牲了必定的準確度(在一些場景下是能夠忽略的),但卻實現了空間複雜度上的極大的壓縮,能夠說是性價比很高的。大數據
雖然基數不徹底準確,可是能夠符合,隨着數量的遞增,基數也是遞增的。優化
布隆過濾器原理插件
布隆過濾器(Bloom Filter)的核心實現是一個超大的位數組和幾個哈希函數。假設位數組的長度爲m,哈希函數的個數爲k,以上圖爲例,具體的操做流程:假設集合裏面有3個元素{x, y, z},哈希函數的個數爲3。首先將位數組進行初始化,將裏面每一個位都設置爲0。對於集合裏面的每個元素,將元素依次經過3個哈希函數進行映射,每次映射都會產生一個哈希值,這個值對應位數組上面的一個點,而後將位數組對應的位置標記爲1。查詢W元素是否存在集合中的時候,一樣的方法將W經過哈希映射到位數組上的3個點。若是3個點的其中有一個點不爲1,則能夠判斷該元素必定不存在集合中。反之,若是3個點都爲1,則該元素可能存在集合中。注意:此處不能判斷該元素是否必定存在集合中,可能存在必定的誤判率。能夠從圖中能夠看到:假設某個元素經過映射對應下標爲4,5,6這3個點。雖然這3個點都爲1,可是很明顯這3個點是不一樣元素通過哈希獲得的位置,所以這種狀況說明元素雖然不在集合中,也可能對應的都是1,這是誤判率存在的緣由。(這段話與圖片引用於 布隆過濾器(Bloom Filter)的原理和實現 中的描述,還有一些細節實現 感興趣可閱讀 http://www.javashuo.com/article/p-aenfkllo-mo.html)
特色:巧妙的使用hash算法和bitmap位存儲的方式,極大的節約了空間。
因爲主要用的是hash算法的特色,全部知足和hash算法相同的規則:當過濾器返回 true時(表示頗有可能該值是存在的),有必定機率是誤判的,便可能不存在;當過濾器返回false時(表示肯定不存在),是能夠徹底相信的。
咱們換個數據的角度來看規則:當數據添加到布隆過濾器中時,對該數據的查詢必定會返回true;當數據沒有插入過濾器時,對該數據的查詢大部分狀況返回false,但有小几率返回true,也就是誤判。
咱們知道它最終知足的規則和hash的規則是一致的,只是組合了多個hash,使用了bitmap來存儲,大大優化了存儲的空間和判斷的效率。
redis中的HyperLogLog
在redis中對HyperLogLog 的支持早在2.8.9的時候就有了。它的操做很是簡單
redis中的布隆過濾器
在redis中的布隆過濾器的支持是在redis4.0後支持插件的狀況下,經過插件的方式實現的 ,redis的布隆過濾器插件地址:https://github.com/RedisLabsModules/rebloom
它的操做也很簡單,如下爲幾個主要命令,其它命令請參考文檔 https://github.com/RedisLabsModules/rebloom/blob/master/docs/Bloom_Commands.md
BF.RESERVE {key} {error_rate} {size} 建立一個布隆過濾器 key爲redis存儲鍵值,error_rate 爲錯誤率(大於0,小於1),size爲預計存儲的數量(size是比較關鍵的,須要根據本身的需求狀況合理估計,設置過小的話會增大錯誤率,設置太大會佔用過多沒必要要的空間)
BF.ADD {key} {item} 添加值到布隆過濾器中(當過濾器不存在的時候會,會以默認值自動建立一個,建議最好提早建立好) key爲redis存儲鍵值,item爲值(如須要添加多個,請使用BF.MADD 可同時添加多個)
BF.EXISTS {key} {item} 判斷值是否存在過濾器中 true(表示極可能存在) false (表示絕對不存在)
參考文章:
https://blockchain.iethpay.com/hyperloglog-theory.html hyperloglog原理
http://www.javashuo.com/article/p-aenfkllo-mo.html 布隆過濾器原理
http://redisdoc.com/hyperloglog/index.html redis的hyperloglog的使用
https://github.com/RedisLabsModules/rebloom/blob/master/docs/Bloom_Commands.md redis的布隆過濾器的使用