redis位图
在我們平時開發(fā)過程中,會有一些 bool 型數(shù)據(jù)需要存取,比如用戶一年的簽到記錄,簽了是 1,沒簽是 0,要記錄 365 天。如果使用普通的 key/value,每個用戶要記錄 365個,當用戶上億的時候,需要的存儲空間是驚人的。為了解決這個問題,Redis 提供了位圖數(shù)據(jù)結構,這樣每天的簽到記錄只占據(jù)一個位,365 天就是 365 個位,46 個字節(jié) (一個字節(jié)有8位) 就可以完全容納下,這就大大節(jié)約了存儲空間。
位圖不是特殊的數(shù)據(jù)結構,它的內容其實就是普通的字符串,也就是 byte 數(shù)組。我們可以使用普通的 get/set 直接獲取和設置整個位圖的內容,也可以使用位圖操作 getbit/setbit等將 byte 數(shù)組看成「位數(shù)組」來處理。
基本使用
Redis 的位數(shù)組是自動擴展,如果設置了某個偏移位置超出了現(xiàn)有的內容范圍,就會自動將位數(shù)組進行零擴充。
接下來我們使用位操作將字符串設置為 hello (不是直接使用 set 指令),首先我們需要得到 hello 的 ASCII 碼,用 Python 命令行可以很方便地得到每個字符的 ASCII 碼的二進制值。
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
?
統(tǒng)計和查找
Redis 提供了位圖統(tǒng)計指令 bitcount 和位圖查找指令 bitpos,bitcount 用來統(tǒng)計指定位置范圍內 1 的個數(shù),bitpos 用來查找指定范圍內出現(xiàn)的第一個 0 或 1。
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
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
bitfield 有三個子指令,分別是get/set/incrby,它們都可以對指定位片段進行讀寫,但是最多只能處理 64 個連續(xù)的位,如果超過 64 位,就得使用多個子指令,bitfield 可以一次執(zhí)行多個子指令。
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w get u4 0 # 從第一個位開始取 4 個位,結果是無符號數(shù) (u)
(integer) 6
127.0.0.1:6379> bitfield w get u3 2 # 從第三個位開始取 3 個位,結果是無符號數(shù) (u)
(integer) 5
127.0.0.1:6379> bitfield w get i4 0 # 從第一個位開始取 4 個位,結果是有符號數(shù) (i)
1) (integer) 6
127.0.0.1:6379> bitfield w get i3 2 # 從第三個位開始取 3 個位,結果是有符號數(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
wow,很魔法有沒有!
然后我們使用 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,它用來對指定范圍的位進行自增操作。
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
?
飽和截斷 SAT
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í)行 FAIL
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)
來源:https://www.cnblogs.com/wuwuyong/p/11739495.html
總結
- 上一篇: 假如年少有为不自卑,懂得什么叫做珍惜
- 下一篇: 寓意吉祥的鱼名字