当前位置:   article > 正文

Redis ---BitMap在redis中的使用_redis bitmap使用

redis bitmap使用

bitmap:

BitMap,即位图,使用每个位表示某种状态,适合处理整型的海量数据。本质上是哈希表的一种应用实现,原理也很简单,给定一个int整型数据,将该int整数映射到对应的位上,并将该位由0改为1。例如:

使用情景 当我们业务要求 :
需要实现用户的保存签到记录,我们一般是根据数据库存储的,这样每个人的一天签到,就是一条记录 ,但是
在这里插入图片描述
在这里插入图片描述
所以我们就可以使用位图来完成签到业务:
在这里插入图片描述
刚好redis底层按照字节储存32bit位,如果一位对应本月的1天 ,1,代表已经签到,0代表未签到,一个用户一个月才使用个位数字节的消耗
在这里插入图片描述
对应操作:bit是从0开始-31
在这里插入图片描述
此时代表 这位user除了周四未打卡,其余时间都已经签到
redis查看
在这里插入图片描述
因为存储时按照字节储存 ,一个字节8bit,我们刚使用7位表示一周的签到情况,剩下的bit位 补全0
getbit :获取指定索引位置的值 我们就可以用于查找某一天的打卡请况
bitfield:操作包含几个操作一般哦用于批量查找在这里插入图片描述
问题实战:
前端用户点击签到按钮发送签到请求,服务端根据此用户的id进行保存,可以存入redis,也可以持久化数据库
接口地址:

/**
 * 当前用户进行签到
 * @return
 */
@PostMapping("/sign")
public Result sign(){
    return userService.sign();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
实现方法:
    /**
     * 用户签到功能
     * @return
     */
    @Override
    public Result sign() {
        //获取当前用户id
        Long userid = UserHolder.getUser().getId();
        //获取日期
        LocalDateTime now = LocalDateTime.now();
//        获取哪一天签到的标识
        String key_sufix= now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        //拼接key
         String key="sign:"+userid+key_sufix;
       //在bitmap 存入bit位 存放第几位 所以需要获取今天是本月的第几天
        int day = now.getDayOfMonth();
        //写入当前bit位        offset偏移量 因为是bit 从0开始计数 1-31 在bit中是0-30
         stringRedisTemplate.opsForValue().setBit(key,day-1,true);//true代表1 签到
        return Result.ok();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

这样我们就用:业务前缀:用户id:签到月份为key,存储了用户的签到情况
在这里插入图片描述

知识扩展

签到统计

在这里插入图片描述
bitfiled 参数说明,因为这个指令包含多个操作这里只涉及get
u代表无符号 ,dayofmonth(今日时本月的第多少天) 0从第几号开始
在这里插入图片描述
案列
在这里插入图片描述

代码实现:
    /**
     * 实现统计连续签到天数如今天14号
     *  u14 无符号 查询14个bit
     * @return
     */
    @Override
    public Result signCount() {
//1.  获取目前的是本月的第几天 以及需要用到的key
        Long userid = UserHolder.getUser().getId();
        LocalDateTime now = LocalDateTime.now();
        String key_sufix= now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key="sign:"+userid+key_sufix;
        int today = now.getDayOfMonth();
//  2.      获取本月为止所有的签到记录 因为bitfield包含了很多操作所以才返回集合
        List<Long> rs = stringRedisTemplate.opsForValue().bitField(key,
                BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(today))//对应u today 查询无符号多少位
                .valueAt(0)
        );
        if (rs==null||rs.isEmpty())
        {
//            没有任何结果
            return  Result.ok(0);
        }
//        因为我们知识get了一个结果 所有直接get 0
        Long num = rs.get(0);
        if (num==null||num==0){
            return Result.ok(0);
        }
        //  3.循环便利
        int count=0;
        while(true){
//          3.1  让获取的结果跟1做于运算 得到数字最后一个bit位
           if( (num&1)==0){
//               如果为0 找到第一个未签到的
               break;
           } else{
               //           3.2如果不为0 说明便利的已经签到计数器加1
               ++count;

           }
//把数字无符号右移进行下一次便利
            //        8.把数字右移一位抛弃最后一位
            num>>>=1;//num=>>>1;


        }


        return Result.ok(count);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

HyperLogLog

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

我们存入5个元素
在这里插入图片描述
使用pfcount统计:
在这里插入图片描述
如果我们存储同样的element元素呢
在这里插入图片描述
在这里插入图片描述
结果可知:不会统计重复的元素,所以HyperLogLog简直就是为uv统计量身定做的数据结构

模拟100w用户存储游览量

@Test
void testHyperLogLog() {
    String[] values = new String[1000];
    int j        = 0;
    for (int i = 0; i < 1000000; i++) {
        j = i % 1000;//角标范围0-999
        values[j] = "user_" + i;//模拟用户点击
        if(j == 999){//每隔1000 插入1次
            // 发送到Redis
            stringRedisTemplate.opsForHyperLogLog().add("hl2", values);//可变参数 也是数组
        }
    }
    // 统计数量
    Long count = stringRedisTemplate.opsForHyperLogLog().size("hl2");
    System.out.println("count = " + count);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

结果:
在这里插入图片描述
可以看到数据的误差百万级别只有0.25 是相当不错的

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/382013
推荐阅读
相关标签
  

闽ICP备14008679号