BITPOS:查找第一个指定的二进制位值
用户可以通过执行 BITPOS 命令,在位图中查找第一个被设置为指定值的二进制位,并返回这个二进制位的偏移量:
BITPOS bitmap value
比如,通过执行以下命令,我们可以知道位图 bitmap003 第一个被设置为 1 的二进制位所在的偏移量:
redis> BITPOS bitmap003 1
(integer) 0 -- 位图第一个被设置为1的二进制位的偏移量为0
而执行以下命令则可以知道 bitmap003 第一个被设置为 0 的二进制位所在的偏移量:
redis> BITPOS bitmap003 0
(integer) 3 -- 位图第一个被设置为0的二进制位的偏移量为3
图8-8 展示了以上两个命令的执行图示。

只在指定的字节范围内进行查找
在默认情况下,BITPOS 命令的查找范围将覆盖位图包含的所有二进制位,但在有需要的情况下,用户也可以通过可选的 start 参数和 end 参数,让 BITPOS 命令只在指定字节范围内的二进制位中进行查找:
BITPOS bitmap value [start end]
举个例子,如果我们想要在位图 bitmap003 的第二个字节中找到第一个值为 1 的二进制位所处的偏移量,那么可以执行以下命令:
redis> BITPOS bitmap003 1 1 1
(integer) 12
注意,BITPOS 命令返回的偏移量为 12,这个偏移量是被找到的二进制位在整个位图中所处的偏移量,而不是它在第二个字节中所处的偏移量。换句话说,即使我们指定了 BITPOS 命令要查找的字节范围,BITPOS 命令在返回结果时也只会返回目标二进制位在整个位图中所处的绝对偏移量,而不是这个二进制位在指定字节范围内的相对偏移量。
图8-9展示了 BITPOS bitmap003111 命令的执行图示,以及这个命令在执行时查找的范围。
使用负数偏移量定义查找范围
与 BITCOUNT 命令一样,BITPOS 命令的 start 参数和 end 参数也可以是负数。

比如,以下代码就展示了如何在位图 bitmap003 的倒数第一个字节中,查找第一个值为 0 的二进制位:
redis> BITPOS bitmap003 0 -1 -1
(integer) 17
图8-10 展示了这个命令的执行图示,以及它在执行时的查找范围。

边界情况处理
当用户尝试对一个不存在的位图或者一个所有位都被设置成了 0 的位图中查找值为 1 的二进制位时,BITPOS 命令将返回 -1 作为结果:
redis> BITPOS not-exists-bitmap 1 -- 在一个不存在的位图中查找
(integer) -1
redis> BITPOS all-0-bitmap 1 -- 在一个所有位都被设置成了0的位图中查找
(integer) -1
如果用户在一个所有位都被设置成 1 的位图中查找值为 0 的二进制位,那么 BITPOS 命令将返回位图最大偏移量加上 1 作为结果。
举个例子,如果我们在一个包含 8 个二进制位,并且所有二进制位都被设置成 1 的位图 bitmap-8bits-all-1 中查找值为 0 的二进制位,那么 BITPOS 命令将返回以下结果:
redis> BITPOS bitmap-8bits-all-1 0
(integer) 8
这个 BITPOS 命令之所以会返回 8,是因为它在对位图中偏移量从 0 到 7 的 8 个二进制位进行检查之后,都没有找到值为 0 的二进制位,于是它继续移动指针,尝试去检查偏移量为 8 的二进制位,但是由于偏移量 8 已经超出了位图的有效偏移量范围,而 Redis 又会把位图中不存在的二进制位的值看作 0,所以 BITPOS 命令最后就把偏移量 8 作为结果返回给用户。