• 技术文章 >数据库 >Redis

    深入浅析Redis中的位图(bitmap)

    青灯夜游青灯夜游2021-12-02 10:17:18转载421
    本篇文章带大家了解一下Redis中的位图(bitmap),希望对大家有所帮助!

    Redis 的位图(bitmap)是由多个二进制位组成的数组,数组中的每个二进制位都有与之对应的偏移量(从 0 开始),通过这些偏移量可以对位图中指定的一个或多个二进制位进行操作。【相关推荐:Redis视频教程

    实际上,位图并不是 Redis 提供的一种新的数据类型,它是字符串类型的扩展。所以位图的命令可以直接使用在字符串类型的键上,位图命令操作的键也可以被字符串类型命令操作。

    比如,现有一个字符串键 foo:

    redis> set foo bar

    1 个字节由 8 个二进制位组成,所以 foo 键的二进制形式就是:

    1.png

    SETBIT

    通过 SETBIT 命令,可以为位图指定偏移量上的二进制位设置值,offset 必须大于等于 0,value 只能是 0 或 1。此命令的时间复杂度是 O(1)。

    SETBIT key offset value

    SETBIT 命令在对二进制位进行设置之后,将返回二进制位被设置之前的旧值作为结果。

    假设现在想把 bar 变为 aar,只需如下两步操作:

    redis> setbit foo 6 0
    (integer) 1
    redis> setbit foo 7 1
    (integer) 0
    redis> get foo"aar"

    当执行 SETBIT 命令尝试对一个位图进行设置的时候,如果位图不存在,或者位图当前的大小无法满足,Redis 将对被设置的位图进行扩展,并将所有未被设置的二进制位的值初始化为 0。比如:

    redis> setbit far 10 1

    由于 far 并不存在,所以 Redis 会将 0~9 的二进制位设置为 0,因为 Redis 对位图的扩展操作是以字节为单位进行的,所以实际上 far 一共有 16 个二进制位,并不是 10 个,且 11~15 的二进制位也是 0。

    基于这种情况,当指定的二进制位偏移量过大时,Redis 需要一次性分配完所有内存,这可能会造成 Redis 服务器阻塞。比如存储用户的性别,1 代表男性,0 代表女性,使用 ID 作为二进制偏移量,如果 ID 从 10000000001 开始的,就需要将用户 ID 减去 10000000000 再进行存储,否则会造成内存浪费。

    GETBIT

    使用 GETBIT 命令可以获取位图指定偏移量上的二进制位的值。此命令的时间复杂度是 O(1)。

    GETBIT key offset

    如果输入的偏移量超过了位图目前拥有的最大偏移量,将返回 0 作为结果。

    BITCOUNT

    通过 BITCOUNT 命令可以统计位图中值为 1 的二进制位数量。此命令的时间复杂度是 O(n)。

    BITCOUNT key [start end]

    在默认情况下,BITCOUNT 命令对位图包含的所有字节中的二进制位进行统计,也可以通过可选的 start 参数和 end 参数,让 BITCOUNT 只对指定字节范围内的二进制位进行统计(不是二进制偏移量)。比如,希望统计 ar 两个字节中值为 1 的二进制数量:

    redis> bitcount foo 1 2
    (integer) 7

    start 和 end 参数也支持使用负数索引,下方的用法与上方的等效:

    redis> bitcount foo -2 -1
    (integer) 7

    BITPOS

    通过执行 BITPOS 命令,在位图中查找第一个被设置为指定值的二进制位,并返回这个二进制位的偏移量。

    BITPOS key value [start end]

    BITPOS 也接受可选的 start 参数和 end 参数,让 BITPOS 命令只在指定字节范围内的二进制位中进行查找。

    redis> get foo"aar"redis> bitpos foo 1
    (integer) 1
    redis> bitpos foo 0
    (integer) 0
    redis> bitpos foo 0 1 2
    (integer) 8
    redis> bitpos foo 1 1 2
    (integer) 9
    redis> bitpos foo 1 -1 -1
    (integer) 17

    针对边界的处理:

    BITOP

    通过 BITOP 命令,对一个或多个位图执行指定的二进制位运算,并将运算结果存储到指定的键中。

    BITOP operation destkey key [key ...]

    operation 参数的值可以是 AND、OR、XOR、NOT 中的任意一个,这 4 个值分别对应逻辑并、逻辑或、逻辑异或和逻辑非 4 种运算,其中 AND、OR、XOR 这 3 种运算允许用户使用任意数量的位图作为输入,而 NOT 运算只允许使用一个位图作为输入。BITOP 命令在将计算结果存储到指定键中之后,会返回被存储位图的字节长度。

    当 BITOP 命令在对两个长度不同的位图执行运算时,会将长度较短的那个位图中不存在的二进制位的值看作 0。

    redis> set foo1 bar
    OK
    redis> set foo2 aar
    OK
    redis> bitop or res foo1 foo2
    (integer) 3
    redis> get res"car"

    2.png

    注意:BITOP 可能是一个缓慢的命令,它的时间复杂度是 O(N),在处理长字符串时应注意一下效率问题。

    应用场景

    用户行为记录器

    用用户 ID 作为偏移量,若用户做了某种行为则通过 SETBIT 将二进制位设置为 1,通过 GETBIT 判断用户是否做了某种行为,通过 BITCOUNT 可以知道有多少用户执行了行为。

    用户上线统计

    可以使用 SETBIT 和 BITCOUNT 来实现,以用户 ID 作为 key ,假设今天是上线统计功能开放的第一天,ID 为 1 的用户上线后就通过 SETBIT 1 0 1。当要计算此用户的总共以来的上线次数时,使用 BITCOUNT 命令就可以得出的结果。

    使用这种方式存储数据,即使 10 年后,1个用户就只占用几百字节的内存,它的处理速度依然很快。如果 bitmap 数据比较大,建议将 bitmap 拆分成多个小的 bitmap 分别进行处理。

    更多编程相关知识,请访问:编程入门!!

    以上就是深入浅析Redis中的位图(bitmap)的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:掘金社区,如有侵犯,请联系admin@php.cn删除
    专题推荐:Redis 位图
    上一篇:深入聊聊Redis中的双链表 下一篇:分享一些好用Redis可视化工具

    相关文章推荐

    • Redis中什么是慢查询、订阅模式• 深入了解Redis中的主从同步机制• 聊聊Redis的持久化机制,到底采用RDB还是AOF呢?• 浅谈Redis中缓存过期、内存被缓存占用要怎么处理?• Redis如何实现分布式锁?聊聊实现方法

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网