Redis系列第四篇之Bitmap

前言

Bitmap實際上并不是一種數(shù)據(jù)類型,而是定義在String類型上的面向位的操作。因為String是二進制安全的并且最大長度為512MB,所以String可以建立2^32個不同的位。位操作被分為兩種:

  • 常數(shù)時間的單獨一個位的操作税弃,比如設(shè)置某個位的值為1或者0,或者或者某個位的值
  • 對一組bit位的操作,例如在給定的位范圍內(nèi)計算被設(shè)置的bit數(shù)量(如人口統(tǒng)計)

Bitmap最大的一個優(yōu)點是當(dāng)存儲信息時可以節(jié)省極大的空間骏令。例如一個系統(tǒng)中的用戶ID由遞增的ID表示,只需使用512MB的內(nèi)存垄提,就可以記住40億用戶的單比特信息(例如榔袋,知道用戶是否想收到通訊)。

Bitmap使用SETBITGETBIT命令設(shè)置和獲取位的值:

> SETBIT key 10 1
> GETBIT key 10

SETBIT命令第一個參數(shù)表示需要被設(shè)置的位铡俐,第二個參數(shù)表示需要設(shè)置的值(1或者0)凰兑。需要注意的是,當(dāng)被設(shè)置的位超過字符串當(dāng)前的長度時审丘,SETBIT命令將會自動增加字符串的長度吏够。GETBIT返回指定位上的值,對于超過字符串當(dāng)前長度范圍的位,總是被視為0锅知。

Bitmap有三個命令是基于對一組位進行操作的命令:

  1. BITOP:在不同字符串之間執(zhí)行逐位的操作播急,Redis提供的操作有的:ANDOR售睹,XOR
  2. BITCOUNT:統(tǒng)計值為1的位數(shù)
  3. BITPOS:獲取第一個被設(shè)置位0或者1的位

BITPOSBITCOUNT都可以對字符串的字節(jié)范圍進行操作桩警,Bitmap的常見使用場景有:

  • 各種實時分析
  • 存儲與對象ID相關(guān)的布爾信息

比如想統(tǒng)計網(wǎng)站最長的用戶連續(xù)訪問天數(shù),可以使用Bitmap昌妹,每個位的值作為該天是否訪問網(wǎng)站的標(biāo)志(第一位表示第一天捶枢,第二位表示第二天,以此類推)捺宗,每當(dāng)用戶訪問網(wǎng)站時可以使用SETBIT設(shè)置該天對應(yīng)的位為1柱蟀,最后統(tǒng)計連續(xù)設(shè)置為1的位的數(shù)量即可。使用BITCOUNT可以統(tǒng)計出用戶訪問網(wǎng)站的天數(shù)蚜厉,使用BITPOS即可統(tǒng)計出最長的連續(xù)訪問天數(shù)长已。為了分片數(shù)據(jù)集,最好避免使用大鍵昼牛,可以讓每個鍵存儲M個位术瓮,將(位數(shù)/M)的值與鍵名關(guān)聯(lián),將(位數(shù)%M)可以獲取位數(shù)處于鍵內(nèi)的位置贰健。

下面是Bitmap相關(guān)命令胞四。

BITCOUNT key [ start end [ BYTE | BIT]]

  • 可用版本: v2.6.0開始
  • 歷史: 從v7.0.0開始增加BYTE|BIT選項
  • 時間復(fù)雜度: O(N)
  • 解釋: 計算字符串中被設(shè)置為1的位數(shù)。默認(rèn)情況下伶椿,字符串中所有的字節(jié)都會被檢查辜伟,可以通過startend選項指定命令僅執(zhí)行于字符串的某個范圍內(nèi)(startend可以為正數(shù)或者負(fù)數(shù),整數(shù)表示以從頭到尾的順序計算脊另,反之負(fù)數(shù)表示叢尾到頭的順序計算导狡,-1表示最后一位,-2表示倒數(shù)第二位等等)偎痛。不存在的key被視為空字符串旱捧,命令將返回0。默認(rèn)情況下踩麦,startend選項指明的是字節(jié)范圍枚赡,調(diào)用方可以通過BIT選項來指明位范圍。
  • 返回值: Integer(整型)谓谦,返回被設(shè)置為1的位數(shù)贫橙。

