学习目标:
1、了解Redis对位图的操作命令
2、了解位图的应用
学习过程:
计算机基础我们都学习过:一个字节(Byte)等于8个位(bit),一个英文字母可以由字节(Byte)表示,Redis支持直接操作位(bit),redis的操作位的命令主要有
1、GETBIT key offset
对 key 所储存的字符串值,获取指定偏移量上的位(bit)。当 offset 比字符串值的长度大,或者 key 不存在时,返回 0 。
2、SETBIT key offset value
设置指定偏移量上的位(bit)
3、 BITCOUNT key [start end]
统计指定位区间上值为1的个数,从左向右从0开始,从右向左从-1开始,注意start和end是字节
BITCOUNT testkey 0 0 表示从索引0个字节到索引0个字节,就是第一个字节的统计
BITCOUNT testkey 0 -1 等同于BITCOUNT testkey
4、BITPOS key value start end
指定区间查询某个key的二进制位中出现0或1的位置,注意start和end是字节,返回的偏移量是从开头算的。
start 和 end 参数是字节索引,也就是说指定的位范围必须是 8 的倍数,而不能任意指定。
5、BITOP operation destkey key [key ...]
对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种:
BITOP AND destkey key [key ...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。
BITOP OR destkey key [key ...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。
BITOP XOR destkey key [key ...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。
BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey 。
6、BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
BITFIELD 有三个子命令:
GET <type> <offset> – 返回指定的位域
SET <type> <offset> <value> – 设置指定位域的值并返回它的原值
INCRBY <type> <offset> <increment> – 自增或自减(如果increment为负数)指定位域的值并返回它的新值
还有一个命令通过设置溢出行为来改变调用INCRBY指令的后序操作:
OVERFLOW [WRAP|SAT|FAIL]
用GET指令对超出当前字符串长度的位(含key不存在的情况)进行寻址,执行操作的结果会对缺失部分的位(bits)赋值为0。
用SET或INCRBY指令对超出当前字符串长度的位(含key不存在的情况)进行寻址,将会扩展字符串并对扩展部分进行补0,扩展方式包括:按需扩展、按最小长度扩展和按最大寻址能力扩展。
二、示例
比较简单的setbit和getbit
127.0.0.1:6379> setbit work 0 1
(integer) 0
127.0.0.1:6379> setbit work 1 1
(integer) 0127.0.0.1:6379> setbit work 5 1
(integer) 0
127.0.0.1:6379> getbit work 0
(integer) 1
127.0.0.1:6379> getbit work 3
(integer) 0
前面我们说过字符也是以字节保存的,所以我们可以拿到任何一个字符串对应的位信息
127.0.0.1:6379> set string abc
OK
127.0.0.1:6379> getbit string 0
(integer) 0
127.0.0.1:6379> getbit string 1
(integer) 1127.0.0.1:6379> setbit string 0 1 #改变后不能识别了。
(integer) 0
127.0.0.1:6379> get string
"\xe1bc"
统计1的数量
127.0.0.1:6379> bitcount string 0 0
(integer) 4
第一次出现1,和第一次出现0的位置
127.0.0.1:6379> bitpos string 1 0 0
(integer) 0
127.0.0.1:6379> bitpos string 0 0 0
(integer) 3
两个位图取与的操作
127.0.0.1:6379> set s1 a
OK
127.0.0.1:6379> set s2 b
OK
127.0.0.1:6379> bitop and result s1 s2
(integer) 1
bitfield 的操作,bitfield可以对一串字节进行操作
127.0.0.1:6379> set w liubao
OK
取值
127.0.0.1:6379> bitfield w get i6 1 #从第一个位开始取 4 个位,结果是有符号数 (i)
1) (integer) -10
127.0.0.1:6379> bitfield w get u6 1 #从第一个位开始取 4 个位,结果是有符号数 (i)
1) (integer) 54
设置
127.0.0.1:6379> bitfield w set u8 8 97
1) (integer) 105
127.0.0.1:6379> get w
"laubao"
加法操作
127.0.0.1:6379> bitfield w incrby u4 2 1
1) (integer) 12
127.0.0.1:6379> get w
"paubao"
bitfield 指令提供了溢出策略子指令 overflow,用户可以选择溢出行为,默认是折返 (wrap),还可以选择失败 (fail) 报错不执行,以及饱和截断 (sat)
如:
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 13
最后在jredis中也是使用对字符串的操作操作位图的,这里就不展开了:
boolean result = template.opsForValue().setBit("w", 1, true);
可能你会觉得这个位图好像用途也不是很大,但是后面我们马上要学习的HyperLogLog和bloom filter布隆过滤器后台实现都有依赖位图的功能。