核心知識點:
1.Bitmaps是一種特殊的“數據結構”,實質上是一個字符串,操作單元是位。
2.命令:
a.setbit:設置值,只能存儲0和1,適用二元判斷類型
b.getbit:獲取值
c.bitcount:統計1的數量,可指定范圍
d.bitop:可取交集、並集、非、異或
e.bitpos:第一個獲取某種狀態的偏移量
3.Bitmaps並不是任何場合都適合,在某些場合適用會有意想不到的效果。
1.數據結構模型
現代計算機用二進制(位)作為信息的基礎單位,1個字節等位8位,例如“big”字符串是由3個字節組成,
但實際在計算機存儲時將其用二進制表示,“big”分別對應的ASCII碼分別是98、105、103,
對應的二進制分別是01100010、01101001和01100111,如下圖:
許多開發語言都提供了操作位功能,合理地使用位能夠有效地提高內存使用率和開發效率。
Redis提供了Bitmaps這個“數據結構”,可以實現對位的操作。把數據結構加上引號主要因為:
(1)Bitmaps本身不是一種數據結構,實際上它就是字符串,,但它可以對字符串的位進行操作;
(2)Bitmaps單獨提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太一樣。
可以把Bitmaps想象成一個以位為單位的數組,數組的每個單元只能存儲0和1,數組的下標在Bitmaps中叫做偏移量。
2.命令
本節將每個獨立用戶是否訪問過網站存放在Bitmaps中,將訪問的用戶記做1,沒有訪問的用戶記做0,用偏移量作為用戶的id。
(1)設置值
setbit key offset value
設置鍵的第offset個位的值(從0算起),假設現在有20個用戶,userid=0,5,11,15,19的用戶對網站進行了訪問,
那么當前Bitmaps初始化結果如圖:
具體操作過程如下,unique:users:2016-04-05代表2016-04-05這天的獨立訪問用戶的Bitmaps:
127.0.0.1:6379> setbit unique:users:2016-04-05 0 1 (integer) 0 127.0.0.1:6379> setbit unique:users:2016-04-05 5 1 (integer) 0 127.0.0.1:6379> setbit unique:users:2016-04-05 11 1 (integer) 0 127.0.0.1:6379> setbit unique:users:2016-04-05 15 1 (integer) 0 127.0.0.1:6379> setbit unique:users:2016-04-05 19 1 (integer) 0
很多應用的用戶id以一個指定的數字(例如10000)開頭,直接將用戶id和Birmaps的偏移量對應勢必會造成一定的浪費,
通常的做法是每次做setbit操作時將用戶id減去這個指定數字。
在第一次初始化Bitmaps時,如果偏移量非常大,那么整個初始化過程執行會比較慢,可能會造成Redis阻塞。
(2)獲取值
getbit key offset
獲取鍵的第offset位的值(從0開始計算),如果返回0代表沒有訪問,返回1代表訪問過。
127.0.0.1:6379> getbit unique:users:2016-04-05 8 (integer) 0 127.0.0.1:6379> getbit unique:users:2016-04-05 5 (integer) 1 127.0.0.1:6379> getbit unique:users:2016-04-05 1000 (integer) 0 #不存在1000,自然返回0
(3)獲取Bitmaps指定范圍值為1的個數
bitcount key [start] [end]
127.0.0.1:6379> bitcount unique:users:2016-04-05 (integer) 5 127.0.0.1:6379> bitcount unique:users:2016-04-05 10 20 (integer) 0 127.0.0.1:6379> bitcount unique:users:2016-04-05 1 3 (integer) 3 #start和and代表字節數,一個字節8位,1到3個字節就是索引在8到23之間
(4)Bitmaps間的運算
bitop op destkey key [key ...]
bitop是一個復合操作,它可以做多個Bitmaps的and(交集)、or(並集)、not(非)、xor(異或)操作,並將結果保存在destkey中。
下面有該網站連續2天客戶訪問的Bitmaps記錄:
下面操作計算兩天都訪問網站的用戶數:
127.0.0.1:6379> bitop and unique:users:and:2016-04-03_04 unique:users:2016-04-03 unique:users:2016-04-04 (integer) 2 127.0.0.1:6379> bitcount unique:users:and:2016-04-03_04 (integer) 2
下面操作計算兩天中至少有一天訪問網站的用戶數:
127.0.0.1:6379> bitop or unique:users:or:2016-04-03_04 unique:users:2016-04-03 unique:users:2016-04-04 (integer) 2 127.0.0.1:6379> bitcount unique:users:or:2016-04-03_04 (integer) 6
(5)計算Bitmaps中第一個值為tergetBit的偏移量
bitpos key targetBit [start] [end]
下面操作計算2016-04-03這一天當前訪問網站的最小用戶id:
127.0.0.1:6379> bitpos unique:users:2016-04-03 1 (integer) 0 #索引為1的用戶最先訪問
除此之外,bitpos還可以指定start和end,分別代表起始字節和結束字節:
127.0.0.1:6379> bitpos unique:users:2016-04-04 1 1 2 (integer) 9
3.Bitmaps性能分析
假設網站有1億用戶,每天獨立訪問的用戶是5000萬,如果每天用集合類型和Bitmaps分別存儲活躍用戶。
很容易看出,在這種情況下Bitmaps能節省很多內存空間,尤其隨着時間推移比較客觀。
但是Bitmaps並不是萬金油,當該網站每天訪問的用戶很少時,Bitmaps就有點不合時宜了。
注釋:由於有5000萬活躍用戶,每個用戶一個id,這就需要8位數字表示,每個數字一個字節因此就是64位。