Redis之bitmap

1.何为bitmap(位图)

引用redis官网的一段话

Bitmaps are not an actual data type, but a set of bit-oriented operations defined on the String type . This means that bitmaps can be used with string commands, and most importantly with SET and GET.

翻译过来就是

位图不是一种实际的数据类型,而是在String类型上定义的一组面向位的操作(有关更多信息,请参阅数据类型简介页面的“位图”部分)。这意味着位图可以用于字符串命令,还可以用SET和GET命令来进行操作

其实更通俗一点就是,其实bitmap就是普通的字符串,可以用set和get命令来设置或者获取整个位图的内容,也可以通过SETBIT和GETBIT命令等命令来设置字符串的某一位

2.bitmap的应用场景

在我们的平常开发中,我们需要存储一些bool类型的值,比如用户在一年内的签到记录,一年有365天,如果我们用普通的key/value来进行存储的话,那么如果用户数量达到一个非常大的量级的话,这对于内存是一个巨大的消耗,所以在这样的场景下我们使用bitmap来存储的话,每一天的签到记录就只占一个位,那么一年的话就是365个bit(不到46个字节)。
在这里插入图片描述

3.bitmap的常用操作命令

  • SETBIT
    SETBIT用来设置某一个位的值,语法如下
SETBIT key offset value
127.0.0.1:6379> SETBIT test1 0 1
(integer) 0     
127.0.0.1:6379> SETBIT test1 2 1
(integer) 0     
127.0.0.1:6379> 

既然前面说了其实位图就相当于字符串,可以用set和get命令来获取内容,我们就来实验一下,我们首先得到字符a的二进制表示

>>> bin(ord('a'))
'0b1100001'    高位->地位

这里二进制表示的从左到右是高位到低位,我们分别看到字符a的二进制从左到右第1/2/7位为1,那我们设置一个第1位,第2位,第7位为1的bitmap来试一下

127.0.0.1:6379> SETBIT a_bit 1 1
(integer) 0     
127.0.0.1:6379> SETBIT a_bit 2 1
(integer) 0     
127.0.0.1:6379> SETBIT a_bit 7 1
(integer) 0     
127.0.0.1:6379> GET a_bit
"a"

这里我们可以看到,通过SETBIT命令设置对应的位之后,我们再通过GET命令获取到的就是字符a, 这也验证了我们前面所说的bitmap就是在redis中的字符串数据类型上进行位操作,为此我们可以再通过字符串you来测试

>>> bin(ord('y'))
'0b1111001'
>>> bin(ord('o'))
'0b1101111'
>>> bin(ord('u'))
'0b1110101'

我们设置第一个字符y只需要设置第1/2/3/4/7位为1,设置第二个字符o字需要设置第9/10/12/13/14/15位为1,设置第三个字符u只需要设置17/18/19/21/23位为1

127.0.0.1:6379> SETBIT MYBIT 1 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 2 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 3 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 4 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 7 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 9 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 10 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 12 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 13 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 14 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 15 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 17 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 18 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 19 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 21 1
(integer) 0
127.0.0.1:6379> SETBIT MYBIT 23 1
(integer) 0
127.0.0.1:6379> GET MYBIT
"you"
  • GETBIT
    获取某个位上的值
GETBIT key offset
127.0.0.1:6379> GETBIT MYBIT 23
(integer) 1
  • BITCOUNT
BITCOUNT key start end

start和end不是必选的,但是需要注意这里的start和end是以字节为单位
统计位图中出现1的个数

127.0.0.1:6379> SET S y
OK
127.0.0.1:6379> BITCOUNT S
(integer) 5  
127.0.0.1:6379> SET W you
OK
127.0.0.1:6379> BITCOUNT W 0 0
(integer) 5 
127.0.0.1:6379> BITCOUNT W 0 1127.0.0.1:6379> BITPOS W 1
(integer) 1  
(integer) 11 

统计W中第一个字节出现1的位数,y字符的二进制表示中刚好有5个1,而yu字符串中有11个1,所以这里在实际使用中不是很好使用,例如统计一个月内用户签到的次数,我们无法通过指定这一个月的起始位和结束位来统计,只能通过统计包含这个月的字节来统计

  • BITPOS
BITPOS key 0/1 start end

统计从开始字节到结束字节中第一次出现0或者1的位

127.0.0.1:6379> SET W you
OK
127.0.0.1:6379> BITPOS W 1       统计第一个字节第一次出现1的位
(integer) 1  
127.0.0.1:6379> BITPOS W 1 1 1   统计第二个字节中第一次出现1的位
(integer) 9 
  • BITFIELD
    前面的命令都是单个位进行设置或者获取,BITFIELD命令可以允许同时操作多个位
    在这里插入图片描述
    这里我们对照上面的图来进行操作(这里字符h是二进制是01101000,e是01100101)
127.0.0.1:6379> SET W hello
OK
127.0.0.1:6379> BITFIELD W get u3 0  从第一位开始取,取3位,结果是无符号整数,u表示是无符号整数
1) (integer) 3 
127.0.0.1:6379> BITFIELD W get u4 1 从第二位开始取,取4位,结果是无符号整数
1) (integer) 13
127.0.0.1:6379> BITFIELD W get i3 1 从第二位开始取,取3位,结果是有符号整数
1) (integer) -2 

解释下上面的语句的含义,
从第一位取三位的话取到的是011,而且结果是无符号整数011转换为10进制3。
从第二位开始取4位,那么取到的是1101,而且结果是无符号整数,这个就是13了。
从第二位取3位作为有符号整数,那么取到的是110,结果是有符号整数,那么第一位是符号位,1表示负数,0表示正数,所以结果就是-2

4.bitmap的最大长度

官方文档介绍,bitmap能操作的最大偏移量是2^32,所以这里也限制了bitmap的最大容量为512MB,而且最后设置的位如果快到了2的32次方,那么就可能会存在阻塞的情况,下面是官方文档的原文

When key does not exist, a new string value is created. The string is grown to make sure it can hold a bit at offset. The offset argument is required to be greater than or equal to 0, and smaller than 2^32 (this limits bitmaps to 512MB). When the string at key is grown, added bits are set to 0.

Warning: When setting the last possible bit (offset equal to 2^32 -1) and the string value stored at key does not yet hold a string value, or holds a small string value, Redis needs to allocate all intermediate memory which can block the server for some time. On a 2010 MacBook Pro, setting bit number 2^32 -1 (512MB allocation) takes ~300ms, setting bit number 2^30 -1 (128MB allocation) takes ~80ms, setting bit number 2^28 -1 (32MB allocation) takes ~30ms and setting bit number 2^26 -1 (8MB allocation) takes ~8ms. Note that once this first allocation is done, subsequent calls to SETBIT for the same key will not have the allocation overhead.

详情可以看官网:redis官网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值