Redis 位图实现签到之长时间未签到预警

news2024/12/26 20:42:28

#目前通行系统项目中有一个新需求【通过对通行记录数据定时分析,查询出长时间没 有刷卡/刷脸通行的学生】

#一看到通行签到相关,就想到了redis的位图,理由也有很多帖子说明了,最大优点占用空间小。

一.redis命令行

SETBIT:设置指定偏移量上的位值。语法:SETBIT <key> <offset> <value>

使用中key可以为  xxx前缀 + + 用户编号 + + yyyyMM 的格式,设置该人员在该月的签到情况。

当执行以下语句获得一个字符时

假如为2024年10月2号,则执行setbit sign:001:202410 1 1 。偏移量为 1 。

 

获取当前key的值为 @ 

使用  字符串二进制转换 得知,二进制为 0100000 ,八位数字,第二位为 1 ,代表2号签到过。

GETBIT:获取指定偏移量上的位值。语法:GETBIT <key> <offset>

BITCOUNT:统计指定键的位中设置为1的位数。语法:BITCOUNT <key> 

BITPOS:找到第一个设置为1的位。语法:BITPOS <key> <offset> 

也可以使用get / set 直接对整个位图进行设置。 

二.代码实现

1.设置指定key的位图

在项目中,使用中key可以为  xxx前缀 + :+ 用户编号 + :+ yyyyMM 的格式,设置该人员在该月的签到情况。

redisTemplate.opsForValue().setBit(key, offset, value);

参数说明:

  • key:要操作的 Redis 键。
  • offset:要设置的位的偏移量(0-based index),即从零开始的位位置。
  • value:要设置的布尔值,true 表示设置为 1false 表示设置为 0
redisTemplate.opsForValue().setBit("sign:3123000901:202411" , 11 ,true);

 

 2.获取查询时间段内的所有月份(后续用到)
/**
     * 统计时间段内的所有月份
     * @param startDate 开始时间,格式为yyyy-MM-dd
     * @param endDate 结束时间,格式为yyyy-MM-dd
     * @return 包含所有月份的列表,格式为yyyyMM
     */
    public static List<String> getMonthsInRange(String startDate, String endDate) {
        // 定义日期格式化器
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyyMM");

        // 解析开始和结束日期
        LocalDate start = LocalDate.parse(startDate, dateFormatter);
        LocalDate end = LocalDate.parse(endDate, dateFormatter);

        // 保存所有月份的列表
        List<String> months = new ArrayList<>();

        // 逐月增加,直到超过结束日期
        LocalDate current = start.withDayOfMonth(1); // 从当月第一天开始
        while (!current.isAfter(end)) {
            months.add(current.format(monthFormatter));
            current = current.plusMonths(1); // 增加一个月
        }

        return months;
    }
3.已知获取位图时是byte[] ,将 byte[] 转换为二进制字符串(后续用到)
/**
     * 将 byte[] 转换为二进制字符串
     * @param bytes 字节数组
     * @return 二进制字符串
     */
    public static String byteArrayToBinaryString(byte[] bytes) {
        StringBuilder binaryString = new StringBuilder();
        for (byte b : bytes) {
            // 将每个字节转换为二进制字符串,并补齐为8位
            String binary = String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0');
            binaryString.append(binary);
        }
        return binaryString.toString();
    }
4.将字符串按0补齐到指定长度,补齐到该月份的天数(后续用到)
/**
     * 将字符串按0补齐到指定长度
     * @param input 原始字符串
     * @param length 目标长度
     * @return 补齐后的字符串
     */
    public static String padStringWithZeros(String input, int length) {
        StringBuilder paddedString = new StringBuilder(input);
        while (paddedString.length() < length) {
            paddedString.append("0");
        }
        return paddedString.toString();
    }
5.计算最长连续未通行天数,按1切割(后续用到)
/**
     * 计算最长连续未通行天数
     * @param bitmap 通行记录的位图值
     * @return 最长连续的0序列长度
     */
    public static int longestZeroSequence(String bitmap) {
        // 分割字符串并找出最长的连续零序列
        String[] zeroSequences = bitmap.split("1");
        int longestZeroLength = 0;
        for (String seq : zeroSequences) {
            longestZeroLength = Math.max(longestZeroLength, seq.length());
        }
        return longestZeroLength;
    }
