美文网首页Redis
04_redis_位图

04_redis_位图

作者: A_l_A_n | 来源:发表于2020-07-07 11:36 被阅读0次

    当存一些bool型数据,比如用户一年的签到此书。如果使用key/value 大数据量需要大量的存储空间。
    redis的位图可以解决这个问题。每天签到的记录只占一个位,365天就是365个位,46个字节。大大节省了空间。
    位图就是byte数组。

    基本使用

    127.0.0.1:6379> setbit s 1 1 
    (integer) 0 
    127.0.0.1:6379> setbit s 2 1 
    (integer) 0 
    127.0.0.1:6379> setbit s 4 1 
    (integer) 0 
    127.0.0.1:6379> setbit s 9 1 
    (integer) 0 
    127.0.0.1:6379> setbit s 10 1 
    (integer) 0 
    127.0.0.1:6379> setbit s 13 1
    (integer) 0 
    127.0.0.1:6379> setbit s 15 1 
    (integer) 0 
    127.0.0.1:6379> get s 
    "he"
    

    零存零取

    127.0.0.1:6379> setbit w 1 1
    (integer) 0
    127.0.0.1:6379> setbit w 2 1
    (integer) 0
    127.0.0.1:6379> setbit w 4 1
    (integer) 0
    127.0.0.1:6379> getbit w 1 # 获取某个具体位置的值 0/1
    (integer) 1
    127.0.0.1:6379> getbit w 2
    (integer) 1
    127.0.0.1:6379> getbit w 4
    (integer) 1
    127.0.0.1:6379> getbit w 5
    (integer) 0
    

    整存零取

    127.0.0.1:6379> set w h # 整存
    (integer) 0
    127.0.0.1:6379> getbit w 1
    (integer) 1
    127.0.0.1:6379> getbit w 2
    (integer) 1
    127.0.0.1:6379> getbit w 4
    (integer) 1
    127.0.0.1:6379> getbit w 5
    (integer) 0
    

    如果对应的字节是不能打印的字符,redis-cli会 显示该字符的十六进制

    统计和查找

    bitcount 、bitpos

    bitcount 用来统计 制定范围内1的个数。可以统计用户一年的签到次数
    bitpos 用来查找制定范围内第一次出现的0或者1
    [start,end]参数用来指定某个时间范围内用户签到的天数, 用户哪一天开始签到的。
    但是start和end都是字节参数,所以都必须是8的倍数。不能随意指定。因此我们不能直接计算用户在某个时间段签到了几次,必须要将这个月覆盖的所有字节全部取出来,放到内存中进行处理。

    127.0.0.1:6379> set w hello
    OK
    127.0.0.1:6379> bitcount w
    (integer) 21
    127.0.0.1:6379> bitcount w 0 0 # 第一个字符中 1 的位数
    (integer) 3
    127.0.0.1:6379> bitcount w 0 1 # 前两个字符中 1 的位数
    (integer) 7
    Redis 深度历险:核心原理与应用实践 | 钱文品 著 第 39 页 共 226 页
    127.0.0.1:6379> bitpos w 0 # 第一个 0 位
    (integer) 0
    127.0.0.1:6379> bitpos w 1 # 第一个 1 位
    (integer) 1
    127.0.0.1:6379> bitpos w 1 1 1 # 从第二个字符算起,第一个 1 位
    (integer) 9
    127.0.0.1:6379> bitpos w 1 2 2 # 从第三个字符算起,第一个 1 位
    (integer) 17
    

    魔术指令bitfield

    用来操作多个位,最多连续处理64位,如果超过64位需要 使用多个指令,bitfield可以一次执行多个子指令

    get

    127.0.0.1:6379> set w hello
    OK
    127.0.0.1:6379> bitfield w get u4 0 # 从第一个位开始取 4 个位,结果是无符号数 (u)
    (integer) 6
    127.0.0.1:6379> bitfield w get u3 2 # 从第三个位开始取 3 个位,结果是无符号数 (u)
    (integer) 5
    127.0.0.1:6379> bitfield w get i4 0 # 从第一个位开始取 4 个位,结果是有符号数 (i)
    1) (integer) 6
    127.0.0.1:6379> bitfield w get i3 2 # 从第三个位开始取 3 个位,结果是有符号数 (i)
    1) (integer) -3
    

    所谓有符号数是指获取的位数组中第一个位是符号位,剩下的才是值。如果第一位是1,那就是负数。无符号数表示非负数,没有符号位,获取的位数组全部都是值。有符号数最多可以获取 64 位,无符号数只能获取 63 位 (因为 Redis 协议中的 integer 是有符号数,最大 64 位,不能传递 64 位无符号值)。如果超出位数限制,Redis 就会告诉你参数错误。
    执行多个子指令:

    127.0.0.1:6379> bitfield w get u4 0 get u3 2 get i4 0 get i3 2
    1) (integer) 6
    2) (integer) 5
    3) (integer) 6
    4) (integer) -3
    

    set 子指令

    将第二个字符 e 改成 a,a 的 ASCII 码是 97。

    127.0.0.1:6379> bitfield w set u8 8 97 # 从第 8 个位开始,将接下来的 8 个位用无符号数 97 替换
    1) (integer) 101
    127.0.0.1:6379> get w
    "hallo"
    

    incrby

    指定范围内自增。如果溢出,redis的默认方法是折返, 将溢出的符号位丢掉。比如8位 无符号位255,增加一位就会溢出,变成0。如果是8位有符号位位127,加1溢出变为-128

    127.0.0.1:6379> set w hello
    OK
    127.0.0.1:6379> bitfield w incrby u4 2 1 # 从第三个位开始,对接下来的 4 位无符号数 +1
    1) (integer) 11
    127.0.0.1:6379> bitfield w incrby u4 2 1
    1) (integer) 12
    127.0.0.1:6379> bitfield w incrby u4 2 1
    1) (integer) 13
    127.0.0.1:6379> bitfield w incrby u4 2 1
    1) (integer) 14
    127.0.0.1:6379> bitfield w incrby u4 2 1
    1) (integer) 15
    127.0.0.1:6379> bitfield w incrby u4 2 1 # 溢出折返了
    1) (integer) 0
    

    overflow

    bitfield指令 提供了溢出策略子指令overflow。
    可以选择溢出折返,溢出报错,饱和截断,超过范围就会停留到最大/最小值。overflow只影响下来的第一条指令,这条指令执行完溢出策略会变成默认的折返

    饱和截断

    127.0.0.1:6379> set w hello
    OK
    127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
    1) (integer) 11
    127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
    1) (integer) 12
    127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
    1) (integer) 13
    127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
    1) (intege) 14 
    127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1 
    1) (integer) 15 
    127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1 # 保持最大值
    1) (integer) 15
    

    失败不执行

    127.0.0.1:6379> set w hello
    OK
    127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
    1) (integer) 11
    127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
    1) (integer) 12
    127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
    1) (integer) 13
    127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
    1) (integer) 14
    127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
    1) (integer) 15
    127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1 # 不执行
    1) (nil)
    

    相关文章

      网友评论

        本文标题:04_redis_位图

        本文链接:https://www.haomeiwen.com/subject/glqgqktx.html