BITFIELD key GET encoding offset | [OVERFLOW WRAP | SAT | FAIL] SET encoding offset value | INCRBY encoding offset increment [ GET encoding offset | [OVERFLOW WRAP | SAT | FAIL] SET encoding offset value | INCRBY encoding offset increment ...]

  • 可用版本: v3.2.0開始

  • 時間復(fù)雜度: 對于每個子命令的時間復(fù)雜度為O(1)

  • 解釋: 此命令將Redis字符串視為一個bit數(shù)組,可以處理不同比特寬度的特定整數(shù)字段和任意非(必要)對齊的偏移反粥,例如可以將偏移量為1234的有符號5位整數(shù)設(shè)置為一個特定的值料皇,從偏移量4567檢索到一個31位無符號整數(shù)谓松,同樣此命令也可以處理指定偏移量整數(shù)的增量和減量,提供用戶可以配置的保證和明確指定的上溢和下溢行為践剂。BITFIELD可以在一次調(diào)用中使用多個位字段鬼譬,并返滬一個回復(fù)數(shù)組,每個數(shù)組對應(yīng)相應(yīng)順序的操作結(jié)果逊脯。BITFIELD支持的子命令有:

    • SET encoding offset value 設(shè)置指定位字段同時返回這些字段的舊值
    • GET encoding offset 返回指定位字段的值
    • INCRBY encoding offset increment 增加或者減少(如果給定的增量為負(fù)數(shù))指定位字段同時返回操作后的新值
    • OVERFLOW [WARP|SAT|FAIL] 此子命令通過設(shè)置溢出行為來改變連續(xù)的INCRBYSET子命令溢出時的調(diào)用行為优质,需要注意的是OVERFLOW只影響子命令列表中位于其之后的SETINCRBY子命令,直到下一個OVERFLOW語句军洼。
      1. WARP: 針對有符號和無符號的整數(shù)巩螃,在無符號整數(shù)的情況下,WARP就像對整數(shù)所能包含的最大值進行模數(shù)化操作(C的標(biāo)準(zhǔn)行為)匕争。對于有符號的整數(shù)避乏,WARP意味著溢出是朝著最負(fù)的值重新開始的,而溢出是朝著最正的值重新開始的甘桑,如果一個i8整數(shù)被設(shè)置為127拍皮,將其遞增1會產(chǎn)生-128
      2. SAT: 使用飽和算法,在下溢時跑杭,值被設(shè)置為最小的整數(shù)值铆帽,而在上溢時,則設(shè)置為最大的整數(shù)值德谅。例如爹橱,一個i8整數(shù)從值120開始增量為10,將導(dǎo)致值為127窄做,進一步增量將始終保持在127愧驱。同樣的情況也發(fā)生在下溢上,但是數(shù)值會被封鎖在最負(fù)的數(shù)值上
      3. FAIL: 不會對檢測到的上溢或下溢執(zhí)行任何操作椭盏。相應(yīng)的返回值設(shè)置為NULL以向調(diào)用者發(fā)出條件信號

    整數(shù)編碼(encoding)的可選值有:i表示有符號整數(shù)组砚,i16表示有符號的16位整數(shù);u表示無符號整數(shù)庸汗,u8表示無符號的8位整數(shù)惫确,有符號整數(shù)支持的編碼最多為64位手报,無符號整數(shù)最多支持63位蚯舱。無符號整數(shù)的這種限制是由于目前Redis協(xié)議無法返回64位無符號整數(shù)作為回復(fù)。
    命令使用實例掩蛤;

      > BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
      1) (integer) 1
      2) (integer) 1
      > BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
      1) (integer) 2
      2) (integer) 2
      > BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
      1) (integer) 3
      2) (integer) 3
      > BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
      1) (integer) 0
      2) (integer) 3
    
  • 返回值: Array(數(shù)組)枉昏,返回每個子命令的操作結(jié)果,結(jié)果順序與子命令順序一致揍鸟。OVERFLOW返回值為nil

BITFIELD_RO key GET encoding offset [ encoding offset ...]

  • 可用版本: v6.2.0開始
  • 時間復(fù)雜度: O(N)兄裂,N為子命令數(shù)量
  • 解釋: BITFIELD命令的只讀形式句旱,不同的是BITFIELD_RO只接受GET子命令,并且可以安全在只讀副本集中晰奖。
  • 返回值: Array(數(shù)組)谈撒,返回每個子命令的操作結(jié)果,結(jié)果順序與子命令順序一致

BITOP operation destkey key [key ...]

  • 可用版本: v2.6.0開始
  • 時間復(fù)雜度: O(N)
  • 解釋: 在多個key之間執(zhí)行逐位地進行位操作匾南,并且將結(jié)果存儲進destkey中啃匿,BITOP支持的位操作命令有:ANDOR蛆楞、XOR溯乒、NOT(其中NOT操作只接受一個key):
    • BITOP AND destkey srckey1 srckey2 srckey3 ... srckeyN
    • BITOP OR destkey srckey1 srckey2 srckey3 ... srckeyN
    • BITOP XOR destkey srckey1 srckey2 srckey3 ... srckeyN
    • BITOP NOT destkey srckey
      命令執(zhí)行時,對于長度不相同的字符串來說豹爹,Redis將會用0進行填充裆悄,使其長度達到最長字符串的長度;同時對于不存在的key臂聋,Redis也將其視為全為0的字符串
  • 返回值: Integer(整型)光稼,返回存儲在目標(biāo)鍵中的字符串長度,該字符串長度等于輸入鍵中對應(yīng)的字符串中長度最長的值