6.具体实现代码
public List<DevPassRecord> passWarning(DevQueryParam param) {
        //计算时间段
        List<String> months = getMonthsInRange(param.getStartTime(), param.getEndTime());
        //获取该辅导员下所有学生id 例 3123000067    sql语句查询
        List<String> list = Arrays.asList("3123000067" , "3123000901");

        Integer a = Integer.valueOf(param.getStartTime().substring(8, 10));
        // 使用 DateTimeFormatter 解析 yyyy-MM-dd 格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        YearMonth yearMonth = YearMonth.parse(param.getEndTime(), formatter);
        // 返回该月份的天数
        int i1 = yearMonth.lengthOfMonth();
        //获取查询时间段中开始时间的天数(后续用到)
        Integer b = i1 - Integer.valueOf(param.getEndTime().substring(8, 10));

        StringBuilder ids = new StringBuilder();
        for (int i = 0; i < list.size(); i++){
            //该用户时间段内,通行记录字符串
            String dayStr = "";
            for (String m : months) {
                //查询redis中该key的位图
                String key = "sign:" + list.get(i) + ":" + m;
                byte[] bitmapBytes = redisTemplate.getConnectionFactory().getConnection().get(key.getBytes());
                int daysInMonth = getDaysInMonth(m);
                if(Objects.equals(bitmapBytes , null)) {
                    StringBuilder sb = new StringBuilder(daysInMonth);
                    for (int j = 0; j < daysInMonth; j++) {
                        sb.append('0');
                    }
                    dayStr = dayStr + sb;
                }else {
                    String s = byteArrayToBinaryString(bitmapBytes);
                    String s1 = padStringWithZeros(s, daysInMonth);
                    dayStr = dayStr + s1;
                }

            }

            //总长度 减去 开始月份未统计的天数 减去  结束时间未统计的天数 为最终统计情况。
            dayStr = dayStr.substring(a-1, dayStr.length() - b);
            System.out.println("总---" + dayStr);
            int num = longestZeroSequence(dayStr);
            System.out.println("最长天数---" + num);
            if(num >= param.getDays()){
                //大于参数天数的人员id,则视为长时间未通行,需要预警
                ids.append(list.get(i)).append(",");
            }
        }
        System.out.println("------>" + ids);

        return null;
    }

三.运行结果

例如分别设置偏离量为   3 ,11,12,18.分别对应代表4号,12号,13号,19号签到。

参数:查询1号到20号的签到情况,天数超过2天时预警。

结果:字符串总长度为20,分别在第4,12,13,19的位置为1,代表签到了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2231314.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Git】从 GitHub 仓库中移除误提交的 IntelliJ IDEA 配置文件夹 .idea 并将其添加到 .gitignore 文件中

问题描述 在使用Git进行版本控制时&#xff0c;不慎将.idea文件夹提交至GitHub仓库&#xff0c;即使后续在.gitignore文件中添加了.idea&#xff0c;但该文件夹仍在仓库中存在。 原因分析 .idea 是 IntelliJ IDEA 开发工具为项目创建的一个配置文件夹。IntelliJ IDEA 是一个广…

[Linux] 进程地址空间

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;青果大战linux 总有光环在陨落&#xff0c;总有新星在闪烁 好了&#xff0c;折腾…

Vue3 + Element Plus简单使用案例及【eslint】报错处理

本电脑Vue环境已安装正常使用 博主使用npm 包管理器安装 Element Plus.有问题评论区帮忙指正,感谢阅读. 在完成的过程中如果遇到eslint报错 Parsing error &#xff1a;Unexpected token { eslint 这个报错&#xff0c;也可以尝试第7部分报错处理解决。 目录 1.新建项目 2…

【云原生】Docker搭建开源翻译组件Deepl使用详解

目录 一、前言 二、微服务项目使用翻译组件的场景 2.1 多语言用户界面 2.2 业务逻辑中的翻译需求 2.3 满足实时通信的要求 2.4 内容管理系统 2.5 个性化推荐系统 2.6 日志和监控 三、开源类翻译组件解决方案 3.1 国内翻译组件方案汇总 3.1.1 百度翻译 3.1.2 腾讯翻…

DFA算法实现敏感词过滤

DFA算法实现敏感词过滤 需求&#xff1a;检测一段文本中是否含有敏感词。 比如检测一段文本中是否含有&#xff1a;“滚蛋”&#xff0c;“滚蛋吧你”&#xff0c;“有病”&#xff0c; 可使用的方法有&#xff1a; 遍历敏感词&#xff0c;判断文本中是否含有这个敏感词。 …

如何在Linux系统中使用Netcat进行网络调试

文章目录 Netcat简介安装Netcat在Debian/Ubuntu系统中安装在CentOS/RHEL系统中安装 Netcat基本命令Netcat基本用法示例1&#xff1a;监听端口示例2&#xff1a;连接到远程主机 Netcat选项-l选项-p选项-v选项 Netcat模式监听模式连接模式 Netcat排除和包含排除端口包含端口 Netc…

【ClickHouse 探秘】你知道 ClickHouse MergeTree 引擎吗?

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

