redis bitmap简介

bitmap

1.简介

Bitmap实际上就是String类型,通过最小的单位bit来进行0或者1的设置,表示某个元素对应的值或者状态。
一个bit的值,或者是0,或者是1

redis 字符串最大值为512M,所以bigmap最大值为:4294967295

8 * 1024 * 1024 * 512 = 2^32 = 4294967296-1 = 4294967295

2.使用场景
  1. 用户在线状态
  2. 统计活跃用户
  3. 用户签到
3.bitmap的基本使用 更多命令

setbit : 给一个指定key的值得第位offset 赋值为value。

getbit : 返回一个指定key的二进制信息


setbit k1 0 1 #设置第1位为1  0111 0111

getbit k1 1   #获取第一位的值 

在这里插入图片描述

bitfield:批量操作

  1. i 有符号数

    指获取的位数组中第一个位是符号位,剩下的才是值。如果第一位是1,那就是负数。

  2. u 无符号数

    表示非负数,没有符号位,获取的位数组全部都是值。

  3. 原码 原码,反码,补码
    
    # 表示正负(0正,1负)
    # 原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值
    
    [+1]= 0001
    
    [-1]= 1001
    
  4. 反码
    
    # 正数的反码是其本身
    # 负数的反码是在其原码的基础上, 符号位不变,其余各个位取反
    
    [+1] = [0001]= [0001][-1] = [1001]= [1110]
  5. 补码
    
    # 正数的补码就是其本身
    # 负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
    
    [+1] = [00000001]= [00000001]= [00000001][-1] = [10000001]= [11111110]= [11111111]
 
# set 设置指定位域的值

# 33  0010 0001   37 0010 0101
# kx:key, i/u x:替换接下来的x个位, 0:从第一个位开始, 33:十进制数
bitfield k2 set i8 0 33   # 从第0个位开始,将接下来的 8个位用无符号数33替换 0010 0001  !
bitfield k3 set i4 0 37   # 从第4个位开始,将接下来的 4个位用无符号数37替换 0101 0000  P
bitfield k4 set u6 1 37   # 从第1个位开始,将接下来的 6个位用无符号数37替换 0100 1010  J

在这里插入图片描述


# get 返回指定的位域

# kx:key, i/u x:替换接下来的x个位, 2:从第二个位开始
bitfield k2 get u6 2  # 从第二个位开始取 6 个位,结果是无符号数 (u)
bitfield k2 get i6 2  # 从第二个位开始取 6 个位,结果是有符号数 (i)

在这里插入图片描述


# incrby (正数自增,负数自减)
# k3 = 0101 0000  P + 2 = 0101 0010 = R
bitfield k3 incrby u4 4 2  # 从第四个位开始,对接下来的 4 位无符号数 +2

在这里插入图片描述

bitcount : 返回一个指定key中位的值为1的个数 (字节为单位)


# k4 = 0100 1010  J  o1 =  0000 0011 0001 0010
bitcount k4 	 # 获取k4中出现的1的个数
bitcount o1 0 0  # 获取o1第一个字节中出现的1的个数

在这里插入图片描述
在这里插入图片描述

bitpos : 用来查找指定范围内出现的第一个 0 或 1 (字节为单位)


 #k6 = abc = 0110 0001 0110 0010 0110 0011
 bitpos k6 1 1 1  # 获取k6第一,第一个1的位置

在这里插入图片描述

bitop : 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上


  BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作
   
  AND: 与运算符(&) 两个同时为1,结果为1,否则为0  
  OR:  或运算(|) 一个为1,其值为1
  NOT: 取反(0110 0001 NOT: 1001 1110)
  XOR: 异或运算,值不同为1,否则为0

在这里插入图片描述
在这里插入图片描述

4.案例实现 (统计网站活跃度)
   
    该网站一天有多少活跃用户 ? 
    该网站一周有多少活跃用户 ?
    该网站一月有多少活跃用户 ? 
    ...
	
	统计活跃用户:
    USER_A用户 : 连续一周每天都有登录系统
    USER_B用户 : 只在"2021-05-22"登录系统
    USER_C用户 : 一周有5天登录系统


	public static final Long USER_A = 123456L;
    public static final Long USER_B = 2L;
    public static final Long USER_C = 3L;
    
    public static final String DAY_01 = "2021-05-21";
    public static final String DAY_02 = "2021-05-22";
    public static final String DAY_03 = "2021-05-23";
    public static final String DAY_04 = "2021-05-24";
    public static final String DAY_05 = "2021-05-25";
    public static final String DAY_06 = "2021-05-26";
    public static final String DAY_07 = "2021-05-27";

    /**
     * 统计活跃用户
     */
    @Test
    void test() {
        //  String today = DateUtil.today();
        redisTemplate.opsForValue().setBit(DAY_01, USER_A, true);

        redisTemplate.opsForValue().setBit(DAY_02, USER_A, true);
        redisTemplate.opsForValue().setBit(DAY_02, USER_B, true);
        redisTemplate.opsForValue().setBit(DAY_02, USER_C, true);

        redisTemplate.opsForValue().setBit(DAY_03, USER_A, true);
        redisTemplate.opsForValue().setBit(DAY_03, USER_C, true);

        redisTemplate.opsForValue().setBit(DAY_04, USER_A, true);
        redisTemplate.opsForValue().setBit(DAY_04, USER_C, true);

        redisTemplate.opsForValue().setBit(DAY_05, USER_A, true);
        redisTemplate.opsForValue().setBit(DAY_05, USER_C, true);

        redisTemplate.opsForValue().setBit(DAY_06, USER_A, true);
        redisTemplate.opsForValue().setBit(DAY_06, USER_C, true);

        redisTemplate.opsForValue().setBit(DAY_07, USER_A, true);

        countTodayUser(DAY_02);
        countWeekUser();
    }

 
    /**
     * 统计当日登陆用户个数
     *
     * @param date
     */
    void countTodayUser(String date) {
        System.out.println(date + ":" + "登陆的用户个数 :" + redisTemplate.execute((RedisCallback<Long>) 								connection -> connection.bitCount((date).getBytes())));
    }

    /**
     * 统计一周内登陆用户的个数
     */
    void countWeekUser() {
        redisTemplate.execute((RedisCallback<Long>) connection -> 			                     	                   connection.bitOp(RedisStringCommands.BitOperation.AND,"count-week-user-and".getBytes(), 
          DAY_01.getBytes(), DAY_02.getBytes(), DAY_03.getBytes(),DAY_04.getBytes(), DAY_05.getBytes(),               DAY_06.getBytes(), DAY_07.getBytes()));

        redisTemplate.execute((RedisCallback<Long>) connection ->                                                     connection.bitOp(RedisStringCommands.BitOperation.OR, "count-week-user-or".getBytes(), 
          DAY_01.getBytes(), DAY_02.getBytes(), DAY_03.getBytes(), DAY_04.getBytes(), DAY_05.getBytes(),               DAY_06.getBytes(), DAY_07.getBytes()));

        System.out.println("一周内每天都登陆的用户个数 :" + redisTemplate.execute((RedisCallback<Long>)                       connection -> connection.bitCount("count-week-user-and".getBytes())));
        System.out.println("一周内登陆过的用户个数 :" + redisTemplate.execute((RedisCallback<Long>) 
              connection > connection.bitCount("count-week-user-or".getBytes())));
    }


// 运行结果
2021-05-22:登陆的用户个数 :3
一周内每天都登陆的用户个数 :1
一周内登陆过的用户个数 :3	
5.扩展

BitMap、RoaringBitmap与JavaEWAH

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值