溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

redis中的位圖是什么意思

發(fā)布時(shí)間:2021-12-16 10:33:42 來(lái)源:億速云 閱讀:156 作者:小新 欄目:關(guān)系型數(shù)據(jù)庫(kù)

這篇文章將為大家詳細(xì)講解有關(guān)redis中的位圖是什么意思,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

位圖

位圖,即大量bit組成的一個(gè)數(shù)據(jù)結(jié)構(gòu)(每個(gè)bit只能是0和1),主要適合在一些場(chǎng)景下,進(jìn)行空間的節(jié)省,并有意義的記錄數(shù)據(jù),

例如一些大量的bool類型的存取,一個(gè)用戶365天的簽到記錄,簽到了是1,沒(méi)簽到是0,如果用普通的key/value進(jìn)行存儲(chǔ),當(dāng)用戶量很大的時(shí)候,需要的存儲(chǔ)空間是很大的。

如果使用位圖進(jìn)行存儲(chǔ),一年365天,用365個(gè)bit就可以存儲(chǔ),365個(gè)bit換算成46個(gè)字節(jié)(一個(gè)稍長(zhǎng)的字符串),如此就節(jié)省了很多的存儲(chǔ)空間,

redis中的位圖是什么意思

位圖的本質(zhì)其實(shí)是一個(gè)普通的字符串,也就是byte數(shù)組,可以使用get/set直接獲取和設(shè)置整個(gè)位圖的內(nèi)容,也可以使用 getbit/setbit 將byte數(shù)組看成bit數(shù)組來(lái)處理?!鞠嚓P(guān)推薦:Redis視頻教程】

使用位操作設(shè)置字符串

正常設(shè)置字符串都使用set命令,下面我們使用setbit設(shè)置一下位數(shù)組,最后以獲取字符串的形式獲取,

首先我們獲取一下h、e兩個(gè)ASCII碼使用二進(jìn)制的表示如下,

redis中的位圖是什么意思

可以看到h的二進(jìn)制碼是 01101000 , e的二進(jìn)制碼是 01100101,我們只需要注意bit是1的位置,然后進(jìn)行setbit,

redis中的位圖是什么意思

需要注意的是,位數(shù)組的順序和字符的位順序是反的,根據(jù)這個(gè)原則,我們算出 h字符 每個(gè)1的位置分別是1/2/4, e字符的則是 9/10/13/15,

redis中的位圖是什么意思

所以我們將使用setbit設(shè)置一個(gè)位數(shù)組,并在每個(gè)位置上(1/2/4/9/10/13/15)設(shè)置對(duì)應(yīng)的1,

setbit data 1 1
setbit data 2 1
setbit data 4 1
setbit data 9 1
setbit data 10 1
setbit data 13 1
setbit data 15 1

零存整取

redis中的位圖是什么意思

最后直接 get data這個(gè)key,會(huì)發(fā)現(xiàn)正好得到he,

redis中的位圖是什么意思

setbit + get 的組合稱為 零存整取,零存就是一個(gè)bit一個(gè)bit的設(shè)置,整取就是通過(guò)key名字,直接get出來(lái)所有的數(shù)據(jù),

同樣,我們還可以進(jìn)行 零存零取,整存零取,整存就是直接使用字符串設(shè)置整個(gè)位數(shù)組,零取則是通過(guò)bit的位置,進(jìn)行bit的獲取。

零存零取

可以看到,我們根據(jù)setbit,對(duì)key叫做w的位數(shù)組進(jìn)行bit設(shè)置,只設(shè)置了1/2/4這3個(gè)位置的值為1,下圖中有g(shù)etbit w 3, 獲取第三個(gè)位置的值,此時(shí)默認(rèn)是0,如果從業(yè)務(wù)角度觸發(fā),可以理解為,一共簽到4天,第三天沒(méi)有進(jìn)行簽到,

redis中的位圖是什么意思

整存零取

下午所示,我們對(duì)w的這個(gè)key,直接set了一個(gè)h字符,隨后通過(guò)getbit獲取w的位數(shù)組里的每個(gè)bit,可以看到獲取出來(lái)的內(nèi)容和上面h字符的二進(jìn)制內(nèi)容相同 1/2/4的位置是1,其余是0

redis中的位圖是什么意思

