BitMaps
-
數(shù)據(jù)結(jié)構(gòu)模型
現(xiàn)代計算機用二進制(位)作為信息的基礎(chǔ)單位,1個字節(jié)等于8位废赞,例如“big”字符串是由3個字節(jié)組成徽龟,但實際在計算機存儲是將其用二進制表示,“big”分別對應的ASCII碼分別是98唉地、105顿肺、103,對應的二進制分別是01100010渣蜗、01101001屠尊、01100111。
許多開發(fā)語言都提供了操作位的功能耕拷,合理地使用為能夠有效地提高內(nèi)存使用率和開發(fā)效率讼昆。Redis提供了Bitmaps這個“數(shù)據(jù)結(jié)構(gòu)”可以實現(xiàn)對為的操作。吧數(shù)據(jù)結(jié)構(gòu)加上英豪主要因為:
Bitmaps本身不是一種數(shù)據(jù)結(jié)構(gòu)骚烧,實際上它就是個字符串浸赫,但是它可以對字符串的位進行操作。
Bitmaps單獨提供了一套命令赃绊,所以在Redis中使用Bitmaps和使用字符串的方法不太相同既峡。可以把Bigmaps想象成一個以位為單位的數(shù)組碧查,數(shù)組的每個單元只能存儲0和1运敢,數(shù)組的下標在Bitmaps中叫做偏移量校仑。
-
命令
本節(jié)將對每個獨立用戶是否訪問過網(wǎng)站存放在Bigmaps中,將訪問的用戶記做1传惠,沒有訪問的用戶記做0迄沫,用偏移量作為用戶的id。
-
設(shè)置值
setbit key offset value
設(shè)置鍵的第offset個位的值(從0算起)卦方,假設(shè)現(xiàn)在有20個用戶羊瘩,userid=0,5,11,15,19的用戶對網(wǎng)站進行了訪問,那么當前Bitmaps初始化結(jié)果如圖所示盼砍。
2019-04-07-15-33-29.png具體操作過程如下尘吗,unique:user:2019-4-7代表2019-4-7這天的獨立訪問用戶的Bitmaps:
127.0.0.1:6379> setbit unique:users:2019-4-7 0 1 (integer) 0 127.0.0.1:6379> setbit unique:users:2019-4-7 5 1 (integer) 0 127.0.0.1:6379> setbit unique:users:2019-4-7 11 1 (integer) 0 127.0.0.1:6379> setbit unique:users:2019-4-7 15 1 (integer) 0 127.0.0.1:6379> setbit unique:users:2019-4-7 19 1 (integer) 0
如果此時有一個userid=50的用戶訪問了網(wǎng)站,那么Bitmaps的結(jié)構(gòu)中的50位為1.
很多應用的用戶id以一個指定數(shù)字(例如1000)開頭浇坐,直接將yoghurtid和BItmaps的偏移量對應勢必造成一定的浪費睬捶,通常的做法是每次做setbit操作時將用戶id減去這個指定數(shù)字。在第一次初始化Bitmaps是吗跋,加入偏移量非常大侧戴,那么整個初始化過程執(zhí)行會比較大宁昭,可能會造成Redis的阻塞跌宛。
-
獲取值
getbit key offset
獲取鍵的第offset位的值(從0開始算),下面操作獲取id=8的用戶是否在2019-4-7這天訪問過积仗,返回0說明沒有訪問過:
127.0.0.1:6379> getbit unique:users:2019-4-7 8 (integer) 0
由于offset=1000000根本不存在疆拘,所以返回結(jié)果也是0:
127.0.0.1:6379> getbit unique:users:2019-4-7 1000000 (integer) 0
-
獲取Bitmaps指定范圍值為1的個數(shù)
bitcount [start] [end]
下面操作計算2019-4-7這天的獨立訪問用戶數(shù)量:
127.0.0.1:6379> bitcount unique:users:2019-4-7 (integer) 5
[start]和[end]代表其實和結(jié)束字節(jié)數(shù),下面操作計算用戶id在第1字節(jié)到第3字節(jié)之間的獨立訪問用戶數(shù)寂曹,對應的用戶id是11,15,19.
127.0.0.1:6379> bitcount unique:users:2019-4-7 1 3 (integer) 3
-
Bitmaps間的運算
bitop op destkey key [key ...]
bitop是一個復合操作哎迄,它可以做多個Bitmaps的and(交集)、or(并集)隆圆、not(非)漱挚、xor(異或)操作并將結(jié)果保存在destkey中。假設(shè)2019-4-6訪問網(wǎng)站的userid=1,2,5,9渺氧,2019-4-7訪問網(wǎng)站的userid=0,1,4,9 旨涝。
下面操作計算出兩天都訪問過網(wǎng)站的用戶數(shù)量
127.0.0.1:6379> bitop and unique:users:and:2019-4-6_7 unique:users:2019-4-6 unique:users:2019-4-7 (integer) 2 127.0.0.1:6379> bitcount unitque:users:and:2019-4-6_7 (integer) 2
-
計算Bitmaps中第一個值為targetBit的偏移量
bitops key targetBit [start] [end]
下面操作計算2019-4-7當前訪問網(wǎng)站的最小用戶id:
127.0.0.1:6379> bitops unique:users:2019-4-7 1 (integer) 1
除此之外,bitops有兩個選項[start]和[end]侣背,分別代表起始字節(jié)和結(jié)束字節(jié)白华,例如計算第0個字節(jié)到第1個字節(jié)之間,第一個值為0的偏移量贩耐。
127.0.0.1:6379> bitops unique:users:2019-4-7 0 0 1 (integer) 0
-
-
Bitmaps分析
假設(shè)網(wǎng)站有1億用戶弧腥,每天獨立訪問的用戶有5千萬,如果每天用集合類型和Bitmaps分別存儲活躍用戶可以得到下表:
數(shù)據(jù)類型 每個用戶id占用空間 需要存儲的用戶量 全部內(nèi)存量 集合類型 64位 50 000 000 64位*50 000 000=400MB Bitmaps 1位 100 000 000 1位*100 000 000=12.5MB 很明顯潮太,這種情況下使用Bitmaps能節(jié)省很多的內(nèi)存空間管搪,尤其是隨著時間推移節(jié)省的內(nèi)存還是非常可觀,如下表:
數(shù)據(jù)類型 一天 一個月 一年 set 400M 12G 144G Bitmaps 12.5M 375M 4.5G 但Bitmaps并不是萬金油抛蚤,加入該網(wǎng)站每天的獨立訪問用戶很少台谢,例如只有10萬(大量的僵尸用戶),那么兩者的對比如下表所示岁经,很顯然朋沮,這時候使用Bitmaps就不太格式,因為基本上大部分為都是0.
數(shù)據(jù)類型 每個用戶id占用空間 需要存儲的用戶量 全部內(nèi)存量 集合類型 64位 100 000 64位*100 000=800KB Bitmaps 1位 100 000 000 1位*100 000 000=12.5MB