linux中获取redis的map,深入Redis之 bitmap位图和HyperLogLog(五)
bitmap位圖
我們知道一個字符占1個字節,也就是8個位
例如
set name big
big字符串中的3個字符的ASCII碼為98 105 113
所以big轉為二進制就是:
01100010|01101001|01100111
b ? ? ? i ? ? ? ?g
占了3個字節的大小,一共24個位。
bitmap位圖可以幫我們獲取和設置key存儲的值的位。
例如
獲取 name 這個key 的第一個位
getbit name 0 ? # 得到0
設置 name 這個key的第8個位為1
setbit name 7 1
get name ? ? ? ?# 得到cig,b變成c
setbit只能修改位圖指定索引的值,要么是0要么是1
如果使用setbit設置一個不存在的key的位圖,則會生成這個key,并且將偏移量之前的位自動補0
例如:
setbit newKey 99 1 ? ? # 生成一個newKey,其位圖長度為100,第100個位的值為1
位圖為:
000...001
| 99個0 |
get newKey ? ? ?# 會得到一堆你不認識的數字"\x00\x00\x00\x00\x80"
bitcount key [start end] ? # 獲取位圖指定范圍為1的個數
bitop option destkey key1 key2 ... keyn ? ? ?# 將多個bitmap進行 and or not xor操作并將結果存到destkey中
這里題外話說一下位運算:
and: 0&0=0 ?0&1=0 ?1&0=0 ?1&1=1
or: 0|0=0 ?0|1=1 ?1|0=1 ?1|1=1
xor: 0^0=0 ?0^1=1 ?1^0=1 ?1^1=0
實戰場景:
大量的獨立用戶統計,具體情境為,一個網站有1億個注冊用戶,每天登陸的用戶有5000萬個獨立用戶。記錄每天每一個用戶是否登陸。
兩種解決思路:
a.使用集合set:以日期為key,集合存放的是當天登陸的用戶id。
sadd date:20190101 100 5019 43889104 ? ?# 2019-01-01這天存了id為100,5019和43889104的id
假如每個userid平均占用空間為32個位=4字節,則一天約有5000萬個id被記錄到一個集合中,所以一天占用的內存空間=4*5000萬 = 200M
一個月會產生30個這樣的集合(這30個key不會都放到內存,肯定是只有當天的key放到內存,之前的key寫入磁盤文件中),會占用
30 * 200M = 6G 的空間
如果想統計連續登錄一周的用戶可以
sinter date:20190101 date:20190102 ... date:20190107
b.使用位圖: 以日期為key,設置位圖的長度為最大的userid,假設最大的userid剛好是100000000(1億),所以這個key一共有1億個位。
00101100...01101
||
一天占用的空間為 1億/8 = 12.5M
具體命令:
setbit date:20190101 100000000 0 ? ?# 先設定位圖長度為1億
setbit date:20190101 549 1 ? ? ? ? ?# 如userid為549的用戶登錄,就在第549個位上設置為1。
setbit date:20190101 98445219 1
.....
這樣每個userid占用的空間實際上只有1個位=1/8個字節。
但是不管當天只有1個用戶登錄還是有1億個用戶登錄,生成的位圖的長度都是固定的1億,占用的空間都是固定的12.5M。
一個月下來占用
12.5*30 = 375M
如果想統計連續登錄一周的用戶可以
bitop and date:20190101 date:20190102 ... date:20190107
如果想統計一天的獨立用戶登錄數量
bitcount date:20190101
如果想獲取id為1000的用戶在某一天是否登錄:
getbit date:20190101 1000
對比set和bitmap發現,后者會節省很多空間。
但是換一個情景:
1億的用戶,每天10萬獨立用戶登錄
使用set : 32/8 * 10萬 = 4M
使用bitmap: 1億/8 = 12.5M
此時是使用set更節省空間。
HyperLogLog
基于Hyperloglog算法,可以以極小的空間完成獨立數據統計。其本質還是字符串。
命令:
pfadd key element ... ? # 向hyperloglog添加一個或多個元素
pfcount key ... ? ? # 計算hyperloglog的不重復的元素總數
pfmerge destkey k1 k2 ... ? # 合并多個hyperloglog賦給destkey
實戰場景:
計算每一天的網站的獨立訪客數量(用戶重復進入網站不算)
方案:使用hyperloglog,以日期為key,一天建立一個hyperloglog來記錄獨立訪客。用戶每訪問一次網頁就往里面添加用戶的id。可以往這個key中添加重復的用戶id,但是pfcount只會計算不重復值的個數。
添加
pfadd date:20200101 u1 u100 u439 ...
計算一天的獨立訪客數
pfcount date:20200101
計算一周的獨立訪客數
pfcount date:20200101 date:20200102 ... date:20200107
如果一天有100萬的獨立用戶訪問網站,則一個hyperloglog只消耗15K的內存,一個月450K,一年才5M。
hyperloglog與set、bitmap的區別和比較:
hyperloglog消耗內存極小,但是它只能計算key中獨立元素個數,不能取出里面的元素或者查看key中是否有某個元素。
所以想獲取某個用戶在某一天是否登陸就辦不到的,而set和bitmap都是可以辦到的。
hyperloglog有一定的錯誤率,例如往pfadd添加100萬個不同元素(請勿用一條pfadd添加100萬個元素),上面計算出來的元素個數為1009839
相比于單純的字符串型 incr 來計算用戶訪問的區別是:
兩者都先用很小的空間但
incr 不能計算獨立用戶訪問數,只能計算用戶總訪問數(包括刷新頁面也計算在內),而hyperloglog可以。
總結
以上是生活随笔為你收集整理的linux中获取redis的map,深入Redis之 bitmap位图和HyperLogLog(五)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网贷需要什么条件
- 下一篇: 支付宝怎么解除绑定银行卡