當前位置:
首頁 > 科技 > Redis-BitMap 「數據結構」可以實現對位的操作

Redis-BitMap 「數據結構」可以實現對位的操作

BitMap是什麼

通過一個bit位來表示某個元素對應的值或者狀態,其中的key就是對應元素本身。Bitmaps 本身不是一種數據結構,實際上它就是字元串(key 對應的 value 就是上圖中最後的一串二進位),但是它可以對字元串的位進行操作。Bitmaps 單獨提供了一套命令,所以在 Redis 中使用 Bitmaps 和使用字元串的方法不太相同。可以把 Bitmaps 想像成一個以 位 為單位的數組,數組的每個單元只能存儲 0 和 1,數組的下標在Bitmaps中叫做偏移量。

BitMap的命令SETBIT語法:SETBIT key offset value說明:對key所儲存的字元串值,設置或清除指定偏移量上的位(bit)。位的設置或清除取決於value參數,可以是0也可以是1。當key不存在時,自動生成一個新的字元串值。字元串會進行伸展(grown)以確保它可以將value保存在指定的偏移量上。當字元串值進行伸展時,空白位置以0填充。offset參數必須大於或等於0,小於 2^32 (bit 映射被限制在 512 MB 之內)。

對使用大的 offset 的 SETBIT 操作來說,內存分配可能造成 Redis 伺服器被阻塞。

返回值:

字元串值指定偏移量上原來儲存的位(bit)。

示例:

獲取值

GETBIT語法:GETBIT key offset說明:對key所儲存的字元串值,獲取指定偏移量上的位(bit)。當offset比字元串值的長度大,或者key不存在時,返回0。返回值:字元串值指定偏移量上的位(bit)。

示例:

獲取Bitmaps 指定範圍值為 1 的位個數BITCOUNT語法:BITCOUNT key start說明:計算給定字元串中,被設置為1的比特位的數量。一般情況下,給定的整個字元串都會被進行計數,通過指定額外的start或end參數,可以讓計數只在特定的位上進行。start和end參數的設置和GETRANGE命令類似,都可以使用負數值: 比如-1表示最後一個位元組,-2表示倒數第二個位元組,以此類推。不存在的key被當成是空字元串來處理,因此對一個不存在的key進行BITCOUNT操作,結果為0。返回值:被設置為1的位的數量。

示例:

多個 Bitmaps 運算

BITOP

語法:BITOP operation destkey key [key ...]

說明:

對一個或多個保存二進位位的字元串 key 進行位元操作,並將結果保存到destkey上。operation可以是AND、OR、NOT、XOR

這四種操作中的任意一種: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。除了NOT操作之外,其他操作都可以接受一個或多個key作為輸入。

處理不同長度的字元串

當BITOP處理不同長度的字元串時,較短的那個字元串所缺少的部分會被看作0。空的key也被看作是包含0

的字元串序列。

返回值:

保存到 destkey 的字元串的長度,和輸入 key 中最長的字元串長度相等。

示例:

BITOP 的複雜度為 O(N) ,當處理大型矩陣(matrix)或者進行大數據量的統計時,最好將任務指派到附屬節點(slave)進行,避免阻塞主節點。

計算Bitmaps中第一個值為 bit 的偏移量

BITPOS

自2.8.7可用。

時間複雜度:O(N)。

語法:BITPOS key bit [start][end]

說明:

返回字元串裡面第一個被設置為 1 或者 0 的bit位。

返回一個位置,把字元串當做一個從左到右的位元組數組,第一個符合條件的在位置 0,其次在位置 8,等等。

GETBIT 和 SETBIT 相似的也是操作位元組位的命令。

默認情況下整個字元串都會被檢索一次,只有在指定 start 和 end 參數(指定start和end位是可行的),該範圍被解釋為一個位元組的範圍,而不是一系列的位。所以start=0 並且 end=2是指前三個位元組範圍內查找。

