這篇文章帶大家了解一下Redis中的點陣圖(bitmap),希望對大家有幫助!
Redis 的位圖(bitmap)是由多個二進位位元組成的數組,數組中的每個二進位位元都有與之對應的偏移量(從0 開始),透過這些偏移量可以對位圖中指定的一個或多個二進位位元進行操作。 【相關推薦:Redis影片教學】
實際上,點陣圖並不是 Redis 提供的一種新的資料類型,它是字串類型的擴充。所以點陣圖的指令可以直接使用在字串類型的鍵上,點陣圖指令操作的鍵也可以被字串類型指令操作。
例如,現有一個字串鍵foo:
redis> set foo bar
1 個位元組由8 個二進位位元組成,所以foo 鍵的二進位形式就是:
透過SETBIT 指令,可以為位圖指定偏移量上的二進位位元設定值,offset 必須大於等於0 ,value 只能是0 或1。此指令的時間複雜度是 O(1)。
SETBIT key offset value
SETBIT 指令在對二進位位元進行設定之後,將傳回二進位位元被設定之前的舊值作為結果。
假設現在想把bar 變成aar,只需如下兩步驟操作:
redis> setbit foo 6 0 (integer) 1 redis> setbit foo 7 1 (integer) 0 redis> get foo"aar"
當執行SETBIT 指令嘗試對位圖進行設定的時候,如果位圖不存在,或者點陣圖目前的大小無法滿足,Redis 將對被設定的位圖進行擴展,並將所有未設定的二進位位元的值初始化為0。例如:
redis> setbit far 10 1
由於far 並不存在,所以Redis 會將0~9 的二進位位元設為0,因為Redis 對位圖的擴展操作是以位元組為單位進行的,所以實際上far一共有16 個二進位位,並非10 個,且11~15 的二進位位也是0。
基於這種情況,當指定的二進位位元偏移量過大時,Redis 需要一次分配完所有內存,這可能會造成 Redis 伺服器阻塞。例如儲存使用者的性別,1 代表男性,0 代表女性,使用 ID 作為二進制偏移量,如果 ID 從 10000000001 開始的,就需要將用戶 ID 減去 10000000000 再進行存儲,否則會造成內存浪費。
使用 GETBIT 指令可以取得位圖指定偏移量上的二進位位元的值。此指令的時間複雜度是 O(1)。
GETBIT key offset
如果輸入的偏移量超過了點陣圖目前擁有的最大偏移量,將傳回 0 作為結果。
透過 BITCOUNT 指令可以統計位圖中值為 1 的二進位位元數。此指令的時間複雜度是 O(n)。
BITCOUNT key [start end]
在預設情況下,BITCOUNT 指令會對位圖所包含的所有位元組中的二進位位元進行統計,也可以透過可選的start 參數和end 參數,讓BITCOUNT 只對指定位元組範圍內的二進位位元進行統計(不是二進位偏移量)。例如,希望統計ar 兩個位元組中值為1 的二進位數量:
redis> bitcount foo 1 2 (integer) 7
start 和end 參數也支援使用負數索引,下方的用法與上方的等效:
redis> bitcount foo -2 -1 (integer) 7
透過執行BITPOS 指令,在位圖中尋找第一個被設定為指定值的二進位位,並傳回這個二進位位元的偏移量。
BITPOS key value [start end]
#BITPOS 也接受可選的start 參數和end 參數,讓BITPOS 指令只在指定位元組範圍內的二進位位中進行查找。
redis> get foo"aar"redis> bitpos foo 1 (integer) 1 redis> bitpos foo 0 (integer) 0 redis> bitpos foo 0 1 2 (integer) 8 redis> bitpos foo 1 1 2 (integer) 9 redis> bitpos foo 1 -1 -1 (integer) 17
針對邊界的處理:
透過BITOP 指令,對一個或多個位圖執行指定的二進位位元運算,並將運算結果儲存到指定的鍵中。
BITOP operation destkey key [key ...]
operation 参数的值可以是 AND、OR、XOR、NOT 中的任意一个,这 4 个值分别对应逻辑并、逻辑或、逻辑异或和逻辑非 4 种运算,其中 AND、OR、XOR 这 3 种运算允许用户使用任意数量的位图作为输入,而 NOT 运算只允许使用一个位图作为输入。BITOP 命令在将计算结果存储到指定键中之后,会返回被存储位图的字节长度。
当 BITOP 命令在对两个长度不同的位图执行运算时,会将长度较短的那个位图中不存在的二进制位的值看作 0。
redis> set foo1 bar OK redis> set foo2 aar OK redis> bitop or res foo1 foo2 (integer) 3 redis> get res"car"
注意:BITOP 可能是一个缓慢的命令,它的时间复杂度是 O(N),在处理长字符串时应注意一下效率问题。
用用户 ID 作为偏移量,若用户做了某种行为则通过 SETBIT 将二进制位设置为 1,通过 GETBIT 判断用户是否做了某种行为,通过 BITCOUNT 可以知道有多少用户执行了行为。
可以使用 SETBIT 和 BITCOUNT 来实现,以用户 ID 作为 key ,假设今天是上线统计功能开放的第一天,ID 为 1 的用户上线后就通过 SETBIT 1 0 1。当要计算此用户的总共以来的上线次数时,使用 BITCOUNT 命令就可以得出的结果。
使用这种方式存储数据,即使 10 年后,1个用户就只占用几百字节的内存,它的处理速度依然很快。如果 bitmap 数据比较大,建议将 bitmap 拆分成多个小的 bitmap 分别进行处理。
更多编程相关知识,请访问:编程入门!!
以上是深入淺析Redis中的點陣圖(bitmap)的詳細內容。更多資訊請關注PHP中文網其他相關文章!