新聞中心

位圖(bitmap)同樣屬于 string 數(shù)據(jù)類(lèi)型。Redis 中一個(gè)字符串類(lèi)型的值最多能存儲(chǔ) 512 MB 的內(nèi)容,每個(gè)字符串由多個(gè)字節(jié)組成,每個(gè)字節(jié)又由 8 個(gè) Bit 位組成。位圖結(jié)構(gòu)正是使用“位”來(lái)實(shí)現(xiàn)存儲(chǔ)的,它通過(guò)將比特位設(shè)置為 0 或 1來(lái)達(dá)到數(shù)據(jù)存取的目的,這大大增加了 value 存儲(chǔ)數(shù)量,它存儲(chǔ)上限為
2^32 。
位圖本質(zhì)上就是一個(gè)普通的字節(jié)串,也就是 bytes 數(shù)組。您可以使用
getbit/setbit命令來(lái)處理這個(gè)
位數(shù)組,位圖的結(jié)構(gòu)如下所示:
位圖適用于一些特定的應(yīng)用場(chǎng)景,比如用戶(hù)簽到次數(shù)、或者登錄次數(shù)等。上圖是表示一位用戶(hù) 10 天內(nèi)來(lái)網(wǎng)站的簽到次數(shù),1 代表簽到,0 代表未簽到,這樣可以很輕松地統(tǒng)計(jì)出用戶(hù)的活躍程度。相比于直接使用字符串而言,位圖中的每一條記錄僅占用一個(gè) bit 位,從而大大降低了內(nèi)存空間使用率。
Redis 官方也做了一個(gè)實(shí)驗(yàn),他們模擬了一個(gè)擁有 1 億 2 千 8 百萬(wàn)用戶(hù)的系統(tǒng),然后使用 Redis 的位圖來(lái)統(tǒng)計(jì)“日均用戶(hù)數(shù)量”,最終所用時(shí)間的約為 50ms,且僅僅占用 16 MB內(nèi)存。
位圖應(yīng)用原理
某網(wǎng)站要統(tǒng)計(jì)一個(gè)用戶(hù)一年的簽到記錄,若用 sring 類(lèi)型存儲(chǔ),則需要 365 個(gè)鍵值對(duì)。若使用位圖存儲(chǔ),用戶(hù)簽到就存 1,否則存 0。最后會(huì)生成 11010101... 這樣的存儲(chǔ)結(jié)果,其中每天的記錄只占一位,一年就是 365 位,約為 46 個(gè)字節(jié)。如果只想統(tǒng)計(jì)用戶(hù)簽到的天數(shù),那么統(tǒng)計(jì) 1 的個(gè)數(shù)即可。
位圖操作的優(yōu)勢(shì),相比于字符串而言,它不僅效率高,而且還非常的節(jié)省空間。
Redis 的位數(shù)組是自動(dòng)擴(kuò)展的,如果設(shè)置了某個(gè)偏移位置超出了現(xiàn)有的內(nèi)容范圍,位數(shù)組就會(huì)自動(dòng)擴(kuò)充。
下面設(shè)置一個(gè)名為 a 的 key,我們對(duì)這個(gè) key 進(jìn)行位圖操作,使得 a 的對(duì)應(yīng)的 value 變?yōu)椤癶e”。
首先我們分別獲取字符“h”和字符“e”的八位二進(jìn)制碼,如下所示:
>>> bin(ord("h"))
'0b1101000'
>>> bin(ord("e"))
'0b1100101'
接下來(lái),只要對(duì)需值為 1 的位進(jìn)行操作即可。如下圖所示:
把 h 和 e 的二進(jìn)制碼連接在一起,第一位的下標(biāo)是 0,依次遞增至 15,然后將數(shù)字為 1 的位置標(biāo)記出來(lái),得到 1/2/4/9/10/13/15,我們把這組數(shù)字稱(chēng)為位的“偏置數(shù)”,最后按照上述偏置數(shù)對(duì)字符 a 進(jìn)行如下位圖操作。注意,key 的初始二進(jìn)制位全部為 0。
C:\Users\Administrator>redis-cli 127.0.0.1:6379> SETBIT a 1 1 (integer) 0 127.0.0.1:6379> SETBIT a 2 1 (integer) 0 127.0.0.1:6379> SETBIT a 4 1 (integer) 0 127.0.0.1:6379> get hello "h" 127.0.0.1:6379> SETBIT a 9 1 (integer) 0 127.0.0.1:6379> SETBIT a 10 1 (integer) 0 127.0.0.1:6379> SETBIT a 13 1 (integer) 0 127.0.0.1:6379> SETBIT a 15 1 (integer) 0 127.0.0.1:6379> get hello "he"
從上述示例可以得出,位圖操作會(huì)自動(dòng)對(duì) key 進(jìn)行擴(kuò)容。
如果對(duì)應(yīng)位的字節(jié)是不可以被打印的,那么 Redis 會(huì)以該字符的十六進(jìn)制數(shù)來(lái)表示它,如下所示:
127.0.0.1:6379> SETBIT b 0 1 (integer) 0 127.0.0.1:6379> SETBIT b 1 1 (integer) 0 127.0.0.1:6379> get b "\xc0"
位圖常用命令
1) SETBIT命令
用來(lái)設(shè)置或者清除某一位上的值,其返回值是原來(lái)位上存儲(chǔ)的值。key 在初始狀態(tài)下所有的位都為 0 ,語(yǔ)法格式如下:
SETBIT key offset value
其中 offset 表示偏移量,從 0 開(kāi)始。示例如下:
127.0.0.1:6379> SET user:1 a OK #設(shè)置偏移量為0 127.0.0.1:6379> SETBIT user:1 0 1 (integer) 0 #當(dāng)對(duì)應(yīng)位的字符是不可打印字符,redis會(huì)以16進(jìn)制形式顯示 127.0.0.1:6379> GET user:1 "\xe1"
2) GETBIT命令
用來(lái)獲取某一位上的值。示例如下:
127.0.0.1:6379> GETBIT user:1 0 (integer) 1
當(dāng)偏移量 offset 比字符串的長(zhǎng)度大,或者當(dāng) key 不存在時(shí),返回 0。
redis> EXISTS bits (integer) 0 redis> GETBIT bits 100000 (integer) 0
3) BITCOUNT命令
統(tǒng)計(jì)指定位區(qū)間上,值為 1 的個(gè)數(shù)。語(yǔ)法格式如下:
BITCOUNT key [start end]
示例如下:
127.0.0.1:6379> BITCOUNT user:1 (integer) 8
通過(guò)指定的 start 和 end 參數(shù),可以讓計(jì)數(shù)只在特定的字節(jié)上進(jìn)行。start 和 end 參數(shù)和 GETRANGE 命令的參數(shù)類(lèi)似,都可以使用負(fù)數(shù),比如 -1 表示倒數(shù)第一個(gè)位, -2 表示倒數(shù)第二個(gè)位。
在線(xiàn)練習(xí)工具:https://try.redis.io/
查看更多命令:https://redis.io/commands
新聞名稱(chēng):Redisbitmap位圖操作(圖解)
網(wǎng)頁(yè)地址:http://www.5511xx.com/article/dpohhds.html


咨詢(xún)
建站咨詢(xún)
