美文网首页
Redis学习与应用(一)位图

Redis学习与应用(一)位图

作者: youthcity | 来源:发表于2018-08-21 23:55 被阅读80次

    什么是位图

    位图(Bitmap)是通过一个 bit 来表示某个元素对应的值或者状态。它并不是什么新的数据结构。它的内容其实就是普通的字符串。我们可以通过 get/set 获取位图的内容,也可以使用 getbit/setbit 操作 bit 值(0 或者 1)。

    Bit即比特,是目前计算机中数据最小的单位。8个Bit一个Byte(字节)。Bit的值,要么为 0 ,要么为 1。由于Bit是计算机中最小的单位,使用它进行储存将非常节省空间。特别适合一些数据量大的场景。例如,统计每日活跃用户、统计每月打卡数等统计场景。

    常用命令介绍

    1)SETBIT

    作用:对于某个KEY的某位设值
    用法:SETBIT key offset value
    返回值: 原来储存的位

    redis> SETBIT bit 10086 1
    (integer) 0
    

    2)GETBIT

    作用:获取某KEY某位的值
    用法:GETBIT key offset
    返回值:0 或 1。 当 offset 比字符串值的长度大,或者 key 不存在时,返回 0 。

    redis> SETBIT bit 10086 1
    (integer) 0
    
    redis> GETBIT bit 10086
    (integer) 1
    

    3)BITOP

    作用:对多个键进行位操作。 OPoperation的简写。
    用法:BITOP operation destkey key1 key2 [key ...]
    参数说明:
    operation 表示位运算符。一共有四种操作,见下表。
    destkey 表示运算结果保存的值
    key1、key2、key3 表示进行运算的key

    operation 描述
    AND 逻辑并
    OR 逻辑或
    NOT 逻辑非
    XOR 逻辑异或

    返回值:保存到 destkey 的字符串的长度,和输入 key 中最长的字符串长度相等。

    redis> SETBIT bits-1 0 1        # bits-1 = 1001
    (integer) 0
    
    redis> SETBIT bits-1 3 1
    (integer) 0
    
    redis> SETBIT bits-2 0 1        # bits-2 = 1011
    (integer) 0
    
    redis> SETBIT bits-2 1 1
    (integer) 0
    
    redis> SETBIT bits-2 3 1
    (integer) 0
    
    redis> BITOP AND and-result bits-1 bits-2
    (integer) 1
    
    redis> GETBIT and-result 0      # and-result = 1001
    (integer) 1
    
    redis> GETBIT and-result 1
    (integer) 0
    
    redis> GETBIT and-result 2
    (integer) 0
    
    redis> GETBIT and-result 3
    (integer) 1
    

    4)BITCOUNT

    作用:计算给定字符串上,位为1的个数
    用法:BITCOUNT key [start] [end] 注意:此处的[start] [end] 为 字节开始和结束的位置,非偏移量的位置
    返回值:被设置为 1 的位的数量。不存在的key,或空字符串,值为0

    redis> SETBIT tian 0 1
    (integer) 0
    redis> BITCOUNT tian
    (integer) 1
    redis> SETBIT tian 2 1
    (integer) 0
    redis> BITCOUNT tian
    (integer) 2
    

    5)BITPOS

    用法:获取某个键第一位被设置为 0 或 1 位的位置
    作用:BITPOS key bit [start] [end]
    返回值:返回第一个被设为 0 或 1 的位置

    redis> SET test_str 'youthcity'
    OK
    # 查看值为 1 的最开始的位数
    redis> BITPOS test_str 1
    (integer) 1
    # 查看值为 0 的最开始位数
    redis> BITPOS test_str 0
    (integer) 0
    redis> BITPOS test_1 1  # 若没有找到指定位,则返回 -1
    (integer) -1
    

    6)魔术指令 BITFIELD

    作用:一次对多个位范围进行操作。bitfield 有三个子指令,分别是 get/set/incrby。每个指令都可以对指定片段做操作。
    用法:BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
    返回值:返回一个数组作为回复, 数组中的每个元素就是对应操作的执行结果。

    # 从第1位开始取4位,设值为5(有符号数)
    redis> BITFIELD key SET i4 0 5
    1) (integer) 0
    
    # 从第1位开始取4位,结果为有符号数
    redis> BITFIELD key GET i4 0
    1) (integer) 5
    
    # 从第1位取4位,结果为有符号数
    # 从第5位取4位,设值为6,结果为无符号数
    # 从第5位去4位,值增加1,结果为无符号数
    redis> BITFIELD key GET i4 0 SET u4 4 6 INCRBY u4 4 1
    1) (integer) 5
    2) (integer) 0
    3) (integer) 7
    

    BITFIELD还提供了三种溢出策略:

    • WRAP(wrap around,回绕)。一个i8的整数,值为127,递增1会导致值变为-128;
    • SAT(saturation arithmetic,饱和计算)。一个i8的整数,值为120,递增10结果变为127(i8 类型所能储存的最大整数值);
    • FAIL。 发生溢出时,操作失败。并返回空值表示计算未被执行。
    redis> BITFIELD tian_key SET i8 0 127 OVERFLOW WRAP INCRBY i8 0 1
    1) (integer) 0
    2) (integer) -128
    redis> BITFIELD tian_key_2 SET i8 0 120 OVERFLOW SAT INCRBY i8 0 10
    1) (integer) 0
    2) (integer) 127
    redis> BITFIELD tian_key_3 SET i8 0 127 OVERFLOW FAIL INCRBY i8 0 1
    1) (integer) 0
    2) (nil)
    

    应用场景

    1) 统计用户上线次数

    实现原理:
    每当用户在某一天上线的时候,我们就使用 SETBIT,以用户名作为 key ,将那天所代表的网站的上线日作为 offset 参数,并将这个 offset 上的位设置为 1

    例如:

    1. 某应用上线第100天,若用户A在该天上线一次。
    SETBIT A 100 1 
    
    1. 某应用上线第101天,用户A上线。
    SETBIT A 101 1 
    
    1. 统计用户 A 总共上线次数。
    BITCOUNT A
    

    2)用户签到

    与统计用户上线次数原理类似。

    原理:以用户ID为KEY,以当前时间距离开始时间的时间差为偏移量,若用户签到一次,则将位置为 1。最后 bitcountKEY,获取用户一共签到的次数。

    const start_date = '20180801';
    const end_date = '20180830';
    
    const offset = moment(start_date).unix() - moment(end_date).unix();
    redis.setBit('user_id_2018', offset, 1);
    
    // 统计活跃天数
    redis.bitCount('user_id_2018');
    

    3)统计活跃用户

    需求:统计某天或连续几天,活跃用户数
    方案:若某用户上线,则以日期为KEY,以用户user_id为偏移量(若ID不为整数,则将ID hash化为唯一ID),设置位为 1

    redis.setBit('')
    
    const status = 1;
    const user_id = 100;
    redis.setBit('active_20180820', user_id, status);
    redis.setBit('active_20180821', user_id, status);
    // 将20180820号与20180821日进行和运算,得出两天都上线的结果。并存入KEY—— dest_201808_20_21
    redis.bitOp('AND', 'dest_201808_20_21', 'active_20180820', 'active_20180821');
    redis.bitCount('dest_201808_20_21');
    

    4)用户在线状态

    需求:提供接口检查用户是否在线。
    方案:使用bitmap存储用户在线状态。使用一个KEY,若用户在线,则以用户ID位偏移量,将位设为 1;若不在线,则设置为 0

    参考资料

    相关文章

      网友评论

          本文标题:Redis学习与应用(一)位图

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