Redis學(xué)習(xí)與應(yīng)用(一)位圖

什么是位圖

位圖(Bitmap)是通過(guò)一個(gè) bit 來(lái)表示某個(gè)元素對(duì)應(yīng)的值或者狀態(tài)。它并不是什么新的數(shù)據(jù)結(jié)構(gòu)徐紧。它的內(nèi)容其實(shí)就是普通的字符串。我們可以通過(guò) get/set 獲取位圖的內(nèi)容,也可以使用 getbit/setbit 操作 bit 值(0 或者 1)暇矫。

Bit即比特,是目前計(jì)算機(jī)中數(shù)據(jù)最小的單位择吊。8個(gè)Bit一個(gè)Byte(字節(jié))李根。Bit的值,要么為 0 几睛,要么為 1房轿。由于Bit是計(jì)算機(jī)中最小的單位,使用它進(jìn)行儲(chǔ)存將非常節(jié)省空間所森。特別適合一些數(shù)據(jù)量大的場(chǎng)景囱持。例如,統(tǒng)計(jì)每日活躍用戶(hù)焕济、統(tǒng)計(jì)每月打卡數(shù)等統(tǒng)計(jì)場(chǎng)景纷妆。

常用命令介紹

1)SETBIT

作用:對(duì)于某個(gè)KEY的某位設(shè)值
用法:SETBIT key offset value
返回值: 原來(lái)儲(chǔ)存的位

redis> SETBIT bit 10086 1
(integer) 0

2)GETBIT

作用:獲取某KEY某位的值
用法:GETBIT key offset
返回值:0 或 1。 當(dāng) offset 比字符串值的長(zhǎng)度大晴弃,或者 key 不存在時(shí)凭需,返回 0 。

redis> SETBIT bit 10086 1
(integer) 0

redis> GETBIT bit 10086
(integer) 1

3)BITOP

作用:對(duì)多個(gè)鍵進(jìn)行位操作肝匆。 OPoperation的簡(jiǎn)寫(xiě)粒蜈。
用法:BITOP operation destkey key1 key2 [key ...]
參數(shù)說(shuō)明:
operation 表示位運(yùn)算符。一共有四種操作旗国,見(jiàn)下表枯怖。
destkey 表示運(yùn)算結(jié)果保存的值
key1、key2能曾、key3 表示進(jìn)行運(yùn)算的key

operation 描述
AND 邏輯并
OR 邏輯或
NOT 邏輯非
XOR 邏輯異或

返回值:保存到 destkey 的字符串的長(zhǎng)度度硝,和輸入 key 中最長(zhǎng)的字符串長(zhǎng)度相等。

redis> SETBIT bits-1 0 1        # bits-1 = 1001
(integer) 0

redis> SETBIT bits-1 3 1
(integer) 0

redis> SETBIT bits-2 0 1        # bits-2 = 1011
(integer) 0

redis> SETBIT bits-2 1 1
(integer) 0

redis> SETBIT bits-2 3 1
(integer) 0

redis> BITOP AND and-result bits-1 bits-2
(integer) 1

redis> GETBIT and-result 0      # and-result = 1001
(integer) 1

redis> GETBIT and-result 1
(integer) 0

redis> GETBIT and-result 2
(integer) 0

redis> GETBIT and-result 3
(integer) 1

4)BITCOUNT

作用:計(jì)算給定字符串上寿冕,位為1的個(gè)數(shù)
用法:BITCOUNT key [start] [end] 注意:此處的[start] [end] 為 字節(jié)開(kāi)始和結(jié)束的位置蕊程,非偏移量的位置
返回值:被設(shè)置為 1 的位的數(shù)量。不存在的key驼唱,或空字符串藻茂,值為0

redis> SETBIT tian 0 1
(integer) 0
redis> BITCOUNT tian
(integer) 1
redis> SETBIT tian 2 1
(integer) 0
redis> BITCOUNT tian
(integer) 2

5)BITPOS

用法:獲取某個(gè)鍵第一位被設(shè)置為 0 或 1 位的位置
作用:BITPOS key bit [start] [end]
返回值:返回第一個(gè)被設(shè)為 0 或 1 的位置

redis> SET test_str 'youthcity'
OK
# 查看值為 1 的最開(kāi)始的位數(shù)
redis> BITPOS test_str 1
(integer) 1
# 查看值為 0 的最開(kāi)始位數(shù)
redis> BITPOS test_str 0
(integer) 0
redis> BITPOS test_1 1  # 若沒(méi)有找到指定位,則返回 -1
(integer) -1

