简介

Bitmaps are not an actual data type, but a set of bit-oriented operations defined on the String type which is treated like a bit vector. Since strings are binary safe blobs and their maximum length is 512 MB, they are suitable to set up to 2^32 different bits.

引用自官方文档。简单来说就是这个bitmaps不是一个实际的数据类型,而是字符串类型上定义的一组面向bit位操作,最大长度为512MB,可以存储2^32个不同的位。

基本命令

根据文档得知Bitmaps一共有7个操作命令,分别是:BITCOUNT BITFIELD BITFIELD_RO BITOP BITPOS GETBIT SETBIT,这里先详细介绍一下常用的几个命令。

  1. ✨SETBIT
    • 语法:SETBIT key offset value
    • 用途:将key的bit下标为offset的值设为value
    • 文档:redis.io
      -- 将key1的bit下标为3位(后面简称第0位,第3位...)设值为1
      SETBIT key1 3 1
      (integer) 0
      -- 这里回显的是该位修改之前的数据值

      可以看到从左到右第3位的值为1,其余位为0

    如果此时setbit key1 8 1,则会自动扩容一个字节,扩容后的值为:

  2. ✨GETBIT
    • 语法:GETBIT key offset
    • 用途:获取key的bit下标位offset的值
    • 文档:redis.io
      -- 获取第3位的值
      [db15] > getbit key1 3
      (integer) 1
      -- 获取第8位的值
      [db15] > getbit key1 8
      (integer) 1
      -- 获取第0位的值
      [db15] > getbit key1 0
      (integer) 0
  3. ✨BITCOUNT
    • 语法:BITCOUNT key [start end [BYTE | BIT]]
    • 用途:统计所有或指定区间区间内1的数量
    • 文档:redis.io
      -- 再设置几位,便于举例
      [db15] > setbit key1 2 1
      (integer) 0
      [db15] > setbit key1 9 1
      (integer) 0
      [db15] > setbit key1 12 1
      (integer) 0
      [db15] > setbit key1 18 1
      (integer) 0
      [db15] > setbit key1 19 1
      (integer) 0
      [db15] > setbit key1 20 1
      (integer) 0
      [db15] > setbit key1 28 1
      (integer) 0
      [db15] > setbit key1 34 1
      (integer) 0
      [db15] > setbit key1 36 1
      (integer) 0
      -- 现在key1的二进制值为 00110000 11001000 00111000 00001000 00101000 便于查看每个字节中间有空格隔开
      -- 第一字节有2个1,第二字节有3个1,第三字节有3个1,第四个字节有1个1,第五个字节有2个1,所以总共有11个1
      -- 获取所有1的数量
      [db15] > bitcount key1
      (integer) 11
      -- 获取第一字节中1的数量 等同于 bitcount key1 0 0 byte
      [db15] > bitcount key1 0 0
      (integer) 2
      [db15] > bitcount key1 0 0 byte
      (integer) 2
      -- 获取第0位到第7位的1的数量
      [db15] > bitcount key1 0 7 bit
      (integer) 2
      -- 获取倒数第二字节到倒数第一字节1的数量 注意:一定要是从左往右的顺序
      [db15] > bitcount key1 -2 -1
      (integer) 3
      -- 获取倒数第4位到倒数第1位1的数量 由此可得 正向下标是从0开始计数,而倒数是从1开始计数
      [db15] > bitcount key1 -4 -1 bit
      (integer) 1
  4. ✨BITPOS
    • 语法:BITPOS key bit [start [end [BYTE | BIT]]]
    • 用途:获取所有或指定区间内第一个指定bit值[0 | 1]的下标
    • 文档:redis.io
      -- key1: 00110000 11001000 00111000 00001000 00101000
      -- 获取第一个0值的下标
      [db15] > bitpos key1 0
      (integer) 0
      -- 获取第一个1值的下标
      [db15] > bitpos key1 1
      (integer) 2
      -- 从第1位开始到第四位的第一个1的下标 这里的下标还是总数据的下标
      [db15] > bitpos key1 1 1 4 bit
      (integer) 2
      -- 如果没有则返回-1 如果key不存在也返回-1
      [db15] > bitpos key1 1 4 6 bit
      (integer) -1
      -- 从第二字节到第二字节的第一个1的下标
      [db15] > bitpos key1 1 2 2 byte
      (integer) 18
  5. ✨BITOP
    • 语法:BITOP <AND | OR | XOR | NOT> destkey key [key …]
    • 用途:对多个key进行位运算(与 &,或 |,异或 ^,非或者叫取反 ~),结果保存到destkey中
    • 文档:redis.io
      [db15] > setbit op1 1 1
      (integer) 0
      [db15] > setbit op1 3 1
      (integer) 0
      [db15] > setbit op1 5 1
      (integer) 0
      [db15] > setbit op2 4 1
      (integer) 0
      [db15] > setbit op2 6 1
      (integer) 0
      [db15] > bitop and d1 op1 op2
      (integer) 1
      -- op1: 01010100
      -- op2: 00001010
      -- d1: 00000000
      [db15] > bitop or d2 op1 op2
      (integer) 1
      -- d2: 01011110
      [db15] > bitop xor d3 op1 op2
      (integer) 1
      -- d3: 01011110
      [db15] > bitop not d4 op1
      (integer) 1
      -- d4: 10101011

实际应用

由上述的操作命令可以看出,Bitmaps的应用场景主要是统计和判断,比如签到,活跃用户,用户在线状态等等。这里以签到为例,假设有一个用户id为1,每天签到一次,那么可以用一个key来存储用户的签到情况,比如key为sign:1,可以处理的场景大概有:

  • 用户签到
  • 查询用户某天是否签到
  • 统计指定用户的累计签到天数
  • …… 自己发挥想象
    -- 用户签到  记录用户ID为1的用户第一天签到
    [db15] > setbit sign:1 0 1
    -- 用户签到 记录用户ID为1的用户第二天签到 后面以此类推
    [db15] > setbit sign:1 1 1

    -- 查询用户ID为1的用户第一天是否签到
    [db15] > getbit sign:1 0

    -- 统计用户ID为1的用户的累计签到天数
    [db15] > bitcount sign:1

    -- 统计用户ID为1的用户在前七天的签到情况
    [db15] > bitcount sign:1 0 6

留个坑等后面填

BITFIELD 和 BITFIELD_RO 的详细使用暂时没有介绍,等后续有时间再补充!