学习目标:

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布隆过滤器后台实现都有依赖位图的功能。