注意

  • redis的位數(shù)組是自動(dòng)擴(kuò)充的,如果設(shè)置的某個(gè)偏移位置超出了現(xiàn)有的內(nèi)容范圍,就會(huì)自動(dòng)將位數(shù)組進(jìn)行零擴(kuò)充,即擴(kuò)容的位默認(rèn)都是0值。

  • 如果對(duì)應(yīng)位的字節(jié)是不可打印字符,redis-cli將會(huì)顯示該字符的十六進(jìn)制形式。

  • 一個(gè)字節(jié)是8個(gè)bit(位),要區(qū)分字節(jié)和位。

統(tǒng)計(jì)和查找 (bitcount/bitpos)

redis提供了 統(tǒng)計(jì)指令 bitcount  和  位圖查找指令 bitpos ,

bitcount用來(lái)統(tǒng)計(jì)指定位置范圍內(nèi)1的個(gè)數(shù),bitpos用來(lái)查找指定范圍內(nèi)出現(xiàn)的第一個(gè)0或1。

我們可以通過(guò)bitcount統(tǒng)計(jì)用戶一共簽到了多少天,通過(guò)bitpos指令查找用戶從哪一天開(kāi)始第一次簽到,

如果指定了范圍參數(shù)[start, end],就可以統(tǒng)計(jì)在某個(gè)時(shí)間范圍內(nèi)用戶簽到了多少天以及用戶自某天以后的哪天開(kāi)始簽到,

但是需要注意的是,start和end參數(shù)是字節(jié)索引,也就是說(shuō),指定的位范圍必須是8的倍數(shù),

而不能任意指定,所以我們無(wú)法直接計(jì)算某個(gè)月內(nèi)用戶簽到了多少天,如果需要計(jì)算的話,

可以使用getrange命令取出該月覆蓋的字節(jié)內(nèi)容,然后在內(nèi)存中進(jìn)行統(tǒng)計(jì),例如2月覆蓋了10-12個(gè)字節(jié),就使用 getrange w 8 12 。

127.0.0.1:6379> set w hello    

OK

127.0.0.1:6379> bitcount w      # 所有字符中有多少個(gè)1

(integer) 21

127.0.0.1:6379> bitcount w 0 0   # 第一個(gè)字符中 1 的位數(shù)

(integer) 3

127.0.0.1:6379> bitcount w 0 1   # 前兩個(gè)字符中 1 的位數(shù)

(integer) 7

127.0.0.1:6379> bitpos w 0       # 第一個(gè) 0 位

(integer) 0

127.0.0.1:6379> bitpos w 1       # 第一個(gè) 1 位

(integer) 1

127.0.0.1:6379> bitpos w 1 1 1       # 從第二個(gè)字符算起,第一個(gè)1位

(integer) 9

127.0.0.1:6379> bitpos w 1 2 2       # 從第三個(gè)字符算起,第一個(gè)1位

(integer) 17

bitfield

之前介紹的 setbit / getbit 指定位的值都是單個(gè)位,如果要一次操作多個(gè)位,就必須使用管道來(lái)處理,

在redis3.2以后,提供了bitfield指令,可以一次對(duì)多個(gè)位進(jìn)行操作,bitfield有三個(gè)子指令,分別是get/set/incrby, 都可以對(duì)指定位片段進(jìn)行讀寫,

但是最多只能處理64個(gè)連續(xù)的位,如果超過(guò)64位,就需要使用多個(gè)子指令,bitfield可以一次執(zhí)行多個(gè)子指令。

示例

下面對(duì)下圖的位數(shù)組使用 bitfield 做一些操作

redis中的位圖是什么意思

127.0.0.1:6379> bitfield w get u4 0   # 從第1個(gè)位開(kāi)始取4個(gè)位,結(jié)果是無(wú)符號(hào)數(shù)(u)

1) (integer) 6

127.0.0.1:6379> bitfield w get u3 2   # 從第3個(gè)位開(kāi)始取3個(gè)位,結(jié)果是無(wú)符號(hào)數(shù)(u)

1) (integer) 5

127.0.0.1:6379> bitfield w get i4 0   # 從第1個(gè)位開(kāi)始取4個(gè)位,結(jié)果是有符號(hào)數(shù)(i)

1) (integer) 6

127.0.0.1:6379> bitfield w get i3 2   # 從第3個(gè)位開(kāi)始取3個(gè)位,結(jié)果是有符號(hào)數(shù)(i)

1) (integer) -3

