Redis位图Bitmaps详解

概念

  • Redis提供的Bitmaps这个“数据结构”可以实现对位的操作。Bitmaps本身不是一种数据结构,实际上就是字符串,但是它可以对字符串的位进行操作。

  • 可以把Bitmaps想象成一个以位为单位的数组,数组中的每个单元只能存0或者1,数组的下标在bitmaps中叫做偏移量。

  • 单个bitmaps的最大长度是512MB,即2^32个比特位。

例如字符串A 一个字节,对应的ASCII码是65,对应的二进制就是01000001,Bitmaps就是对A的二进制位进行操作。

命令

SETBIT
SETBIT key offset value
summary: Sets or clears the bit at offset in the string value stored at key

设置键的第offset个位的值,value只有0和1两个值

字符串A在位数组的 1和7两个位置是1(从0算起)

127.0.0.1:6379[1]> setbit k1 1 1
(integer) 0
127.0.0.1:6379[1]> setbit k1 7 1
(integer) 0
127.0.0.1:6379[1]> get k1
"A"
127.0.0.1:6379[1]> strlen k1
(integer) 1

对 位1和7设置成1,可以得到字符串A,这时k1只有8位,1个字节,所以长度为1,接下来再对k1进行如下设置

127.0.0.1:6379[1]> setbit k1 9 1
(integer) 0
127.0.0.1:6379[1]> setbit k1 14 1
(integer) 0
127.0.0.1:6379[1]> get k1
"AB"
127.0.0.1:6379[1]> strlen k1
(integer) 2

这时k1的值是如下图,占2个字节

GETBIT
GETBIT key offset
summary: Returns the bit value at offset in the string value stored at key

获取键的第offset位的值

127.0.0.1:6379[1]> getbit k1 1
(integer) 1
127.0.0.1:6379[1]> getbit k1 2
(integer) 0
BITCOUNT
BITCOUNT key [start end]
summary: Count set bits in a string

获取指定范围值为1的个数,其中start和end代表起始和结束字节数

127.0.0.1:6379[1]> bitcount k1 0 0
(integer) 2
127.0.0.1:6379[1]> bitcount k1 1 1
(integer) 2
127.0.0.1:6379[1]> bitcount k1 0 1
(integer) 4
BITPOS
BITPOS key bit [start] [end]
summary: Find first bit set or clear in a string

计算Bitmaps中的第一值为0或者1的偏移量,start和end分别代表起始字节和结束字节

127.0.0.1:6379[1]> bitpos k1 1 0 0
(integer) 1
127.0.0.1:6379[1]> bitpos k1 1 1 1
(integer) 9
127.0.0.1:6379[1]> bitpos k1 0 1 1
(integer) 8

对比上图k1值的位数组进行验证

BITOP
BITOP operation destkey key [key ...]
summary: Perform bitwise operations between strings

bitop是一个复合操作,可以做多个Bitmaps的andornotxor操作。

operation 可以是 ANDORNOTXOR 这四种操作中的任意一种:

  • 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

设置k2 01000001

127.0.0.1:6379[1]> setbit k2 1 1
(integer) 0
127.0.0.1:6379[1]> setbit k2 7 1
(integer) 0
127.0.0.1:6379[1]> get k2
"A"

设置k3 01000010

127.0.0.1:6379[1]> setbit k3 1 1
(integer) 0
127.0.0.1:6379[1]> setbit k3 6 1
(integer) 0
127.0.0.1:6379[1]> get k3
"B"

AND

127.0.0.1:6379[1]> bitop and anddest k2 k3
(integer) 1
127.0.0.1:6379[1]> get anddest
"@"

k2 01000001 和 k3 01000010做与运算(有0为0,全1为1) 结果 01000000 对应的ASCII码是@

OR

127.0.0.1:6379[1]> bitop or ordest k2 k3
(integer) 1
127.0.0.1:6379[1]> get ordest
"C"

k2 01000001 和 k3 01000010做或运算(有1为1全0为0) 结果 01000011 对应的ASCII码是C

XOR

127.0.0.1:6379[1]> bitop xor xordest k2 k3
(integer) 1
127.0.0.1:6379[1]> get xordest
"\x03"

k2 01000001 和 k3 01000010做异或运算(相同为0,不同为1) 结果 00000011 对应的十六进制\x03 十进制下3

NOT

127.0.0.1:6379[1]> bitop not notdest k2 
(integer) 1
127.0.0.1:6379[1]> get notdest
"\xbe"

