BitMap的使用(1)

1.1.思路分析

当我们做项目的时候肯定遇到过签到功能吧,如果用平常数据库,假如一个用户1年签到100次,而网站有100万用户,就会产生1亿条记录。

随着用户量增多、时间的推移,这张表中的数据只会越来越多,占用的空间也会越来越大。

有没有什么办法能够减少签到的数据记录,减少空间占用呢?

大家回忆一下,小时候上补习班时的签到卡:

在这张小小的卡片上面,就记录了从一个月的第一天到最后一天的所有的签到情况。诶,你今天来上课了那就勾一下,没来就空着。这样呢,通过一个小小的卡片就能够记录一个同学这一个月的签到的情况了。虽然很原始,但是非常高效。

如果我们能用程序来模拟这样的签到卡,用一行数据去记录一个用户一个月的签到情况,可想而知,那比这种数据库的方式是不是要大大地节省空间。

那么问题来了,我们该怎么样去模拟这样的一个签到卡?

其实并不复杂,你想嘛?一个用户签到的情况无非就两种,要么签了,要么没签。这就像我们电路当中的这个二极管,那要么通电,要么不通,那用程序怎么表示这种状态呢?

没错,就是 0 或者1

如果我们按月来统计用户签到信息,签到记录为1,未签到则记录为0,就可以用一个长度为31位的二级制数来表示一个用户一个月的签到情况

我们知道二进制是计算机底层最基础的存储方式了,其中的每一位数字就是计算机信息量的最小单位了,称之为bit,一个月最多也就 31 天,因此一个月的签到记录最多也就使用 31 bit 就能保存了,还不到 4 个字节。

而如果用到我们前面讲的数据库方式来保存相同数据,则要使用数百字节,是这种方式的上百倍都不止。

可见,这种用二进制位保存签到记录的方式,是不是非常高效啊!

像这种把每一个二进制位,与某些业务数据一一映射(本例中是与一个月的每一天映射),然后用二进制位上的数字0和1来标识业务状态的思路,称为位图。也叫做BitMap.

这种数据统计的方式非常节省空间,因此经常用来做各种数据统计。比如大名鼎鼎的布隆过滤器就是基于BitMap来实现的。

OK,那么利用BitMap我们就能直接实现签到功能,并且非常节省内存,还很高效。所以就无需通过数据库来操作了。

那么BitMap该怎么使用呢?

1.2.BitMap用法

Commands | Docs

签到

如果要签到就可以利用上面的这个命令,例如这个月的第1、2、3、6、7、8几天签到了,就可以这样

# 第1天签到
SETBIT bm 0 1
# 第2天签到
SETBIT bm 1 1
# 第3天签到
SETBIT bm 2 1
# 第6天签到
SETBIT bm 5 1
# 第7天签到
SETBIT bm 6 1
# 第8天签到
SETBIT bm 7 1

  最终Redis中保存的效果

查询

那如果我们要查询签到记录怎么办?

那就是要读取BitMap中的数据,可以用这个命令

BITFIELD key GET encoding offset
  • key:就是BitMap的key

  • GET:代表查询

  • encoding:返回结果的编码方式,BitMap中是二进制保存,而返回结果会转为10进制,但需要一个转换规则,也就是这里的编码方式

    • u:无符号整数,例如 u2,代表读2个bit位,转为无符号整数返回

    • i:又符号整数,例如 i2,代表读2个bit位,转为有符号整数返回

  • offset:从第几个bit位开始读取,例如0:代表从第一个bit位开始

例如,我想查询从第1天到第3天的签到记录,可以这样:

BITFIELD bm GET u3 0

拓展

Redis最基础的数据类型只有5种:String、List、Set、SortedSet、Hash,其它特殊数据结构大多都是基于以上5这种数据类型。

BitMap也不例外,它是基于String结构的。因为Redis的String类型底层是SDS,也会存在一个字节数组用来保存数据。而Redis就提供了几个按位操作这个数组中数据的命令,实现了BitMap效果。

由于String类型的最大空间是512MB,也就是2的31次幂个bit,因此可以保存的数据量级是十分恐怖的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值