注意,返回的位的位置始終是從 0 開始的,即使使用了 start 來指定了一個開始位元組也是這樣。

和 GETRANGE 命令一樣,start 和 end 也可以包含負值,負值將從字元串的末尾開始計算,-1是字元串的最後一個位元組,-2是倒數第二個,等等。

不存在的key將會被當做空字元串來處理。

返回值:

命令返回字元串裡面第一個被設置為 1 或者 0 的 bit 位。

如果我們在空字元串或者 0 位元組的字元串裡面查找 bit 為1的內容,那麼結果將返回-1。

如果我們在字元串裡面查找 bit 為 0 而且字元串只包含1的值時,將返回字元串最右邊的第一個空位。如果有一個字元串是三個位元組的值為0xff的字元串,那麼命令BITPOS key 0 將會返回 24,因為 0-23 位都是1。

基本上,我們可以把字元串看成右邊有無數個 0。

然而,如果你用指定 start 和 end 範圍進行查找指定值時,如果該範圍內沒有對應值,結果將返回 -1。

示例:

BITFIELD

自3.2.0可用。

時間複雜度:每個子命令的複雜度為 O(1) 。

語法:BITFIELD key [GET type offset][SET type offset value][INCRBY type offset increment][OVERFLOW WRAP|SAT|FAIL]

說明:

BITFIELD key GET type offset INCRBY type offset increment

BITFIELD 命令可以在一次調用中同時對多個位範圍進行操作: 它接受一系列待執行的操作作為參數, 並返回一個數組作為回復, 數組中的每個元素就是對應操作的執行結果。

比如以下命令就展示了如何對位於偏移量 100 的 8 位長有符號整數執行加法操作, 並獲取位於偏移量 0 上的 4 位長無符號整數:

注意:

使用 GET 子命令對超出字元串當前範圍的二進位位進行訪問(包括鍵不存在的情況), 超出部分的二進位位的值將被當做是 0 。

使用 SET 子命令或者 INCRBY 子命令對超出字元串當前範圍的二進位位進行訪問將導致字元串被擴大, 被擴大的部分會使用值為 0 的二進位位進行填充。 在對字元串進行擴展時, 命令會根據字元串目前已有的最遠端二進位位, 計算出執行操作所需的最小長度。

支持的子命令以及數字類型

以下是 BITFIELD 命令支持的子命令:

GET—— 返回指定的二進位位範圍。

SET—— 對指定的二進位位範圍進行設置,並返回它的舊值。

INCRBY—— 對指定的二進位位範圍執行加法操作,並返回它的舊值。用戶可以通過向 increment 參數傳入負值來實現相應的減法操作。

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

OVERFLOW [WRAP|SAT|FAIL]

當被設置的二進位位範圍值為整數時, 用戶可以在類型參數的前面添加 i 來表示有符號整數, 或者使用 u 來表示無符號整數。 比如說, 我們可以使用 u8 來表示 8 位長的無符號整數, 也可以使用 i16 來表示 16 位長的有符號整數。

BITFIELD 命令最大支持 64 位長的有符號整數以及 63 位長的無符號整數, 其中無符號整數的 63 位長度限制是由於 Redis 協議目前還無法返回 64 位長的無符號整數而導致的。

二進位位和位置偏移量

在二進位位範圍命令中, 用戶有兩種方法來設置偏移量:

如果用戶給定的是一個沒有任何前綴的數字, 那麼這個數字指示的就是字元串以零為開始(zero-base)的偏移量。

另一方面, 如果用戶給定的是一個帶有 # 前綴的偏移量, 那麼命令將使用這個偏移量與被設置的數字類型的位長度相乘, 從而計算出真正的偏移量。

比如說, 對於以下這個命令來說:

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

溢出控制

用戶可以通過 OVERFLOW 命令以及以下展示的三個參數, 指定 BITFIELD 命令在執行自增或者自減操作時, 碰上向上溢出(overflow)或者向下溢出(underflow)情況時的行為:

