?
一、位與字節(jié)
1個字節(jié)(byte)等于8個位(bit)。(計算機常識)。
二、string與bitmap
Redis里的bitmap是屬于string這個數(shù)據(jù)類型里的??梢詇elp進行查看bit相關(guān)api。
 
三、bitmap的api
1、setbit
稍微解釋下,setbit 三個參數(shù),第一個是key,第二個是偏移量,也就是在第幾個位(從0開始)上寫value,第三個是值(這個值只支持0和1,因為是位,二進制。如果你寫了大于1的數(shù)或者小于0的數(shù),會報錯的,不信的自己嘗試。)

get b1 是個@符號,因為get取的不是位,所以不是0和1,而是ASCII碼里的值,所以在ASCII碼里對應(yīng)的是@。(二進制轉(zhuǎn)10進制,然后去ASCII碼表里看,是@)
setbit b1 1 1 其實對應(yīng)的是(因為每個字節(jié)8個位):0 1 0 0 0 0 0 0 那我們在setbit b1 7 1 ,其實對應(yīng)的就是:0 1 0 0 0 0 0 1,這時候gei b1 就是A了,因為這個01000001在ASCII里對應(yīng)的是大寫A

那么繼續(xù)setbit b1 9 1 呢?每個字節(jié)等于8位,你這個9相當于第10位,一個字節(jié)放不下了,這時候就會開辟兩個字節(jié)來存儲,會變成如下 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 然后get b1 就又是@了

2、bitpos
含義:查找第start字節(jié)到end字節(jié)之間的值為bit(0/1)的偏移量(匹配到的位的下標,從0開始)。
bitpos 四個參數(shù):key、要找的值(0/1)、從第幾個字節(jié)(1個字節(jié)=8bit)開始找、到第幾個字節(jié)結(jié)束

注意:最后兩個參數(shù)是從第幾個字節(jié)到第幾個字節(jié),這里是字節(jié),可不是位。剛才b1來看,我們setbit了三次,分別是1 7 9,1和7在第一個字節(jié)上(因為1字節(jié)=8位),9在第二個字節(jié)上。所以可以寫:bitpos b1 1 0 1 ,代表在b1這個key上找第一個字節(jié)到第二個字節(jié)之間第一次值為1的位的下標(也稱偏移量)。

3、bitcount
含義:統(tǒng)計start到end字節(jié)中二進制值為1的個數(shù)。

4、bitop
4.1、概述
可以將多個bitmap進行按位與、按位或的操作,形成一個新的bit。
為了演示按位與和按位或,這里初始化兩個bitmap

4.2、and
將b2和b3兩個key進行按位與操作,結(jié)果存到andkey里

為什么andkey是個@? b2:0100 0001 b3:0100 0010 b2 & b3: 0100 0000 換成10進制是64,在ASCII碼表里這不就是@嘛??!??!
4.3、or
將b2和b3兩個key進行按位或操作,結(jié)果存到orkey里

跟上面按位與一樣,自己算按位或后的二進制,在轉(zhuǎn)換為10進制,得到67,ASCII碼表里67是C
四、利用bitmap完成需求
1、統(tǒng)計某用戶登錄天數(shù)
需求:統(tǒng)計出每個用戶的登錄天數(shù),且支持隨即查看哪天是否登錄過。
需求分析: 假設(shè)每年400天,1byte=8bit。那么每個字節(jié)能存8天的記錄,400/8=50,也就是說50個字節(jié)就能記錄某個人的一年登錄狀態(tài)。
具體實現(xiàn): 假設(shè)zhangsan這個用戶在第2、8、50、365天登錄了,那么先setbit進去(假設(shè)zhangsan的用戶id為123)
# 第2天
127.0.0.1:6380[2]> setbit 123 1 1
# 第8天
127.0.0.1:6380[2]> setbit 123 7 1
# 第50天
127.0.0.1:6380[2]> setbit 123 49 1
# 第364天
127.0.0.1:6380[2]> setbit 123 364 1
然后我們可以采取getbit來獲取某一天是否登錄。還可以利用bitcount來統(tǒng)計他今年登錄了多少天。
# 查看123這個用戶第50天是否登錄
127.0.0.1:6380[2]> getbit 123 49
1
# 查看123這個用戶到今年目前為止最后16天登錄了幾天。之所以-2 -1能管用是因為反向索引,string篇幅說了
127.0.0.1:6380[2]> bitcount 123 -2 -1
1
# 查看123這個用戶今年前八天登錄了幾天
127.0.0.1:6380[2]> bitcount 123 0 0
2
# 查看123這個用戶今年全年登錄了多少天
127.0.0.1:6380[2]> bitcount 123
4
最后我們可以驗證下到底用了多少byte存儲的這個用戶的全年記錄,可以發(fā)現(xiàn)46字節(jié)而已。

2、查看活躍用戶總數(shù)
需求:比如要查看活躍用戶,指定日期區(qū)間,在這區(qū)間登錄過就算活躍。
需求分析: 假設(shè)xiaoming在20200320和20200321這兩天登錄了,而xiaohong只在20200321這一天登錄了。那要怎么存儲呢?首先這個是要以日期作為key,value需要是用戶id所占的bit偏移量位置,比如這兩個用戶xiaoming占用字節(jié)里的第2位,也就是1,因為從0開始。再比如xiaohong占用字節(jié)里的第10位,也就是9。 PS:這個位怎么算都行,只要保證每個用戶所占的字節(jié)偏移量不重復就行(也就是bit位置不重復就行),比如1000w個用戶,那就每個用戶id00w也能得到唯一的一個偏移量。 現(xiàn)在知道xiaoming在第2位,小紅在第10位,也知道了他們哪天登錄過,所以上代碼
具體實現(xiàn):
# xiaoming在20200320登錄
127.0.0.1:6380[2]> setbit 20200320 1 1
# xiaoming在20200321登錄
127.0.0.1:6380[2]> setbit 20200321 1 1
# xiaohong在20200321登錄
127.0.0.1:6380[2]> setbit 20200321 9 1
需求是:在這兩天的任意一天登錄過就算活躍用戶,soeay,直接bitop按或運算完事。然后bitcount統(tǒng)計出人數(shù)。
127.0.0.1:6380[2]> bitop or result 20200320 20200321
# 結(jié)果2人
127.0.0.1:6380[2]> bitcount result
2
疑問:連userid都沒有我只統(tǒng)計人數(shù)有啥用?這需求不可能存在。 回復:搞促銷,登錄送禮品。數(shù)據(jù)庫里10E用戶,你準備多少禮品?10E份?虧大發(fā)。僵尸用戶可能占用一大半。所以需要統(tǒng)計出活躍用戶,然后根據(jù)活躍用戶的數(shù)量在乘以一個比例算出合適的禮品數(shù)量。
五、總結(jié)
- 1字節(jié)=8bit
- setbit
- bitpos
- bitcount
- bitop
- 那兩需求在面試中常被問到
來源:https://www./content-2-894551.html
|