有符號(hào)數(shù)是指獲取的位數(shù)組中的第一個(gè)位是符號(hào)位,剩下的才是值,如果第一位是1,就是負(fù)數(shù),

無(wú)符號(hào)數(shù)表示非負(fù)數(shù),沒(méi)有符號(hào)位,獲取的位數(shù)組全部都是值,有符號(hào)數(shù)最多可以獲取64位,

無(wú)符號(hào)數(shù)只能獲取63位,因?yàn)閞edis協(xié)議中的integer是有符號(hào)數(shù),最大64位,不能傳遞64位的無(wú)符號(hào)值,

如果超出位數(shù)限制,redis就會(huì)告訴你參數(shù)錯(cuò)誤。

上面的指令可以合并成一條指令,可以看到得到的結(jié)果是一樣的,

bitfield w get u4 0 get u3 2 get i4 0 get i3 2

redis中的位圖是什么意思

set修改

我們從第9個(gè)位開(kāi)始,用8個(gè)無(wú)符號(hào)數(shù)替換已經(jīng)存在的8個(gè)位,其實(shí)就是把第二個(gè)字符替換了,由e變成a(它的ASCII碼是97),可以看到結(jié)果也變成了 hallo

127.0.0.1:6379> bitfield w set u8 8 97

1) (integer) 101

127.0.0.1:6379> get w

"hallo"

incrby

incrby對(duì)指定范圍的位進(jìn)行自增操作,即++,這可能會(huì)發(fā)生溢出,如果增加了正數(shù),會(huì)出現(xiàn)上溢出,如果增加的是負(fù)數(shù),會(huì)出現(xiàn)下溢出,

redis默認(rèn)的處理是折返,即如果出現(xiàn)了溢出,就將溢出的符號(hào)位丟掉,例如,如果是8位無(wú)符號(hào)數(shù)255,加1后就全部變成0,如果是8位有符號(hào)數(shù)127,加1后就溢出變成-128。

redis中的位圖是什么意思

依然根據(jù)hello字符,來(lái)演示一下 incrby

127.0.0.1:6379> set w hello

OK

127.0.0.1:6379> bitfield w get u4 2     # 從第3位開(kāi)始取4個(gè)無(wú)符號(hào)整數(shù),第一次是10

1) (integer) 10

127.0.0.1:6379> bitfield w incrby u4 2 1

1) (integer) 11

127.0.0.1:6379> bitfield w incrby u4 2 1

1) (integer) 12

127.0.0.1:6379> bitfield w incrby u4 2 1

1) (integer) 13

127.0.0.1:6379> bitfield w incrby u4 2 1

1) (integer) 14

127.0.0.1:6379> bitfield w incrby u4 2 1

1) (integer) 15
127.0.0.1:6379> bitfield w incrby u4 2 1   #到這里的時(shí)候,已經(jīng)溢出折返成0了

1) (integer) 0

bitfield指令提供溢出策略子指令 overflow,用戶可以選擇溢出行為,默認(rèn)是折返(wrap),還可以選擇失敗(fail) 即報(bào)錯(cuò)不執(zhí)行,還有飽和截?cái)?sat) 即超過(guò)范圍就停留在最大或最小值,

overflow指令只影響接下來(lái)的第一條指令,這條指令執(zhí)行完以后,溢出策略就會(huì)變成默認(rèn)值 折返(wrap)。

飽和截?cái)?/strong>

127.0.0.1:6379> set w hello

OK

127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1

1) (integer) 11

127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1

1) (integer) 12

127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1

1) (integer) 13

127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1

1) (integer) 14

127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1

1) (integer) 15

127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1 # 接下來(lái)的都將是保持最大值

1) (integer) 15

127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1

1) (integer) 15

127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1

1) (integer) 15

失敗不執(zhí)行

127.0.0.1:6379> set w hello

OK

127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1

1) (integer) 11

127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1

1) (integer) 12

127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1

1) (integer) 13

127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1

1) (integer) 14

127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1

1) (integer) 15

127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1 # 接下來(lái)的都是失敗

1) (nil)

127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1

1) (nil)

127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1

1) (nil)

get/set/incrby一起執(zhí)行

127.0.0.1:6379> bitfield w set u4 1 0 get u4 1 incrby u4 2 1

1) (integer) 0

2) (integer) 0

3) (integer) 1

127.0.0.1:6379> get w

"\x04ello"

關(guān)于“redis中的位圖是什么意思”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI