摘自本人 http://irfen.me/redis-hyperloglog-intro/redis
咱們一直都知道,redis幾大經常使用數據結構,字符串、散列、列表、集合、有序集合。其實後來Redis作了不少補充,其中之一就是HyperLogLog,另外的還有GEO(地理位置),是3.2版本加的。算法
這裏咱們就來簡單介紹下HyperLogLog結構。數據結構
先說用處:這個結構能夠很是省內存的去統計各類計數,好比註冊ip數、每日訪問IP數、頁面實時UV(PV確定字符串就搞定了)、在線用戶數等。學習
這裏看到全部的用處都是xxx數,因此這個數據結構的特色就是,能夠比較準確的估算出你要統計的數量,可是卻沒法知道統計的詳細內容。好比統計每日訪問IP數,能夠獲取當時訪問過的IP總數量,可是無法知道這些IP都是什麼。網站
有得必有失,固然你要統計上面提到的那些內容,能夠用集合來處理,這樣能夠知道數量,也能得到全部的詳細列表。可是一個大型的網站,天天IP好比有100萬個呢,咱們粗算一個IP消耗15字節,那麼100萬個IP就是15M,若是1千萬,就是150M。spa
再來看看咱們的HyperLogLog,在Redis中每一個鍵佔用的內容都是12K,理論存儲近似接近2^64個值,無論存儲的內容是什麼。12K,知道這個數據結構的做用了吧。這也是爲何他不能知道里面的詳細內容了。這是一個基於基數估算的算法,只能比較準確的估算出基數,可使用少許固定的內存去存儲並識別集合中的惟一元素。並且這個估算的基數並不必定準確,是一個帶有 0.81% 標準錯誤(standard error)的近似值。ip
這裏當你記錄的內容越多,和集合使用的內容就越容易產生鮮明的對比,由於HyperLogLog結構,在範圍容許的狀況下不管多少值,都置灰佔用12K內存。內存
這樣好比咱們把每日IP記錄下來,假設天天有一億個IP訪問,若是使用集合的話,一天的內存使用就是1.5G,假設咱們存儲一個月的記錄,就須要45G容量。可是使用HyperLogLog的話,一天12K,一個月360K。若是咱們不須要知道IP具體信息的話,徹底能夠把這些記錄留在內存一年、或者不刪都行。若是須要,咱們也會把全部的IP訪問記錄經過其餘途徑存儲起來。把天天的信息存儲起來,咱們能夠計算每個月IP總數(MERGE),一年的IP總數等(去重)。字符串
下面介紹一下HyperLogLog的命令,其實他和集合的命令比較像,只是命令少,不能獲取列表而已。另外這個數據結構須要2.8.9及以上的版本才能使用哦~get
在執行這個命令以後,HyperLogLog內部的結構會被更新,並有所反饋,若是執行完以後HyperLogLog內部的基數估算髮生了變化,那麼就會返回1,不然(認爲已經存在)就返回0。
這個命令還有一個比較神器的就是能夠只有鍵,沒有值,這樣的意思就是隻是建立空的鍵,不放值。
若是這個鍵存在,不作任何事情,返回0;不存在的話就建立,並返回1。
這個命令的時間複雜度爲O(1),因此就放心用吧~
命令例子:
1 2 3 4 5 6 7 8 |
redis> PFADD ip:20160929 "1.1.1.1" "2.2.2.2" "3.3.3.3" (integer) 1 redis> PFADD ip:20160929 "2.2.2.2" "4.4.4.4" "5.5.5.5" # 存在就只加新的 (integer) 1 redis> PFCOUNT ip:20160929 # 元素估計數量沒有變化 (integer) 5 redis> PFADD ip:20160929 "2.2.2.2" # 存在就不會增長 (integer) 0 |
其實咱們發如今少的時候仍是挺準的,哈哈。
其實在上面的學習中咱們已經用過這個了,這裏再來介紹下。
當命令做用於單個鍵的時候,返回這個鍵的基數估算值。若是鍵不存在,則返回0。
看成用於多個鍵的時候,返回這些鍵的並集估算值。相似於把這些鍵都合併了以後,在調用這個命令輸出。
這個命令在做用於單個值的時候,時間複雜度爲O(1),而且具備很是低的平均常數時間;在做用於N個值的時候,時間複雜度爲O(N),這個命令的常數複雜度會比較低些。
命令例子:
1 2 3 4 5 6 7 8 |
redis> PFADD ip:20160929 "1.1.1.1" "2.2.2.2" "3.3.3.3" (integer) 1 redis> PFCOUNT ip:20160929 (integer) 3 redis> PFADD ip:20160928 "1.1.1.1" "4.4.4.4" "5.5.5.5" (integer) 1 redis> PFCOUNT ip:20160928 ip:20160929 (integer) 5 |
合併(merge)多個HyperLogLog爲一個HyperLogLog。其實這個也很好理解,而合併後的估算基數也近似於全部HyperLogLog估算基數的並集。
這個命令的第一個參數爲目標鍵,剩下的參數爲要合併的HyperLogLog。命令執行時,若是目標鍵不存在,則建立後再執行合併。
這個命令的時間複雜度爲O(N),其中N爲要合併的HyperLogLog的個數。不過這個命令的常數時間複雜度比較高。
命令例子:
1 2 3 4 5 6 7 8 |
redis> PFADD ip:20160929 "1.1.1.1" "2.2.2.2" "3.3.3.3" (integer) 1 redis> PFADD ip:20160928 "1.1.1.1" "4.4.4.4" "5.5.5.5" (integer) 1 redis> PFMERGE ip:201609 ip:20160928 ip:20160929 OK redis> PFCOUNT ip:201609 (integer) 5 |
到此HyperLogLog全部的命令就都介紹完了,沒錯,目前就只有這三個。其實也很簡單的,知道了這個結構的用法,也就知道何時適合用了,對咱們很是珍貴的內存仍是頗有幫助。