在Redis数据库中,Bitmap(位图)是一种特殊的数据结构,它不是一个独立的数据类型,而是基于String类型实现的。Bitmap主要用于存储大量二进制位(0或1)的数据,这些位可以代表不同的状态或标志。具体来说:
-
存储原理: Redis的Bitmap实际上是利用String类型的最大容量(512 MB)存储一个连续的二进制序列,其中每个字节的8位可以分别代表8个独立的状态。这意味着你可以用一个Bitmap来跟踪多达数百万甚至数十亿的状态,只要状态总数不超过
2^(8 * (512 MB / 1 byte))
,即大约2^32
个状态(考虑到字符串末尾的结束符,实际可用的偏移量上限是2^32 - 1
)。 -
常见操作: Redis提供了丰富的Bitmap操作命令,包括但不限于:
SETBIT key offset value
:设置指定偏移量处的位状态。GETBIT key offset
:获取指定偏移量处的位状态。BITCOUNT key [start end]
:统计给定范围内为1的位的数量。BITOP operation destkey key [key ...]
:执行针对多个Bitmap的并集、交集、差集等位操作。
-
应用场景: Bitmap在Redis中常用于以下场景:
- 大规模用户在线状态记录:每位代表一个用户是否在线。
- 用户行为标记:比如用户是否阅读过某篇文章、是否参与过某项活动等。
- 大数据分析前的数据预处理:如用户画像构建,通过Bitmap记录用户属性,便于后续的批量统计和分析。
- 布隆过滤器的实现:虽然Redis内并未直接提供布隆过滤器,但可以使用Bitmap和其他数据结构组合模拟布隆过滤器的功能。
这种数据结构的优点在于它的内存效率极高,特别适合存储需要频繁进行位运算且总体状态较多的情况。同时,Bitmap也可以与其他Redis数据结构结合,实现复杂的数据查询和处理逻辑。
SETBIT
SETBIT key offset value
对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
位的设置或清除取决于 value 参数,可以是 0 也可以是 1 。
当 key 不存在时,自动生成一个新的字符串值。
字符串会进行伸展(grown)以确保它可以将 value 保存在指定的偏移量上。当字符串值进行伸展时,空白位置以 0 填充。
offset 参数必须大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。
GETBIT
GETBIT key offset
对 key 所储存的字符串值,获取指定偏移量上的位(bit)。
当 offset 比字符串值的长度大,或者 key 不存在时,返回 0 。
BITCOUNT
BITCOUNT key [start] [end]
计算给定字符串中,被设置为 1 的比特位的数量。
一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。
start 和 end 参数的设置和 GETRANGE 命令类似,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,以此类推。
不存在的 key 被当成是空字符串来处理,因此对一个不存在的 key 进行 BITCOUNT 操作,结果为 0 。
BITOP
BITOP operation destkey key [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 作为输入。
参考:
And 与 全1出1
Or 或 有1出1
Not 非 有1出0 有0出1
Xor 异或 相同为0,不同为1
需求:
学生签到
问题1(学生签到):某个具体的学生今年签到了多少天
我们做如下假设:这是某位同学的签到数据,1个单元格占用1bit空间
结果
新的问题
为什么我们统计0 1时返回的数据是2
原因
BITCOUNT key [start] [end]
我们的start end表示的是一个字节内的数据
我们将第九天也设置为签到后,再次统计得到的结果就是3
车展人数
问题2(车展):三天一共来了多少人;这三天每天都来的人
我们做如下假设:这三天5、8、32分别代表三个人
我们设置以上基本数据
三天一共来了多少人
这三天每天都来的人