Redis之操作位图

1 示例

用户一年的签到记录,如果你用String类型来存储,那则需要365个 key/value来存储,操作起来麻烦。通过位图可以有效的简化这个操作。

它的统计很简单

011110001110没签到,1签到)(每一个占1比特,8比特就是1字节)

每天的记录占一个位,365天就是365个位,大概46个字节,这样可以有效的节省存储空间,如果有一天想要通过用户一共签到了多少天,统计1的个数即可。

对于位图的操作,可以直接操作对应的字符串(get/set),可以直接操作位(getbit/setbit)

2 操作

Redis的基础操作可以归为两大类:

2.1 零存整取

存的时候是位,但获取的时候是直接获取字符串

例如存储一个java字符串

字符ASCII二进制
J7401001010
a9701100001
v11801110110
74=64+8+2
97=64+32+1
118=64+32+16+4+2

接下来去存储:

127.0.0.1:6379> setbit n 1 1
(integer) 0
127.0.0.1:6379> setbit n 4 1
(integer) 0
127.0.0.1:6379> setbit n 6 1
(integer) 0
127.0.0.1:6379> get n
"J"
127.0.0.1:6379> setbit n 9 1
(integer) 0
127.0.0.1:6379> setbit n 10 1
(integer) 0
127.0.0.1:6379> setbit n 15 1
(integer) 0
127.0.0.1:6379> get n
"Ja"
127.0.0.1:6379> setbit n 17 1
(integer) 0
127.0.0.1:6379> setbit n 18 1
(integer) 0
127.0.0.1:6379> setbit n 19 1
(integer) 0
127.0.0.1:6379> setbit n 21 1
(integer) 0
127.0.0.1:6379> setbit n 22 1
(integer) 0
127.0.0.1:6379> get n
"Jav"
127.0.0.1:6379> setbit n 25 1
(integer) 0
127.0.0.1:6379> setbit n 26 1
(integer) 0
127.0.0.1:6379> setbit n 31 1
(integer) 0
127.0.0.1:6379> get n
"Java"
0~7  第一个字符
8~15 第二个字符
16~23 第三个字符
24~31 第四个字符

2.2 整存零取

存的时候是一个字符串,但是通过位操作获取字符串中位的值

127.0.0.1:6379> set k1 www
OK
127.0.0.1:6379> get k1
"www"
127.0.0.1:6379> getbit k1 1
(integer) 1
127.0.0.1:6379> getbit k1 3
(integer) 1
127.0.0.1:6379> getbit k1 23
(integer) 1
127.0.0.1:6379> getbit k1 24
(integer) 0

2.3 统计

例如签到记录:

01111000111

1 表示签到的天,0表示没签到,统计总的签到天数:

可以使用bitcount(统计字符串里面1的个数)

127.0.0.1:6379> set name java
OK
127.0.0.1:6379> bitcount name
(integer) 15

bitcount中,可以统计里面的起始位置,但是注意,这个起始位置是指字符串的起始位置而不是bit的起始位置。

127.0.0.1:6379> bitcount name 0 0
(integer) 4
127.0.0.1:6379> bitcount name 0 1
(integer) 7

bitpos:统计(查找指定范围内出现的第一次0或1的位置),这个命令中的起始和结束位置都是字符索引,不是bit索引,一定要注意

127.0.0.1:6379> bitpos name 1
(integer) 1
127.0.0.1:6379> bitpos name 0
(integer) 0
127.0.0.1:6379> bitpos name 0 1 1
(integer) 8

查找从1到1中第一个0的位置,即a里面第一个出现0的位置

2.4 Bit批处理

在Redis3.2之后,新加的一个功能叫做bitfield,可以对bit进行批量操作。

例如:

bitfield name get u4 0

表示获取name中的位,从0开始获取,获取4个位,返回一个无符号数字(u表示无符号)。
(i表示有符号):有符号的话,第一个符合就表示符号位,1表示一个负数

01000011中的4位就是0100=4
127.0.0.1:6379> BITFIELD name get u4 0
1) (integer) 6
01001010   J:u4 11001) 等于8+1=9
           J:i4 1  等于-8+1=-7

bitfield也可以一次执行多个操作

  • get:
127.0.0.1:6379> bitfield name get u4 0 get i4 0 get u4 1 get i4 1
1) (integer) 6
2) (integer) 6
3) (integer) 13
4) (integer) -3
  • set:
127.0.0.1:6379> bitfield name set u8 8 98
1) (integer) 97
127.0.0.1:6379> get name
"jbva"

从第8位开始,把之前的无符号的替代掉,就是用b替代a。
用无符号的98转成的8位二进制数字,代替从第8位开始接下来的8位数字。

  • incrby:
    对指定范围进行自增操作,自增操作可能会出现溢出,既可能向上溢出,也可能是向下溢出,Redis中对于溢出的处理方案是折返。8位无符号数255加1溢出变为0;8位有符号数127,加1变为-128
127.0.0.1:6379> bitfield name incrby u2 6 1
1) (integer) 3
127.0.0.1:6379> get name
"Kava"
127.0.0.1:6379> bitfield name incrby u2 6 1
1) (integer) 0
127.0.0.1:6379> get name
"Hava"

Java 的前8位:01001010
从第6位开始,选2位加一,10变11
继续加一,溢出,11变00

也可以修改默认的溢出策略,可以改为fail,表示执行失败

127.0.0.1:6379> bitfield name overflow fail incrby u2 6 1 
1) (integer) 1
127.0.0.1:6379> bitfield name overflow fail incrby u2 6 1 
1) (integer) 2
127.0.0.1:6379> bitfield name overflow fail incrby u2 6 1 
1) (integer) 3
127.0.0.1:6379> bitfield name overflow fail incrby u2 6 1 
1) (nil)
127.0.0.1:6379> get name
"Kava"
  • sat表示留在最大/最小值
    定义规则停留在最大或者最小值
127.0.0.1:6379> bitfield name overflow sat incrby u2 6 1 
1) (integer) 3
127.0.0.1:6379> bitfield name overflow sat incrby u2 6 1
1) (integer) 3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值