【Redis】数据类型:bitmap


8.redis位图(bitmap)

一句话:由0和1状态表现的二进制位的bit数组

看需求:

  1. 用户是否登陆过Y、N,比如软件的每日签到功能
  2. 电影、广告是否被点击播放过
  3. 钉钉打卡上下班,签到统计
img
img

现代计算机用二进制(位),作为信息的基础单位,1个字节等于8位。

例如“abc”字符串,是由3个字节组成,但实际在计算机存储时将其用二进制表示, “abc”分别对应的ASCII码分别是97、 98、 99,对应的二进制分别是01100001、01100010和01100011,如下图

img
img

合理地使用操作位,能够有效地提高内存使用率和开发效率。

Redis提供了Bitmaps这个“数据类型”可以实现对位的操作:

1)Bitmaps本身不是一种数据类型,实际上它就是字符串(key-value),但是它可以对字符串的位进行操作。

2)Bitmaps单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同。可以把Bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在Bitmaps中叫做偏移量。

img
img

说明:用String类型作为底层数据结构,实现的一种统计二值状态的数据类型

位图本质是数组,它是基于String数据类型的按位的操作。该数组由多个二进制位组成,每个二进制位都对应一个偏移量(我们称之为一个索引)。

Bitmap支持的最大位数是2^32位,它可以极大的节约存储空间,使用512M内存就可以存储多达42.9亿的字节信息(2^32=4294967296)

常用命令

(1)setbit

a、格式
setbit <key> <offset> <value>      设置Bitmaps中某个偏移量的值(0或1)
offset:偏移量从0开始

b、实例

每个独立用户是否访问过网站存放在Bitmaps中,将访问的用户记1,没有访问的用户记0,用偏移量作为用户的id。

设置键的第offset个位的值(从0算起),假设现在有20个用户,userid=1,6,11,15,19的用户对网站进行了访问,那么当前Bitmaps初始化结果如图

img
img

unique:users:20201106 代表2020-11-06这天的独立访问用户的Bitmaps

img
img

注:很多应用的用户id以一个指定数字(例如10000)开头, 直接将用户id和Bitmaps的偏移量对应势必会造成一定的浪费,通常的做法是每次做setbit操作时将用户id减去这个指定数字。

在第一次初始化Bitmaps时,假如偏移量非常大,那么整个初始化过程执行会比较慢,可能会造成Redis的阻塞。

Bitmap的偏移量从零开始计算的

img
img
img
img

(2)getbit

a、格式
getbit<key><offset>     获取Bitmaps中某个偏移量的值

获取键的第offset位的值(从0开始算)
b、实例
获取id=8的用户是否在2020-11-06这天访问过, 返回0说明没有访问过:

img
img
img
img

(3)bitcount

统计字符串被设置为1的bit数

一般情况下,给定的整个字符串都会被进行计数,通过指定额外的start或end参数,可以让计数只在特定的位上进行。

start和end参数的设置,都可以使用负数值:比如-1表示最后一个位,而-2表示倒数第二个位,start、end是指bit组的字节的下标数,二者皆包含。

a、格式
bitcount <key> [start end]    统计字符串从start字节到end字节比特值为1的数量
b、实例
计算2022-11-06这天的独立访问用户数量
img
img

start和end代表起始和结束字节数,下面操作计算用户id在第1个字节到第3个字节之间的独立访问用户数,对应的用户id是11,15,19。

img
img
c、举例: 
K1 【01000001 01000000  00000000 00100001】,对应【0,1,2,3】

bitcount K1 1 2 : 统计下标1、2字节组中bit=1的个数,即01000000 00000000
--》bitcount K1 1 2   --》1

bitcount K1 1 3 : 统计下标1、2字节组中bit=1的个数,即01000000 00000000 00100001
--》bitcount K1 1 3  --》3

bitcount K1 0 -2 : 统计下标0到下标倒数第2,字节组中bit=1的个数,即01000001 01000000 00000000
--》bitcount K1 0 -2  --》3

注意:redis的setbit设置或清除的是bit位置,而bitcount计算的是byte位置。

img
img

(4)bitop

a、格式
bitop and(或or/not/xor) <destkey> [key…]

bitop是一个复合操作,它可以做多个Bitmaps的and(交集)、or(并集)、not(非)、xor(异或)操作,并将结果保存在destkey中。
b、实例
2020-11-04 日访问网站的userid=1,2,5,9。
setbit unique:users:20201104 1 1
setbit unique:users:20201104 2 1
setbit unique:users:20201104 5 1
setbit unique:users:20201104 9 1

2020-11-03 日访问网站的userid=0,1,4,9。
setbit unique:users:20201103 0 1
setbit unique:users:20201103 1 1
setbit unique:users:20201103 4 1
setbit unique:users:20201103 9 1

计算出两天都访问过网站的用户数量
bitop and unique:users:and:20201104_03 unique:users:20201103 unique:users:20201104

img
img
img
img

案例:连续2天都签到的用户数量

假如某个网站或者系统,它的用户有1000W,我们可以使用redis的HASH结构,和bitmap结构,做个用户id和位置的映射

img
img
img
img

(5)strlen key

统计字节数占用多少

img
img

不是字符串长度而是占据几个字节,超过8位后自己按照8位一组一byte再扩容

Bitmaps与set对比

假设网站有1亿用户, 每天独立访问的用户有5千万, 如果每天用集合类型和Bitmaps分别存储活跃用户可以得到表。

set和Bitmaps存储一天活跃用户对比

数据类型 每个用户id占用空间 需要存储的用户量 全部内存量
集合类型 64位 50000000 64位*50000000 = 400MB
Bitmaps 1位 100000000 1位*100000000 = 12.5MB

很明显, 这种情况下使用Bitmaps能节省很多的内存空间, 尤其是随着时间推移节省的内存还是非常可观的。

set和Bitmaps存储独立用户空间对比

数据类型 一天 一个月 一年
集合类型 400MB 12GB 144GB
Bitmaps 12.5MB 375MB 4.5GB

但Bitmaps并不是万金油, 假如该网站每天的独立访问用户很少, 例如只有10万(大量的僵尸用户) , 那么两者的对比如下表所示, 很显然, 这时候使用Bitmaps就不太合适了, 因为基本上大部分位都是0。

set和Bitmaps存储一天活跃用户对比(独立用户比较少)

数据类型 每个userid占用空间 需要存储的用户量 全部内存量
集合类型 64位 100000 64位*100000 = 800KB
Bitmaps 1位 100000000 1位*100000000 = 12.5MB
posted @ 2026-06-09 15:08  青柠代码录  阅读(9)  评论(0)    收藏  举报