k2 01000001 做非运算(非0则1,非1则0) 结果是 10111110 对应的十六进制\xbe

BITFIELD
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
summary: Perform arbitrary bitfield integer operations on strings

redis3.2后新增了一个bitfield命令,可以一次对多个位进行操作.这个指令有三个子指令,get,set,incrby,都可以对指定位片段进行读写,但最大支持 64 位长的有符号整数以及 63 位长的无符号整数, 其中无符号整数的 63 位长度限制是由于 Redis 协议目前还无法返回 64 位长的无符号整数而导致的。。

BITFIELD 命令支持的子命令:

  • GET <type> <offset> —— 返回指定的二进制位范围。
  • SET <type> <offset> <value> —— 对指定的二进制位范围进行设置,并返回它的旧值。
  • INCRBY <type> <offset> <increment> —— 对指定的二进制位范围执行加法操作,并返回它的旧值。用户可以通过向 increment 参数传入负值来实现相应的减法操作。

除了以上三个子命令之外, 还有一个子命令, 它可以改变之后执行的 INCRBY 子命令在发生溢出情况时的行为:

  • OVERFLOW [WRAP|SAT|FAIL]

当被设置的二进制位范围值为整数时, 用户可以在类型参数的前面添加 i 来表示有符号整数, 或者使用 u 来表示无符号整数。 比如说, 我们可以使用 u8 来表示 8 位长的无符号整数, 也可以使用 i16 来表示 16 位长的有符号整数。

127.0.0.1:6379[1]> set k4 A 
OK
#A对应的二进制 01000001
#从第1个位开始读取4个位 0100 结果为无符号数(u)
127.0.0.1:6379[1]> bitfield k4 get u4 0
1) (integer) 4
#从第2个位开始读取2个位 10 结果为无符号数(u)
127.0.0.1:6379[1]> bitfield k4 get u2 1
1) (integer) 2
#从第0个位开始读取3个位 010 结果为有符号数(i)
127.0.0.1:6379[1]> bitfield k4 get i3 0
1) (integer) 2
#从第1个位开始读取5个位 10000 结果为有符号数(i) 首位是1代表负数,对10000减1 -> 01111 取反 -> 10000 十进制下是16,由于符号位是1,所以结果是-16
127.0.0.1:6379[1]> bitfield k4 get i5 1
1) (integer) -16

二进制位和位置偏移量

在二进制位范围命令中, 用户有两种方法来设置偏移量:

  • 如果用户给定的是一个没有任何前缀的数字, 那么这个数字指示的就是字符串以零为开始(zero-base)的偏移量。
  • 另一方面, 如果用户给定的是一个带有 # 前缀的偏移量, 那么命令将使用这个偏移量与被设置的数字类型的位长度相乘, 从而计算出真正的偏移量。
127.0.0.1:6379[1]> BITFIELD k5 SET i8 #0 100
1) (integer) 0
127.0.0.1:6379[1]> BITFIELD k5 SET i8 #1 200
1) (integer) 0
# 01100100 11001000

命令会把 k5 键里面, 第一个 i8 长度的二进制位的值设置为 100 , 并把第二个 i8 长度的二进制位的值设置为 200 。 当我们把一个字符串键当成数组来使用, 并且数组中储存的都是同等长度的整数时, 使用 # 前缀可以让我们免去手动计算被设置二进制位所在位置的麻烦。

应用

统计用户登录天数

构建长度为天数365的位数组,哪天登录过,设置value为1,这样每个用户最多占用46个字节

127.0.0.1:6379[1]> setbit jack 1 1 #第2天登录过
(integer) 0
127.0.0.1:6379[1]> setbit jack 8 1 #第9天登录过
(integer) 0
127.0.0.1:6379[1]> setbit jack 364 1 #第365天登录过
(integer) 0
127.0.0.1:6379[1]> strlen jack
(integer) 46
127.0.0.1:6379[1]> bitcount jack  #登录的天数
(integer) 3
统计每天的活跃用户数量

位数组,每一位代表用户的ID

127.0.0.1:6379[1]> setbit 2020-11-11 1 1 	#用户ID为1用户活跃
(integer) 0
127.0.0.1:6379[1]> setbit 2020-11-11 30 1   #用户ID为30用户活跃
(integer) 0
127.0.0.1:6379[1]> setbit 2020-11-11 184 1  #用户ID为184用户活跃
(integer) 0
127.0.0.1:6379[1]> bitcount 2020-11-11		#统计2020-11-11的活跃量
(integer) 3

像签到、点赞、评论数都可以用Bitmaps来实现

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值