6)魔術(shù)指令 BITFIELD

作用:一次對(duì)多個(gè)位范圍進(jìn)行操作。bitfield 有三個(gè)子指令辨赐,分別是 get/set/incrby优俘。每個(gè)指令都可以對(duì)指定片段做操作。
用法:BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
返回值:返回一個(gè)數(shù)組作為回復(fù)掀序, 數(shù)組中的每個(gè)元素就是對(duì)應(yīng)操作的執(zhí)行結(jié)果帆焕。

# 從第1位開(kāi)始取4位,設(shè)值為5(有符號(hào)數(shù))
redis> BITFIELD key SET i4 0 5
1) (integer) 0

# 從第1位開(kāi)始取4位不恭,結(jié)果為有符號(hào)數(shù)
redis> BITFIELD key GET i4 0
1) (integer) 5

# 從第1位取4位叶雹,結(jié)果為有符號(hào)數(shù)
# 從第5位取4位,設(shè)值為6换吧,結(jié)果為無(wú)符號(hào)數(shù)
# 從第5位去4位浑娜,值增加1,結(jié)果為無(wú)符號(hào)數(shù)
redis> BITFIELD key GET i4 0 SET u4 4 6 INCRBY u4 4 1
1) (integer) 5
2) (integer) 0
3) (integer) 7

BITFIELD還提供了三種溢出策略:

  • WRAP(wrap around式散,回繞)筋遭。一個(gè)i8的整數(shù),值為127暴拄,遞增1會(huì)導(dǎo)致值變?yōu)?128漓滔;
  • SAT(saturation arithmetic,飽和計(jì)算)乖篷。一個(gè)i8的整數(shù)响驴,值為120,遞增10結(jié)果變?yōu)?27(i8 類(lèi)型所能儲(chǔ)存的最大整數(shù)值)撕蔼;
  • FAIL豁鲤。 發(fā)生溢出時(shí),操作失敗鲸沮。并返回空值表示計(jì)算未被執(zhí)行琳骡。
redis> BITFIELD tian_key SET i8 0 127 OVERFLOW WRAP INCRBY i8 0 1
1) (integer) 0
2) (integer) -128
redis> BITFIELD tian_key_2 SET i8 0 120 OVERFLOW SAT INCRBY i8 0 10
1) (integer) 0
2) (integer) 127
redis> BITFIELD tian_key_3 SET i8 0 127 OVERFLOW FAIL INCRBY i8 0 1
1) (integer) 0
2) (nil)

應(yīng)用場(chǎng)景

1) 統(tǒng)計(jì)用戶(hù)上線(xiàn)次數(shù)

實(shí)現(xiàn)原理:
每當(dāng)用戶(hù)在某一天上線(xiàn)的時(shí)候,我們就使用 SETBIT讼溺,以用戶(hù)名作為 key 楣号,將那天所代表的網(wǎng)站的上線(xiàn)日作為 offset 參數(shù),并將這個(gè) offset 上的位設(shè)置為 1怒坯。

例如:

  1. 某應(yīng)用上線(xiàn)第100天炫狱,若用戶(hù)A在該天上線(xiàn)一次。
SETBIT A 100 1 
  1. 某應(yīng)用上線(xiàn)第101天剔猿,用戶(hù)A上線(xiàn)视译。
SETBIT A 101 1 
  1. 統(tǒng)計(jì)用戶(hù) A 總共上線(xiàn)次數(shù)。
BITCOUNT A

2)用戶(hù)簽到

與統(tǒng)計(jì)用戶(hù)上線(xiàn)次數(shù)原理類(lèi)似归敬。

原理:以用戶(hù)ID為KEY酷含,以當(dāng)前時(shí)間距離開(kāi)始時(shí)間的時(shí)間差為偏移量鄙早,若用戶(hù)簽到一次,則將位置為 1第美。最后 bitcountKEY蝶锋,獲取用戶(hù)一共簽到的次數(shù)陆爽。

const start_date = '20180801';
const end_date = '20180830';

const offset = moment(start_date).unix() - moment(end_date).unix();
redis.setBit('user_id_2018', offset, 1);

// 統(tǒng)計(jì)活躍天數(shù)
redis.bitCount('user_id_2018');

3)統(tǒng)計(jì)活躍用戶(hù)

需求:統(tǒng)計(jì)某天或連續(xù)幾天什往,活躍用戶(hù)數(shù)
方案:若某用戶(hù)上線(xiàn),則以日期為KEY慌闭,以用戶(hù)user_id為偏移量(若ID不為整數(shù)别威,則將ID hash化為唯一ID),設(shè)置位為 1

