在Redis
中,位图 Bitmaps
不是实际的数据结构,而是 string
字符串类型上定义的一组 位操作。
在 Redis
中字符串限制最大为 512MB
,所以位图中最大可以设置 2^32
个不同的位(42.9
亿个)。图位的最小单位是比特(bit
),每个bit
的值只能是0
或1
。
1 基本命令
SETBIT key offset value
设置指定key
的值在offset
处的bit
值,offset
从0
开始(从左边开始)。返回值为在offset
处原来的bit
值。
127.0.0.1:6379> set h h # 首先设置一个字符串,key=h,value=“h”,二进制为 01101000
OK
127.0.0.1:6379> get h
"h"
127.0.0.1:6379> setbit h 7 1 # 通过setbit修改h的offset=7位置的bit为1
(integer) 0
127.0.0.1:6379> get h # 修改之后,二进制变成了 01101001,也就是"i"
"i"
GETBIT key offset
获取指定key
值在offset
处的bit
值,offset
从0
开始(从左边开始)。如果offset
超出了当前位图的范围,则返回0
。
127.0.0.1:6379> get h # “i”的二进制为 01101001
"i"
127.0.0.1:6379> getbit h 7 # offset=7的bit值为1
(integer) 1
127.0.0.1:6379> getbit h 8 # offset=8,超出了位图范围,返回的值为0
(integer) 0
BITCOUNT key [start end]
统计指定key
值中被设置为1
的bit
数。可以通过指定参数star
和end
来限制统计范围。
注意:这里的
star
和end
不是指bit
的下标,而是字节(byte
)的下标。比如start
为1
,则实际对应的bit
下标为8
(1byte = 8 bit
)。
127.0.0.1:6379> set hi hi
OK
127.0.0.1:6379> get hi # 二进制为 0110100001101001
"hi"
127.0.0.1:6379> bitcount hi # 所有是1的位数:7个
(integer) 7
127.0.0.1:6379> bitcount hi 1 2 # 统计 01101001 中1的位数
(integer) 4
BITPOS key bit [start] [end]
统计首次出现的0
或1
的bit
位,可以通过start
和end
来指定范围,同样是指字节的下标。
- 在不存在的
key
或者空字符串中查找1
,则返回-1
- 在所有
bit
都为1
中查找bit
为0
的情况下,返回字符串最右边的第一个空位
127.0.0.1:6379> get nilkey # 不存在的key
(nil)
127.0.0.1:6379> bitpos nilkey 1 # 在不存在的key中查首次出现1的位
(integer) -1
127.0.0.1:6379> setbit nilkey 0 0 # 空字符串
(integer) 0
127.0.0.1:6379> get nilkey
"\x00"
127.0.0.1:6379> bitpos nilkey 1
(integer) -1
BITOP operation destkey key [key …]
对一个或多个二进制位字符串进行操作,并将结果保存到 destkey
上。当某个字符串长度不够时,对应的位用0
补上。
- AND(逻辑与):都为
1
返回1
,否则返回0
127.0.0.1:6379> set a a # 二进制 01100001
OK
127.0.0.1:6379> get a
"a"
127.0.0.1:6379> set c c # 二进制 01100011
OK
127.0.0.1:6379> get c
"c"
127.0.0.1:6379> bitop and a_and_c a c # 与操作 01100001 -> a
(integer) 1
127.0.0.1:6379> get a_and_c
"a"
- OR(逻辑或):只要有一个1就返回1,否则返回0
127.0.0.1:6379> set a a
OK
127.0.0.1:6379> get a
"a"
127.0.0.1:6379> set c c
OK
127.0.0.1:6379> get c
"c"
127.0.0.1:6379> bitop or a_or_c a c
(integer) 1
127.0.0.1:6379> get a_or_c
"c"
- XOR(逻辑异或):当都是0或者都是1时返回0,否则返回1
127.0.0.1:6379> set a a
OK
127.0.0.1:6379> get a
"a"
127.0.0.1:6379> set c c
OK
127.0.0.1:6379> get c
"c"
127.0.0.1:6379> bitop xor a_xor_c a c
(integer) 1
127.0.0.1:6379> get a_xor_c
"\x02"
- NOT(逻辑非):取反,1变成0,0变成1。只能传入一个要操作的key。
127.0.0.1:6379> set a a
OK
127.0.0.1:6379> get a
"a"
127.0.0.1:6379> bitop not not_a a
(integer) 1
127.0.0.1:6379> get not_a
"\x9e"
2 利用位图统计签到
位图可以用于统计签到的场景。
大致思路:
- 每天的签到情况作为一条记录,key 的格式为
sign:{yyyyMMdd}
; - 将用户 id 作为偏移量 offset,通过
SETBIT
操作设置 id 位置的值为 1; - 将用户 id 作为偏移量 offset,通过
GETBIT
操作查询这一天该用户是否签到; - 通过
BITCOUNT
统计今天所有签到的用户数量;