BITPOS key bit [ start [ end [ BYTE | BIT]]]

  • 可用版本: v2.8.7開始
  • 歷史: 從v7.0.0開始增加BYTEBIT選項
  • 時間復(fù)雜度: O(N)
  • 解釋: 返回字符串中第一個被設(shè)置為0或者1的位的位置逻住。此命令將字符串視為從左到右的位數(shù)組钟哥,其中第一個字節(jié)的最高有效位在位置0,第二個字節(jié)的最高有效位在位置8瞎访,依此類推腻贰。
    默認(rèn)情況下,字符串中包含的所有字節(jié)都將被檢查扒秸。調(diào)用方可以通過參數(shù)startend播演,指明只在指定的區(qū)間內(nèi)查找位(也可以只傳遞start,操作將假定end是字符串的最后一個字節(jié))伴奥。默認(rèn)情況下写烤,范圍被解釋為一個字節(jié)的范圍,而不是一個比特的范圍拾徙,所以start=0和end=2意味著查看前三個字節(jié)洲炊;可以使用可選的BIT修飾符來指定應(yīng)將范圍解釋為位范圍,當(dāng)使用BIT選項時尼啡,start=0和end=2表示看前三位暂衡。
    不存在的key將被視為空字符串;startend的值既可以是正數(shù)也可以是負(fù)數(shù)崖瞭,正數(shù)表示從正序狂巢,反之為倒序。
  • 返回值: Integer(整型)书聚,返回指定范圍內(nèi)第一個0或者1所在的位或者字節(jié)數(shù)唧领。

GETBIT key offset

  • 可用版本: v2.2.0開始
  • 時間復(fù)雜度: O(1)
  • 解釋: 返回存儲在位置offset處的位值藻雌。當(dāng)offset超過字符串長度時,超出部分的字符串被假定為一個位值為0的連續(xù)空間斩个;當(dāng)key不存在時胯杭,它被假定為一個空字符串甘邀,因此偏移量總是超出范圍练俐,并且該值也被假定為一個以0填充的連續(xù)空間
  • 返回值: Integer(整型),返回存儲在位置offset處的值

SETBIT key offset value

  • 可用版本: v2.2.0開始
  • 時間復(fù)雜度: O(1)
  • 解釋: 設(shè)置或者清除offset處的位值激蹲,設(shè)置的值可以是0或者1腔呜。當(dāng)key不存在時叁温,將會創(chuàng)建一個新的字符串值,字符串的長度會自動增長(填充0)以確保它可以達到偏移量處的位置核畴。偏移量參數(shù)必須大于或等于0膝但,并且小于 2^32(因為Redis字符串長度限制位512MB)
  • 返回值: Integer(整型),返回存儲在offset的舊值

參考資料

Redis Bitmap
原文連接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谤草,一起剝皮案震驚了整個濱河市跟束,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌丑孩,老刑警劉巖冀宴,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異温学,居然都是意外死亡略贮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門仗岖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逃延,“玉大人,你說我怎么就攤上這事轧拄±肯椋” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵檩电,是天一觀的道長拄丰。 經(jīng)常有香客問我,道長俐末,這世上最難降的妖魔是什么料按? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮鹅搪,結(jié)果婚禮上站绪,老公的妹妹穿的比我還像新娘遭铺。我一直安慰自己丽柿,他們只是感情好恢准,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著甫题,像睡著了一般馁筐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坠非,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天敏沉,我揣著相機與錄音,去河邊找鬼炎码。 笑死盟迟,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潦闲。 我是一名探鬼主播攒菠,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼歉闰!你這毒婦竟也來了辖众?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤和敬,失蹤者是張志新(化名)和其女友劉穎凹炸,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昼弟,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡啤它,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了舱痘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚕键。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖衰粹,靈堂內(nèi)的尸體忽然破棺而出锣光,到底是詐尸還是另有隱情,我是刑警寧澤铝耻,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布誊爹,位于F島的核電站,受9級特大地震影響瓢捉,放射性物質(zhì)發(fā)生泄漏频丘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一泡态、第九天 我趴在偏房一處隱蔽的房頂上張望搂漠。 院中可真熱鬧,春花似錦某弦、人聲如沸桐汤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怔毛。三九已至员萍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拣度,已是汗流浹背碎绎。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留抗果,地道東北人筋帖。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像冤馏,于是被迫代替她去往敵國和親幕随。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容