redis.setBit('')
const status = 1;
const user_id = 100;
redis.setBit('active_20180820', user_id, status);
redis.setBit('active_20180821', user_id, status);
// 將20180820號(hào)與20180821日進(jìn)行和運(yùn)算驴剔,得出兩天都上線(xiàn)的結(jié)果省古。并存入KEY—— dest_201808_20_21
redis.bitOp('AND', 'dest_201808_20_21', 'active_20180820', 'active_20180821');
redis.bitCount('dest_201808_20_21');

4)用戶(hù)在線(xiàn)狀態(tài)

需求:提供接口檢查用戶(hù)是否在線(xiàn)。
方案:使用bitmap存儲(chǔ)用戶(hù)在線(xiàn)狀態(tài)丧失。使用一個(gè)KEY豺妓,若用戶(hù)在線(xiàn),則以用戶(hù)ID位偏移量布讹,將位設(shè)為 1琳拭;若不在線(xiàn),則設(shè)置為 0描验。

參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末白嘁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子膘流,更是在濱河造成了極大的恐慌絮缅,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呼股,死亡現(xiàn)場(chǎng)離奇詭異耕魄,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)彭谁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)屎开,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人马靠,你說(shuō)我怎么就攤上這事奄抽。” “怎么了甩鳄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵逞度,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我妙啃,道長(zhǎng)档泽,這世上最難降的妖魔是什么俊戳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮馆匿,結(jié)果婚禮上抑胎,老公的妹妹穿的比我還像新娘。我一直安慰自己渐北,他們只是感情好阿逃,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著赃蛛,像睡著了一般恃锉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上呕臂,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天破托,我揣著相機(jī)與錄音,去河邊找鬼歧蒋。 笑死土砂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谜洽。 我是一名探鬼主播萝映,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼褥琐!你這毒婦竟也來(lái)了锌俱?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤敌呈,失蹤者是張志新(化名)和其女友劉穎贸宏,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體磕洪,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吭练,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了析显。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲫咽。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖谷异,靈堂內(nèi)的尸體忽然破棺而出分尸,到底是詐尸還是另有隱情,我是刑警寧澤歹嘹,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布箩绍,位于F島的核電站,受9級(jí)特大地震影響尺上,放射性物質(zhì)發(fā)生泄漏材蛛。R本人自食惡果不足惜圆到,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望卑吭。 院中可真熱鬧芽淡,春花似錦、人聲如沸豆赏。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)河绽。三九已至己单,卻和暖如春唉窃,著一層夾襖步出監(jiān)牢的瞬間耙饰,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工纹份, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留苟跪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓蔓涧,卻偏偏與公主長(zhǎng)得像件已,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子元暴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • 基本的Redis key的操作都已經(jīng)熟悉了之后篷扩,便可以開(kāi)始針對(duì)Redis提供的各種可操作的數(shù)據(jù)結(jié)構(gòu)進(jìn)行學(xué)習(xí)和了解。...
    Yorking閱讀 850評(píng)論 0 0
  • 一億個(gè)用戶(hù)茉盏,有的用戶(hù)頻繁登錄鉴未,也有不經(jīng)常登錄的。如何記錄用戶(hù)的登錄信息鸠姨?如何查詢(xún)活躍用戶(hù)铜秆?[如一周內(nèi) 登錄三次的]...
    小胖學(xué)編程閱讀 8,413評(píng)論 0 12
  • Redis中BitMap技術(shù)簡(jiǎn)介及應(yīng)用 BitMap簡(jiǎn)介 BitMap是一串連續(xù)的二進(jìn)制數(shù)字(0和1),類(lèi)似于位數(shù)...
    747大雄閱讀 1,145評(píng)論 0 1
  • 1.什么叫做Redis的bitmap 即:操作String數(shù)據(jù)結(jié)構(gòu)的key所存儲(chǔ)的字符串指定偏移量上的位讶迁,返回原位...
    香沙小熊閱讀 5,379評(píng)論 0 3
  • 新發(fā)現(xiàn)的《墨子經(jīng)義釋詁》錯(cuò)誤 本文用于記錄《墨子經(jīng)義釋詁》所含錯(cuò)誤连茧。發(fā)現(xiàn)一個(gè)記錄一個(gè)。手上有《墨子經(jīng)義釋詁》的朋友...
    墨者顧如閱讀 890評(píng)論 0 2