當存一些bool型數(shù)據(jù),比如用戶一年的簽到此書。如果使用key/value 大數(shù)據(jù)量需要大量的存儲空間。
redis的位圖可以解決這個問題。每天簽到的記錄只占一個位,365天就是365個位,46個字節(jié)。大大節(jié)省了空間。
位圖就是byte數(shù)組。
基本使用

127.0.0.1:6379> setbit s 1 1
(integer) 0
127.0.0.1:6379> setbit s 2 1
(integer) 0
127.0.0.1:6379> setbit s 4 1
(integer) 0
127.0.0.1:6379> setbit s 9 1
(integer) 0
127.0.0.1:6379> setbit s 10 1
(integer) 0
127.0.0.1:6379> setbit s 13 1
(integer) 0
127.0.0.1:6379> setbit s 15 1
(integer) 0
127.0.0.1:6379> get s
"he"
零存零取
127.0.0.1:6379> setbit w 1 1
(integer) 0
127.0.0.1:6379> setbit w 2 1
(integer) 0
127.0.0.1:6379> setbit w 4 1
(integer) 0
127.0.0.1:6379> getbit w 1 # 獲取某個具體位置的值 0/1
(integer) 1
127.0.0.1:6379> getbit w 2
(integer) 1
127.0.0.1:6379> getbit w 4
(integer) 1
127.0.0.1:6379> getbit w 5
(integer) 0
整存零取
127.0.0.1:6379> set w h # 整存
(integer) 0
127.0.0.1:6379> getbit w 1
(integer) 1
127.0.0.1:6379> getbit w 2
(integer) 1
127.0.0.1:6379> getbit w 4
(integer) 1
127.0.0.1:6379> getbit w 5
(integer) 0
如果對應的字節(jié)是不能打印的字符,redis-cli會 顯示該字符的十六進制
統(tǒng)計和查找
bitcount 、bitpos
bitcount 用來統(tǒng)計 制定范圍內(nèi)1的個數(shù)。可以統(tǒng)計用戶一年的簽到次數(shù)
bitpos 用來查找制定范圍內(nèi)第一次出現(xiàn)的0或者1
[start,end]參數(shù)用來指定某個時間范圍內(nèi)用戶簽到的天數(shù), 用戶哪一天開始簽到的。
但是start和end都是字節(jié)參數(shù),所以都必須是8的倍數(shù)。不能隨意指定。因此我們不能直接計算用戶在某個時間段簽到了幾次,必須要將這個月覆蓋的所有字節(jié)全部取出來,放到內(nèi)存中進行處理。
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitcount w
(integer) 21
127.0.0.1:6379> bitcount w 0 0 # 第一個字符中 1 的位數(shù)
(integer) 3
127.0.0.1:6379> bitcount w 0 1 # 前兩個字符中 1 的位數(shù)
(integer) 7
Redis 深度歷險:核心原理與應用實踐 | 錢文品 著 第 39 頁 共 226 頁
127.0.0.1:6379> bitpos w 0 # 第一個 0 位
(integer) 0
127.0.0.1:6379> bitpos w 1 # 第一個 1 位
(integer) 1
127.0.0.1:6379> bitpos w 1 1 1 # 從第二個字符算起,第一個 1 位
(integer) 9
127.0.0.1:6379> bitpos w 1 2 2 # 從第三個字符算起,第一個 1 位
(integer) 17
魔術指令bitfield
用來操作多個位,最多連續(xù)處理64位,如果超過64位需要 使用多個指令,bitfield可以一次執(zhí)行多個子指令
get
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w get u4 0 # 從第一個位開始取 4 個位,結(jié)果是無符號數(shù) (u)
(integer) 6
127.0.0.1:6379> bitfield w get u3 2 # 從第三個位開始取 3 個位,結(jié)果是無符號數(shù) (u)
(integer) 5
127.0.0.1:6379> bitfield w get i4 0 # 從第一個位開始取 4 個位,結(jié)果是有符號數(shù) (i)
1) (integer) 6
127.0.0.1:6379> bitfield w get i3 2 # 從第三個位開始取 3 個位,結(jié)果是有符號數(shù) (i)
1) (integer) -3
所謂有符號數(shù)是指獲取的位數(shù)組中第一個位是符號位,剩下的才是值。如果第一位是1,那就是負數(shù)。無符號數(shù)表示非負數(shù),沒有符號位,獲取的位數(shù)組全部都是值。有符號數(shù)最多可以獲取 64 位,無符號數(shù)只能獲取 63 位 (因為 Redis 協(xié)議中的 integer 是有符號數(shù),最大 64 位,不能傳遞 64 位無符號值)。如果超出位數(shù)限制,Redis 就會告訴你參數(shù)錯誤。
執(zhí)行多個子指令:
127.0.0.1:6379> bitfield w get u4 0 get u3 2 get i4 0 get i3 2
1) (integer) 6
2) (integer) 5
3) (integer) 6
4) (integer) -3
set 子指令
將第二個字符 e 改成 a,a 的 ASCII 碼是 97。
127.0.0.1:6379> bitfield w set u8 8 97 # 從第 8 個位開始,將接下來的 8 個位用無符號數(shù) 97 替換
1) (integer) 101
127.0.0.1:6379> get w
"hallo"
incrby
指定范圍內(nèi)自增。如果溢出,redis的默認方法是折返, 將溢出的符號位丟掉。比如8位 無符號位255,增加一位就會溢出,變成0。如果是8位有符號位位127,加1溢出變?yōu)?128
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w incrby u4 2 1 # 從第三個位開始,對接下來的 4 位無符號數(shù) +1
1) (integer) 11
127.0.0.1:6379> bitfield w incrby u4 2 1
1) (integer) 12
127.0.0.1:6379> bitfield w incrby u4 2 1
1) (integer) 13
127.0.0.1:6379> bitfield w incrby u4 2 1
1) (integer) 14
127.0.0.1:6379> bitfield w incrby u4 2 1
1) (integer) 15
127.0.0.1:6379> bitfield w incrby u4 2 1 # 溢出折返了
1) (integer) 0
overflow
bitfield指令 提供了溢出策略子指令overflow。
可以選擇溢出折返,溢出報錯,飽和截斷,超過范圍就會停留到最大/最小值。overflow只影響下來的第一條指令,這條指令執(zhí)行完溢出策略會變成默認的折返
飽和截斷
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 11
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 12
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 13
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (intege) 14
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 15
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1 # 保持最大值
1) (integer) 15
失敗不執(zhí)行
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
1) (integer) 11
127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
1) (integer) 12
127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
1) (integer) 13
127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
1) (integer) 14
127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
1) (integer) 15
127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1 # 不執(zhí)行
1) (nil)