Redis位图
Posted 架构技术栈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis位图相关的知识,希望对你有一定的参考价值。
上课签到时间到了,张三老师开始点名了,每点一名同学就新增加一条记录,我们数据库会把这条记录写到学生考勤表里,到学期末考核的时候汇总根据学生迟到次数计算总学分。假设一个班级50个学生,一天4课时,一个星期就要记录1000条记录,那么如果说我们根据学生的学号顺序记录学生签到信息,通过“0”和“1”来表示,“1”就代表学生签到,“0”代表学生迟到,那么我们一个星期只要保存20条数据即可。
Redis也有这样的结构名叫位图,位图最小的单位是bit,每个bit是由0或1构成,我们的字符串就是由很多个bit数组组成的,所以我们在使用位图的时候是可以把一组bit转换成字符串,也可以由字符串转换成bit数组。
如下,“h”的ACSLL码是0110 1000
> setbit name 1 1 #设置位图的位置
(integer) 0
> setbit name 2 1
(integer) 0
> setbit name 4 1
(integer) 0
> get name #获取这个位图转换成字符串的值
"h"
> getbit name 1 #获取位图的某个位置是否有值
(integer) 1
> getbit name 3
(integer) 0
字符串转位图
> set kh h #存字符串
OK
> getbit kh 1 #第二个位置的bit是1
(integer) 1
> getbit kh 3 #第四个位置的bit是0
(integer) 0
注意:如果对应位的字节是不可打印字符,redis会显示该字符的十六进制形式。
> setbit x O 1
(integer) 0
> setbit x 1 1
(integer) 0
> get x
"\xc0"
Redis位图提供bitcount和bitpos指令,bitcount用来统计一定范围内1的个数,bitpos用来查找指定范围内出现的第一个0或者1。
这里我们需要注意的是参数start_index和end_index是字节索引,简单的来说就是他们只能是8的倍数而不是指定值。
咱们对照下图来看
> set name hello
OK
#计数所有的1的个数 bitcount name
(integer) 21
0 1 #获取前两个字符出现1的个数 bitcount name
(integer) 7
0 0 #获取第一个字符出现1的个数 bitcount name
(integer) 3
1 #获取第一个1出现的位置 bitpos name
(integer) 1
0 #获取第一个0出现的位置 bitpos name
(integer) 0
1 1 1 #获取第二个字符1出现的位置 bitpos name
(integer) 9
我们通过setbit和getbit指令来操作位图都是一次操作一个位,那么有时候我们需要一次性操作多个位,如何操作呢?
在Redis3.2版本之前我们可以使用管道来一次性操作多个指令,redis给我们提供了bitfield指令,该指令有三个子指令分别是get、set、incrby它们都可以对指定位片段进行读写,但是最多只能处理64个连续的位,如果超过64位,就得使用多个子指令,bitfield 可以一次执行多个子指令。
下面我们来看例子,还是使用上面的name=hello
字母 |
数值 | 二进制 |
h |
104 |
0110 1000 |
e | 101 |
0110 0101 |
l | 108 |
0110 1100 |
l | 108 |
0110 1100 |
o | 111 |
0110 1111 |
> bitfield name get u4 0 #第一个位开始取4个位(0110),结果为无符号数(u)
(integer) 6
> bitfield name get u3 2 #第三个位开始取3个位(101),结果为无符号数(u)
(integer) 5
> bitfield name get i4 0 #第一个位开始取4个位(0110),结果为有符号数(i)
(integer) 6
> bitfield name get i3 2 #第三个位开始取3个位(101),结果为有符号数(i)
(integer) -3
下面我们才试试批处理
> bitfield name get u4 0 get u3 2 get i4 0 get i3 2
(integer) 6
(integer) 5
(integer) 6
(integer) -3
有符号数是指获取的位数组中第一个位是符号位,剩下的才是值。如果第一位是1,那就是负数。无符号数表示非负数,没有符号位,获取的位数组全部都是值。有符号数最多可以获取 64 位,无符号数只能获取 63 位(因为 Redis 协议中的integer是有符号数,最大 64 位,不能传递 64 位无符号值)。
下面我们来使用set,把hello的e变成a,a的ASCLL码是97
set u8 8 97 #从第八位开始,接下来的8位用无符号的ASCLL码97代替 bitfield name
(integer)101
get name
"hallo"
这个指令用来自增,如果自增到最大值的时候会溢出,如果是无符号那么就变成0,如果是有符号的就会变成负数,向下自增反之。
bitfield指令提供溢出策略的指令overflow,用户可以指定类型,默认为:wrap,溢出及折返,还可以选择失败:fail,失败不执行,截断:sat,溢出就停留。
> bitfield name incrby u4 2 1 #从第三个位开始,对接下来的4位元符号数+ 1
(integer) 11
> bitfield name incrby u4 2 1
(integer) 12
> bitfield name incrby u4 2 1
(integer) 13
> bitfield name incrby u4 2 1
(integer) 14
> bitfield name incrby u4 2 1
(integer) 15
####sat
> bitfield name overflow sat incrby u4 2 1 #保持最大值
(integer) 15
####fail
> bitfield name overflow fail incrby u4 2 1 #不执行
(nil)
####wrap
> bitfield name incrby u4 2 1 #溢出折返
(integer) 0
一名正在抢救的coder
笔名:mangolove
以上是关于Redis位图的主要内容,如果未能解决你的问题,请参考以下文章