Redis学习笔记(6)- Bitmap(位图)

1、简介

  位图不是一个真实的数据类型,而是定义在字符串类型上的面向位的操作的集合。由于字符串类型是二进制安全的二进制大对象,并且最大长度是 512MB,适合于设置 2^32个不同的位。
  位图的最大优势是有时是一种非常显著的节省空间来存储信息的方式。例如,比如统计用户是否在线,可以通过将数组中的每个二进制位与用户 ID 进行一一对应, 我们可以使用位图去记录每个用户是否在线。
  简而言之,位图操作是用来操作比特位的,其优点是节省内存空间。在记录用户是否在线的功能中,一个bit位对应一个用户,bit位的0/1可以表示用户是否在线,这样就可以通过一个bit位来表示一个用户是否在线了。

2、Bitmap(位图)命令
  1. SETBIT
    语法: SETBIT key offset value
    时间复杂度: O(1)
    功能: 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
    返回值: 指定偏移量原来储存的位。
      位的设置或清除取决于 value 参数,可以是 0 也可以是 1 。
      当 key 不存在时,自动生成一个新的字符串值。
      字符串会进行伸展(grown)以确保它可以将 value 保存在指定的偏移量上。当字符串值进行伸展时,空白位置以 0 填充。
      offset 参数必须大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。

对使用大的 offset 的 SETBIT 操作来说,内存分配可能造成 Redis 服务器被阻塞。具体参考 SETRANGE key offset value 命令,warning(警告)部分。
在这里插入图片描述

  1. GETBIT
    语法: GETBIT key offset
    时间复杂度: O(1)
    功能: 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。当 offset 比字符串值的长度大,或者 key 不存在时,返回 0 。
    返回值: 字符串值指定偏移量上的位(bit)。
    在这里插入图片描述
  2. BITCOUNT
    语法: BITCOUNT key [start] [end]
    时间复杂度: O(N)
    功能: 计算给定字符串中,被设置为 1 的比特位的数量。
    返回值: 被设置为 1 的位的数量。

  一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。
  start 和 end 参数的设置和 GETRANGE key start end 命令类似,都可以使用负数值: 比如 -1 表示最后一个字节, -2 表示倒数第二个字节,以此类推。
  不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。
在这里插入图片描述

  1. BITPOS
    语法: BITPOS key bit [start] [end]
    时间复杂度: O(N),其中 N 为位图包含的二进制位数量
    功能: 返回位图中第一个值为 bit 的二进制位的位置。在默认情况下, 命令将检测整个位图, 但用户也可以通过可选的 start 参数和 end 参数指定要检测的范围。
    返回值: 整数回复。
    在这里插入图片描述

  2. BITOP
    语法: BITOP operation destkey key [key …]
    时间复杂度: O(N)
    功能: 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
    返回值: 保存到 destkey 的字符串的长度,和输入 key 中最长的字符串长度相等。

  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 。

  除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入。

处理不同长度的字符串
  当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0 。空的 key 也被看作是包含 0 的字符串序列。

BITOP 的复杂度为 O(N) ,当处理大型矩阵(matrix)或者进行大数据量的统计时,最好将任务指派到附属节点(slave)进行,避免阻塞主节点。
在这里插入图片描述

  1. BITFIELD
    语法: BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
    时间复杂度: 每个子命令的复杂度为 O(1)
    功能: BITFIELD 命令可以将一个 Redis 字符串看作是一个由二进制位组成的数组, 并对这个数组中储存的长度不同的整数进行访问 (被储存的整数无需进行对齐)。 换句话说, 通过这个命令, 用户可以执行诸如 “对偏移量 1234 上的 5 位长有符号整数进行设置”、 “获取偏移量 4567 上的 31 位长无符号整数”等操作。 此外, BITFIELD 命令还可以对指定的整数执行加法操作和减法操作, 并且这些操作可以通过设置妥善地处理计算时出现的溢出情况。
    返回值: BITFIELD 命令的返回值是一个数组, 数组中的每个元素对应一个被执行的子命令。 需要注意的是, OVERFLOW 子命令本身并不产生任何回复。

  BITFIELD 命令的作用在于它能够将很多小的整数储存到一个长度较大的位图中, 又或者将一个非常庞大的键分割为多个较小的键来进行储存, 从而非常高效地使用内存, 使得 Redis 能够得到更多不同的应用 —— 特别是在实时分析领域: BITFIELD 能够以指定的方式对计算溢出进行控制的能力, 使得它可以被应用于这一领域。

  该命令较复杂,具体可以参考《Redis命令参考 - BITFIELD》
在这里插入图片描述

3、Bitmap(位图)应用

  通过Bitmap(位图)来统计在线用户,既可以获取在线用户名单, 又可以尽量减少内存消耗的。
  Redis 的位图就是一个由二进制位组成的数组, 可以通过将数组中的每个二进制位与用户 ID 进行一一对应, 我们可以使用位图去记录每个用户是否在线。
  当一个用户上线时, 我们就使用 SETBIT 命令, 将这个用户对应的二进制位设置为 1 :

# 此处的 user_id 必须为数字,因为它会被用作索引
SETBIT "online_users" <user_id> 1

  通过使用 GETBIT 命令去检查一个二进制位的值是否为 1 , 我们可以知道指定的用户是否在线:

GETBIT "online_users" <user_id>

  而通过 BITCOUNT 命令, 我们可以统计出位图中有多少个二进制位被设置成了 1 , 也即是有多少个用户在线:

BITCOUNT "online_users"

  跟集合一样, 用户也能够对多个位图进行聚合计算 —— 通过 BITOP 命令, 用户可以对一个或多个位图执行逻辑并、逻辑或、逻辑异或或者逻辑非操作:

# 计算出 7 天都在线的用户
BITOP "AND" "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ... "day_7_online_users"
# 计算出 7 在的在线用户总人数
BITOP "OR" "7_days_total_online_users" "day_1_online_users" "day_2_online_users" ... "day_7_online_users"
# 计算出两天当中只有其中一天在线的用户
BITOP "XOR" "only_one_day_online" "day_1_online_users" "day_2_online_users"

  和HyperLogLog相比,位图节约内存的效果不及 HyperLogLog 那么显著, 但是使用位图可以准确地判断一个用户是否上线, 并且能够像集合和有序集合一样, 对在线用户名单进行聚合计算。 因此对于想要尽量节约内存, 但又需要准确地知道用户是否在线, 又或者需要对用户的在线名单进行聚合计算的应用来说, 使用位图可以说是最佳之选。

发布了71 篇原创文章 · 获赞 3 · 访问量 5272

猜你喜欢

转载自blog.csdn.net/hou_ge/article/details/104531500