WRAP : 使用迴繞(wrap around)方法處理有符號整數和無符號整數的溢出情況。 對於無符號整數來說, 迴繞就像使用數值本身與能夠被儲存的最大無符號整數執行取模計算, 這也是 C 語言的標準行為。 對於有符號整數來說, 上溢將導致數字重新從最小的負數開始計算, 而下溢將導致數字重新從最大的正數開始計算。 比如說, 如果我們對一個值為127的i8整數執行加一操作, 那麼將得到結果-128。SAT: 使用飽和計算(saturation arithmetic)方法處理溢出, 也即是說, 下溢計算的結果為最小的整數值, 而上溢計算的結果為最大的整數值。 舉個例子, 如果我們對一個值為120的i8整數執行加10計算, 那麼命令的結果將為i8類型所能儲存的最大整數值127。 與此相反, 如果一個針對i8值的計算造成了下溢, 那麼這個i8值將被設置為-127。FAIL: 在這一模式下, 命令將拒絕執行那些會導致上溢或者下溢情況出現的計算, 並向用戶返回空值表示計算未被執行。需要注意的是,OVERFLOW子命令只會對緊隨著它之後被執行的INCRBY命令產生效果, 這一效果將一直持續到與它一同被執行的下一個OVERFLOW命令為止。 在默認情況下,INCRBY命令使用WRAP方式來處理溢出計算。

以下是一個使用OVERFLOW子命令來控制溢出行為的例子:

而以下則是一個因為 OVERFLOW FAIL 行為而導致子命令返回空值的例子:

作用

BITFIELD 命令的作用在於它能夠將很多小的整數儲存到一個長度較大的點陣圖中, 又或者將一個非常龐大的鍵分割為多個較小的鍵來進行儲存, 從而非常高效地使用內存, 使得 Redis 能夠得到更多不同的應用 —— 特別是在實時分析領域: BITFIELD 能夠以指定的方式對計算溢出進行控制的能力, 使得它可以被應用於這一領域。

性能注意事項

BITFIELD 在一般情況下都是一個快速的命令, 需要注意的是, 訪問一個長度較短的字元串的遠端二進位位將引發一次內存分配操作, 這一操作花費的時間可能會比命令訪問已有的字元串花費的時間要長。

二進位位的排列

BITFIELD 把點陣圖第一個位元組偏移量 0 上的二進位位看作是 most significant 位, 以此類推。 舉個例子, 如果我們對一個已經預先被全部設置為 0 的點陣圖進行設置, 將它在偏移量 7 的值設置為 5 位無符號整數值 23 (二進位位為 10111 ), 那麼命令將生產出以下這個點陣圖表示:

當偏移量和整數長度與位元組邊界進行對齊時, BITFIELD 表示二進位位的方式跟大端表示法(big endian)一致, 但是在沒有對齊的情況下, 理解這些二進位位是如何進行排列也是非常重要的。

返回值:

如果 member 元素是集合的成員,返回 1 。

如果 member 元素不是集合的成員,或 key 不存在,返回 0 。

示例:

案例

使用場景一:用戶簽到

使用場景二:統計活躍用戶

使用時間作為cacheKey,然後用戶ID為offset,如果當日活躍過就設置為1那麼我該如果計算某幾天/月/年的活躍用戶呢(暫且約定,統計時間內只有有一天在線就稱為活躍),有請下一個redis的命令命令 BITOP operation destkey key [key ...]說明:對一個或多個保存二進位位的字元串 key 進行位元操作,並將結果保存到 destkey 上。說明:BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 這四種操作中的任意一種參數

作者:dzzgml


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 極客工 的精彩文章:

你還在因為專網、外網不在一台電腦發愁嗎?我教你怎麼設置
柳傳志:怪我當年沒眼光,不然BAT早成了聯想系!

TAG:極客工 |