系列文章
我們都知道8bit = 1b = $2^{-10}$kb,bitmap
就是通過最小的單位bit
來進行0或者1的設定,表示某個元素對應的值或者狀態。
一個bit的值,或者是0,或者是1;也就是說一個bit能儲存的最多資訊是2。
點陣圖並不是一種特殊的資料結構,其實本質上是二進位制字串,也可以看做是 byte 陣列。可以使用普通的 get/set 直接獲取和設定整個點陣圖的內容,也可以使用點陣圖操作 getbit/setbit 等將 byte 陣列看成「位陣列」來處理。
點陣圖的優勢:
- 基於最小的單位bit進行儲存,所以非常省空間。
- 設定時候時間複雜度O(1)、讀取時候時間複雜度O(n),操作是非常快的
- 二進位制資料的儲存,進行相關計算的時候非常快
- 方便擴容
一般可以在如下場景使用:
- 使用者簽到
- 使用者線上狀態
- 統計活躍使用者
- 各種狀態值
常用命令
SETBIT
對 key 所儲存的字串值,設定或清除指定偏移量上的位(bit)。SETBIT key offset value
offset 引數必須大於或等於 0 ,小於 2^32 (bit 對映被限制在 512 MB 之內)。
GETBIT
對 key 所儲存的字串值,獲取指定偏移量上的位(bit)。GETBIT key offset
BITCOUNT
計算給定字串中,被設定為 1 的位元位的數量。BITCOUNT key
BITPOS
返回點陣圖中第一個值為 bit 的二進位制位的位置。BITPOS key bit [start] [end]
BITOP
對一個或多個儲存二進位制位的字串 key 進行位元操作,並將結果儲存到 destkey 上。BITOP operation destkey key [key …]
operation 可以是 AND 、 OR 、 NOT 、 XOR 這四種操作中的任意一種BITOP AND destkey key [key ...]
,對一個或多個 key 求邏輯並,並將結果儲存到 destkey 。
BITFIELD
bitfield 有三個子指令,分別是 get/set/incrby,它們都可以對指定位片段進行讀寫,但是最多隻能處理 64 個連續的位,如果超過 64 位,就得使用多個子指令,bitfield 可以一次執行多個子指令。
適用於各類統計應用
記錄使用者的簽到,每日線上情況等,可以將當天或者當天的偏移量對應的bit位設定為1即可,使用BITCOUNT
可以輕鬆統計簽到次數。
還有一種使用比較多的情況,就是設定各類狀態值,例如商城的設定:是否可以評價訂單,是否展示售罄商品,是否正常營業等狀態值可以使用bitmap來儲存
在效能方面,如前面提到的簽到,即使執行 10 年,佔用的空間也只是每個使用者 10*365 位元位(bit),也即是每個使用者 456 位元組。對於這種大小的資料來說, BITCOUNT key [start] [end] 的處理速度就像 GET key 和 INCR key 這種 O(1) 複雜度的操作一樣快。
當然如果你的 bitmap 資料非常大,那麼可以考慮使用以下兩種方法:
- 將一個大的 bitmap 分散到不同的 key 中,作為小的 bitmap 來處理。使用 Lua 指令碼可以很方便地完成這一工作。
- 使用 BITCOUNT key [start] [end] 的 start 和 end 引數,每次只對所需的部分位進行計算,然後在進行累加。
本文亦在微信公眾號【小道資訊】釋出,歡迎掃碼關注!