1. 程式人生 > 其它 >Redis點陣圖Bitmaps詳解

Redis點陣圖Bitmaps詳解

技術標籤:redis

概念

  • Redis提供的Bitmaps這個“資料結構”可以實現對位的操作。Bitmaps本身不是一種資料結構,實際上就是字串,但是它可以對字串的位進行操作。

  • 可以把Bitmaps想象成一個以位為單位的陣列,陣列中的每個單元只能存0或者1,陣列的下標在bitmaps中叫做偏移量。

  • 單個bitmaps的最大長度是512MB,即2^32個位元位。

例如字串A 一個位元組,對應的ASCII碼是65,對應的二進位制就是01000001,Bitmaps就是對A的二進位制位進行操作。

命令

SETBIT

SETBIT key offset value
summary: Sets or clears the bit at offset in
the string value stored at key

設定鍵的第offset個位的值,value只有0和1兩個值

字串A在位陣列的 1和7兩個位置是1(從0算起)

127.0.0.1:6379[1]> setbit k1 1 1
(integer) 0
127.0.0.1:6379[1]> setbit k1 7 1
(integer) 0
127.0.0.1:6379[1]> get k1
"A"
127.0.0.1:6379[1]> strlen k1
(integer) 1

對 位1和7設定成1,可以得到字串A,這時k1只有8位,1個位元組,所以長度為1,接下來再對k1進行如下設定

127.0.0.1:6379[1]> setbit k1 9 1
(integer) 0
127.0.0.1:6379[1]> setbit k1 14 1
(integer) 0
127.0.0.1:6379[1]> get k1
"AB"
127.0.0.1:6379[1]> strlen k1
(integer) 2

這時k1的值是如下圖,佔2個位元組

GETBIT

GETBIT key offset
summary: Returns the bit value at offset in the string value stored at key

獲取鍵的第offset位的值

127.0.0.1:6379[1]> getbit k1 1
(integer) 1
127.0.0.1:6379[1]> getbit k1 2
(integer) 0

BITCOUNT

BITCOUNT key [start end]
summary: Count set bits in a string

獲取指定範圍值為1的個數,其中start和end代表起始和結束位元組數

127.0.0.1:6379[1]> bitcount k1 0 0
(integer) 2
127.0.0.1:6379[1]> bitcount k1 1 1
(integer) 2
127.0.0.1:6379[1]> bitcount k1 0 1
(integer) 4

BITPOS

BITPOS key bit [start] [end]
summary: Find first bit set or clear in a string

計算Bitmaps中的第一值為0或者1的偏移量,start和end分別代表起始位元組和結束位元組

127.0.0.1:6379[1]> bitpos k1 1 0 0
(integer) 1
127.0.0.1:6379[1]> bitpos k1 1 1 1
(integer) 9
127.0.0.1:6379[1]> bitpos k1 0 1 1
(integer) 8

對比上圖k1值的位陣列進行驗證

BITOP

BITOP operation destkey key [key ...]
summary: Perform bitwise operations between strings

bitop是一個複合操作,可以做多個Bitmaps的andornotxor操作。

operation 可以是 ANDORNOTXOR 這四種操作中的任意一種:

  • BITOP AND destkey key [key ...] ,對一個或多個 key 求邏輯並,並將結果儲存到 destkey
  • BITOP OR destkey key [key ...] ,對一個或多個 key 求邏輯或,並將結果儲存到 destkey
  • BITOP XOR destkey key [key ...] ,對一個或多個 key 求邏輯異或,並將結果儲存到 destkey
  • BITOP NOT destkey key ,對給定 key 求邏輯非,並將結果儲存到 destkey

設定k2 01000001

127.0.0.1:6379[1]> setbit k2 1 1
(integer) 0
127.0.0.1:6379[1]> setbit k2 7 1
(integer) 0
127.0.0.1:6379[1]> get k2
"A"

設定k3 01000010

127.0.0.1:6379[1]> setbit k3 1 1
(integer) 0
127.0.0.1:6379[1]> setbit k3 6 1
(integer) 0
127.0.0.1:6379[1]> get k3
"B"

AND

127.0.0.1:6379[1]> bitop and anddest k2 k3
(integer) 1
127.0.0.1:6379[1]> get anddest
"@"

k2 01000001 和 k3 01000010做與運算(有0為0,全1為1) 結果 01000000 對應的ASCII碼是@

OR

127.0.0.1:6379[1]> bitop or ordest k2 k3
(integer) 1
127.0.0.1:6379[1]> get ordest
"C"

k2 01000001 和 k3 01000010做或運算(有1為1全0為0) 結果 01000011 對應的ASCII碼是C

XOR

127.0.0.1:6379[1]> bitop xor xordest k2 k3
(integer) 1
127.0.0.1:6379[1]> get xordest
"\x03"

k2 01000001 和 k3 01000010做異或運算(相同為0,不同為1) 結果 00000011 對應的十六進位制\x03 十進位制下3

