Redis 的 Bitmap 是一种特殊的数据结构,它可以存储一组二进制位,并对这些二进制位进行位运算。Bitmap 在 Redis 中被广泛用于计数器、统计、排重等场景。
一、命令介绍
1、SETBIT key offset value
将指定偏移量的二进制位设置为给定的值(0 或 1)。例如,SETBIT mybitmap 1001 1 将 mybitmap 中偏移量为 1001 的二进制位设置为 1。
2、GETBIT key offset
获取指定偏移量的二进制位的值(0 或 1)。例如,GETBIT mybitmap 1001 将返回 mybitmap 中偏移量为 1001 的二进制位的值。
3、BITCOUNT key [start end]
计算指定范围内所有二进制位被设置为 1 的个数。例如,BITCOUNT mybitmap 0 1023 将返回 mybitmap 中偏移量从 0 到 1023 的所有二进制位中被设置为 1 的个数。
4、BITOP operation destkey key [key ...]
对多个指定的 bitmap 进行位运算,并将结果存储到 destkey 中。operation 参数可以是 AND、OR、XOR、NOT 四种运算之一。例如,BITOP AND myresult mybitmap1 mybitmap2 将 mybitmap1 和 mybitmap2 中的所有二进制位进行 AND 运算,并将结果存储到 myresult 中。
Bitmap 的主要优点是占用的空间非常小,一个 bitmap 只需要占用 1MB 的内存,就可以存储 8 1024 1024 个二进制位。Bitmap 还支持非常高效的位运算操作,可以快速实现复杂的统计、计算等功能。
不过,由于 Redis Bitmap 只能存储二进制位,因此只适用于对数据量比较小、结构比较简单的数据进行存储和计算。对于结构比较复杂的数据或者需要高性能的大规模数据处理场景,建议使用其他类型的数据结构和分布式计算框架。
二、理解bitmap 中偏移量offset的概念
当我们使用 Redis 的 Bitmap 存储数据时,实际上是将数据转换为一组二进制位,并将这些二进制位存储在一个字符串中。偏移量 offset 指的是这个字符串中的位置,用于标识每个二进制位的位置。
下面举一个具体的例子来说明。假设我们有一个员工打卡系统,需要记录每个员工每天的打卡情况,包括上午打卡和下午打卡两个时间点。我们可以使用 Redis Bitmap 存储这些数据,其中每个二进制位表示一个员工在某个时间点是否打卡。
假设我们有 1000 个员工,需要记录每个员工在某一天的打卡情况。我们可以创建一个名为 "checkin:20220306" 的 Bitmap,用于存储这些数据。在这个 Bitmap 中,每个员工的打卡情况占用两个二进制位,一个表示上午打卡,一个表示下午打卡。偏移量 offset 表示每个员工在这个 Bitmap 中占用的位置。
假设我们规定每个员工在 Bitmap 中占用的位置为 2 个二进制位。那么,员工编号为 1001 的员工在 Bitmap 中的占用位置就是 2 * 1001 = 2002。如果这个员工在上午打卡了,我们可以使用 SETBIT 命令将这个位置的二进制位设置为
SETBIT checkin:20220306 2002 1
如果这个员工在下午也打卡了,我们可以使用 SETBIT 命令将这个位置的第二个二进制位设置为 1:
SETBIT checkin:20220306 2003 1
如果我们需要查询这个员工在某个时间点是否打卡,可以使用 GETBIT 命令查询对应的二进制位的值:
GETBIT checkin:20220306 2002 # 查询上午打卡情况
GETBIT checkin:20220306 2003 # 查询下午打卡情况
通过 Bitmap,我们可以非常高效地存储和查询大量的打卡数据,并进行一些高级的计算和统计操作。
三、上面Demo中,如何把员工编号1001转换成offset?
在上面的示例中,我们假设每个员工在 Bitmap 中占用的位置为 2 个二进制位。这意味着每个员工在 Bitmap 中的起始偏移量为 2 员工编号。例如,员工编号为 1001 的员工在 Bitmap 中的起始偏移量为 2 1001 = 2002。
具体来说,如果我们有 n 个员工,需要使用 Bitmap 存储这些数据,每个员工在 Bitmap 中占用的二进制位数为 m,那么我们可以使用如下公式将员工编号转换为偏移量 offset:
offset = m * (employee_id - 1)
其中,employee_id 是员工编号,从 1 开始编号。由于 Redis 中字符串的下标也是从 0 开始的,因此我们需要将员工编号减去 1。例如,如果我们有 1000 个员工,每个员工在 Bitmap 中占用 2 个二进制位,那么员工编号为 1001 的员工在 Bitmap 中的起始偏移量为 2 * (1001 - 1) = 2000。
四、bitmap中key的设计
1、从员工角度,统计员工每日,每月的打卡情况,如何设计bitmap的key和offset
对于每个员工的打卡情况,我们可以使用 Redis 的 Bitmap 来存储。对于每个员工,我们可以为其创建一个以日期为后缀的键,例如 "checkin:employee_id:20220306" 表示员工在 2022 年 3 月 6 日的打卡情况。
为了方便统计每个员工在每日、每月的打卡情况,我们可以为每个员工创建两个特殊的键,分别用于记录该员工在某个月份内的所有打卡数据和该员工在某一天内的所有打卡数据。例如:
"checkin:employee_id:daily:20220306" 表示员工在 2022 年 3 月 6 日的所有打卡数据。
"checkin:employee_id:monthly:202203" 表示员工在 2022 年 3 月的所有打卡数据。
这些键的值都是一个 Bitmap,可以使用 Redis 的 BITOP 命令对多个 Bitmap 进行位运算,从而实现对多个键对应的 Bitmap 进行统计。
对于偏移量 offset,我们可以将其设为员工的编号,例如员工编号为 1001 的员工在 "checkin:employee_id:daily:20220306" 对应的 Bitmap 中的偏移量为 1001。当员工在某一天内打卡时,我们可以使用 SETBIT 命令将该员工在对应的 Bitmap 中的位设置为
SETBIT checkin:1001:daily:20220306 1001 1
这样,我们可以快速地获取该员工在某一天内的打卡情况,例如:
GETBIT checkin:1001:daily:20220306 1001
将返回该员工在 2022 年 3 月 6 日是否打卡的信息(0 表示未打卡,1 表示已打卡)。
类似地,我们可以使用 BITOP 命令对多个 "checkin:employee_id:daily:" 和 "checkin:employee_id:monthly:" 键的 Bitmap 进行统计,从而得到每个员工在每日、每月的打卡情况。
2、从时间角度,统计每月,每日所有员工的打卡,如何设计bitmap的key和offset
要统计每月、每日所有员工的打卡情况,我们可以创建两个键:
1)一个键用于记录所有员工在某一天的打卡情况,例如 "checkin:daily:20220306" 表示所有员工在 2022 年 3 月 6 日的打卡情况。
2)另一个键用于记录所有员工在某个月份内的打卡情况,例如 "checkin:monthly:202203" 表示所有员工在 2022 年 3 月的打卡情况。
这些键的值都是一个 Bitmap,可以使用 BITOP 命令对多个 Bitmap 进行位运算,从而实现对多个键对应的 Bitmap 进行统计。
对于偏移量 offset,我们可以将其设为员工的编号,例如员工编号为 1001 的员工在 "checkin:daily:20220306" 对应的 Bitmap 中的偏移量为 1001。当员工在某一天内打卡时,我们可以使用 SETBIT 命令将该员工在对应的 Bitmap 中的位设置为 1,例如:
SETBIT checkin:daily:20220306 1001 1
这样,我们可以快速地获取某个员工在某一天内的打卡情况,例如:
GETBIT checkin:daily:20220306 1001
将返回该员工在 2022 年 3 月 6 日是否打卡的信息(0 表示未打卡,1 表示已打卡)。
类似地,我们可以使用 BITOP 命令对多个 "checkin:daily:" 和 "checkin:monthly:" 键的 Bitmap 进行统计,从而得到每日、每月所有员工的打卡情况。
五、在线网址推荐:
https://try.redis.io/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。