推荐一款高效的内存清理工具:MemoryCleaner

MemoryCleaner是一款高效的内存清理工具&#xff0c;旨在优化您的计算机性能。它利用Windows内置的多种功能&#xff0c;能够在不影响系统运行的情况下&#xff0c;自动释放内存。用户可以通过系统托盘直接访问MemoryCleaner的功能&#xff0c;无需打开程序&#xff0c;使得内存…

MySQL分区表(二)

说明&#xff1a;之前有写过一篇博客&#xff0c;介绍MySQL如何建立分区表&#xff0c;本文介绍如何建立子分区表。子分区&#xff0c;就是在原来分区的基础上&#xff0c;再嵌套一个分区。 例如&#xff0c;按照记录的创建时间分区&#xff0c;在此基础上&#xff0c;再按照租…

ssm043基于JavaEE的龙腾公司员工信息管理系统的设计与实现+jsp(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;龙腾公司员工信息管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本龙腾公司…

使用 PyCharm 构建 FastAPI 项目:零基础入门 Web API 开发

使用 PyCharm 构建 FastAPI 项目&#xff1a;零基础入门 Web API 开发 本文提供了一份完整的 FastAPI 入门指南&#xff0c;涵盖从环境搭建、依赖安装到创建并运行一个简单的 FastAPI 应用的各个步骤。通过 FastAPI 和 Uvicorn&#xff0c;开发者可以快速构建现代化的 Web API…

<项目代码>YOLOv8 夜间车辆识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

centos7.X zabbix监控参数以及邮件报警和钉钉报警

1&#xff1a;zabbix安装 1.1 zabbix 环境要求 硬件配置: 2个CPU核心, 4G 内存, 50G 硬盘&#xff08;最低&#xff09; 操作系统: Linux centos7.2 x86_64 Python 2.7.x Mariadb Server ≥ 5.5.56 httpd-2.4.6-93.el7.centos.x86_64 PHP 5.4.161.2 zabbix安装版本 [rootnod…

类(4)

1.拷贝构造函数 我们在创建对象得的时候&#xff0c;可否创造一个与已存在对象一摸一样的对象呢&#xff1f; 拷贝构造函数&#xff1a;只有单个形参&#xff0c;该形参是对本类类型对象的引用&#xff08;一般常用const修饰&#xff09; 用在已存在的类类型对象创建新对象时…

‌【元素周期表】氢

化学式&#xff1a;H₂ 外观&#xff1a;无色透明 分子量&#xff1a;2.01588 吸入少量氢气对人体没有危害&#xff0c;甚至还可能对人体有益。但是不能吸入大量氢气&#xff0c;否则可能会对身体造成影响。 氢在生活中的主要用途包括以下几个方面‌&#xff1a; ‌医疗保健…

【06】A-Maven项目SVN设置忽略文件

做Web项目开发时&#xff0c;运用的是Maven管理工具对项目进行管理&#xff0c;在项目构建的过程中自动生成了很多不需要SVN进行管理的文件&#xff0c;SVN在对源码进行版本管理时&#xff0c;需要将其忽略&#xff0c;本文给出了具体解决方案。 SVN设置忽略Maven项目中自动生成…

【Windows】X-DOC:无需NAS使用Windows也能安装Jellyfin玩私人影音媒体平台

【Windows】X-DOC&#xff1a;无需NAS使用Windows也能安装Jellyfin玩私人影音媒体平台 1、前言2、Jellyfin服务搭建2.1 Jellyfin简介2.2 Jellyfin下载2.3 Jellyfin安装2.4 Jellyfin设置2.5 Jellyfin使用 3、终端访问3.1 浏览器访问 4、内网穿透 1、前言 下载收藏高清电影、电视…

海的记忆篇章:海滨学院班级回忆录项目

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了海滨学院班级回忆录的开发全过程。通过分析海滨学院班级回忆录管理的不足&#xff0c;创建了一个计算机管理海滨学院班级回忆录的方案。文章介绍了海滨学院班级回…

Unity 使用Netcode实现用户登录和登出

Unity之NetCode for GameObjets 基本使用 说明思路相关API代码实现Tips 说明 最近项目需要联机&#xff0c;项目方案选用Unity提供的NetCode for GameObjets&#xff08;以下简称NGO&#xff09;&#xff0c;踩了不少坑&#xff0c;本文不介绍基础使用&#xff0c;围绕双端&…

C++(类和对象-运算符重载)

运算符重载概念&#xff1a; 对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型 运算符重载的同时也可以发生函数重载 1.加号运算符重载 1.1加号运算符重载的本质 1.2运算符重载也可以发生函数重载 总结1&#xff1a;对于内置的数据类型…