NOT

127.0.0.1:6379[1]> bitop not notdest k2 
(integer) 1
127.0.0.1:6379[1]> get notdest
"\xbe"

k2 01000001 做非運算(非0則1,非1則0) 結果是 10111110 對應的十六進位制\xbe

BITFIELD

BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
summary: Perform arbitrary bitfield integer operations on strings

redis3.2後新增了一個bitfield命令,可以一次對多個位進行操作.這個指令有三個子指令,get,set,incrby,都可以對指定位片段進行讀寫,但最大支援 64 位長的有符號整數以及 63 位長的無符號整數, 其中無符號整數的 63 位長度限制是由於 Redis 協議目前還無法返回 64 位長的無符號整數而導致的。。

BITFIELD 命令支援的子命令:

  • GET <type> <offset> —— 返回指定的二進位制位範圍。
  • SET <type> <offset> <value> —— 對指定的二進位制位範圍進行設定,並返回它的舊值。
  • INCRBY <type> <offset> <increment> —— 對指定的二進位制位範圍執行加法操作,並返回它的舊值。使用者可以通過向 increment 引數傳入負值來實現相應的減法操作。

除了以上三個子命令之外, 還有一個子命令, 它可以改變之後執行的 INCRBY 子命令在發生溢位情況時的行為:

  • OVERFLOW [WRAP|SAT|FAIL]

當被設定的二進位制位範圍值為整數時, 使用者可以在型別引數的前面新增 i 來表示有符號整數, 或者使用 u 來表示無符號整數。 比如說, 我們可以使用 u8 來表示 8 位長的無符號整數, 也可以使用 i16 來表示 16 位長的有符號整數。

127.0.0.1:6379[1]> set k4 A 
OK
#A對應的二進位制 01000001
#從第1個位開始讀取4個位 0100 結果為無符號數(u)
127.0.0.1:6379[1]> bitfield k4 get u4 0
1) (integer) 4
#從第2個位開始讀取2個位 10 結果為無符號數(u)
127.0.0.1:6379[1]> bitfield k4 get u2 1
1) (integer) 2
#從第0個位開始讀取3個位 010 結果為有符號數(i)
127.0.0.1:6379[1]> bitfield k4 get i3 0
1) (integer) 2
#從第1個位開始讀取5個位 10000 結果為有符號數(i) 首位是1代表負數,對10000減1 -> 01111 取反 -> 10000 十進位制下是16,由於符號位是1,所以結果是-16
127.0.0.1:6379[1]> bitfield k4 get i5 1
1) (integer) -16

二進位制位和位置偏移量

在二進位制位範圍命令中, 使用者有兩種方法來設定偏移量:

  • 如果使用者給定的是一個沒有任何字首的數字, 那麼這個數字指示的就是字串以零為開始(zero-base)的偏移量。
  • 另一方面, 如果使用者給定的是一個帶有 # 字首的偏移量, 那麼命令將使用這個偏移量與被設定的數字型別的位長度相乘, 從而計算出真正的偏移量。
127.0.0.1:6379[1]> BITFIELD k5 SET i8 #0 100
1) (integer) 0
127.0.0.1:6379[1]> BITFIELD k5 SET i8 #1 200
1) (integer) 0
# 01100100 11001000

命令會把 k5 鍵裡面, 第一個 i8 長度的二進位制位的值設定為 100 , 並把第二個 i8 長度的二進位制位的值設定為 200 。 當我們把一個字串鍵當成陣列來使用, 並且陣列中儲存的都是同等長度的整數時, 使用 # 字首可以讓我們免去手動計算被設定二進位制位所在位置的麻煩。

應用

統計使用者登入天數

構建長度為天數365的位陣列,哪天登入過,設定value為1,這樣每個使用者最多佔用46個位元組

127.0.0.1:6379[1]> setbit jack 1 1 #第2天登入過
(integer) 0
127.0.0.1:6379[1]> setbit jack 8 1 #第9天登入過
(integer) 0
127.0.0.1:6379[1]> setbit jack 364 1 #第365天登入過
(integer) 0
127.0.0.1:6379[1]> strlen jack
(integer) 46
127.0.0.1:6379[1]> bitcount jack  #登入的天數
(integer) 3

統計每天的活躍使用者數量

位陣列,每一位代表使用者的ID

127.0.0.1:6379[1]> setbit 2020-11-11 1 1 	#使用者ID為1使用者活躍
(integer) 0
127.0.0.1:6379[1]> setbit 2020-11-11 30 1   #使用者ID為30使用者活躍
(integer) 0
127.0.0.1:6379[1]> setbit 2020-11-11 184 1  #使用者ID為184使用者活躍
(integer) 0
127.0.0.1:6379[1]> bitcount 2020-11-11		#統計2020-11-11的活躍量
(integer) 3

像簽到、點贊、評論數都可以用Bitmaps來實現