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

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

#一看到通行签到相关,就想到了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.xdnf.cn/news/7038.html

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

相关文章

java 多态

1.认识多态 class animals{String name"animals";public void run(){} } class cat extends animals{String name"cat";Overridepublic void run(){System.out.println("cat run");} } class dog extends animals{String name"dog";Ov…

Android TextView自动换行文本显示不全解决

某些情况下&#xff0c;TextView自动换行后&#xff0c;会出现每行结尾处显示不全的问题&#xff0c; 如图&#xff1a; 常见解决方案&#xff1a; 设置TextView的“ellipsize”属性为“end” 实测无效&#xff01;将TextView外部的Layout改为RelativeLayout 实测无效&…

基于springboot+vue实现的养老院管理系统(源码+L文+ppt)

基于springbootvue实现的养老院管理系统&#xff08;源码L文ppt&#xff09;4-106 养老院系统管理是一个综合性养老在线平台&#xff0c;旨在综合并简化养老机构中的照护流程。该系统集成了多种功能&#xff0c;以支持医生、护士、家属及管理员等不同角色的需求。对于医务人员而…

智慧城市的守护者——智能井盖监测终端

城市化进程的加速推进使得基础设施建设成为提升城市品质的关键环节。然而&#xff0c;在这一进程中&#xff0c;市政公用设施中的井盖与地下线缆的安全问题却日益凸显。由于缺乏有效的实时监控与管理体系&#xff0c;给犯罪分子留下了可趁之机&#xff0c;频繁发生的井盖被盗及…

uniApp之uni-file-picker使用踩坑

标题党~也不算坑吧 就是初体验 上传是需要存储一下子的&#xff0c;我以为uniApp是自己免费开的服务给大家中转使用&#xff0c;就没管这个事&#xff0c;但是官网是这么说的&#xff1a; 就我是怎么发现的&#xff0c;使用了一段时间后&#xff0c;上传的图片都裂了&#xff…

动态规划理论基础和习题【力扣】【算法学习day.23】

前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&am…

Docker:介绍与安装

Docker官网与仓库地址 docker官网&#xff1a;http://www.docker.comopenDocker Hub官网: https://hub.docker.com/open Docker三要素 镜像 (Image) 镜像是Docker的核心概念之一&#xff0c;它是不可变的、只读的&#xff0c;并包含了一套文件系统&#xff0c;里面包含了运…

基于SpringBoot的微信小程序学生运动打卡系统【附源码】

基于SpringBoot的微信小程序学生运动打卡系统 效果如下&#xff1a; 系统主页面 论坛页面 登陆页面 我的页面 系统登录页面 管理员主页面 公告信息页面 研究背景 随着数字化时代的到来&#xff0c;大学生的生活节奏日益加快&#xff0c;学习压力与社交活动并行不悖。如何在繁…

【go从零单排】go中的nil到底是啥意思?

Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 nil 在Go语言中&#xff0c;nil 是一个预定义的标识符&#xff0c;用于表示指针、切片、映射、通道、接口和函数的…

forEach可以遍历不可枚举属性吗

首先第一个问题,forEach能不能遍历对象的属性 const obj { a: 1, b: 2, c: 3 }; obj.forEach((item) > console.log(item))运行这段代码我们发现发生了一个错误 这说明forEach是不可以遍历对象的属性的 在js中,forEach 方法用于遍历数组或类数组对象&#xff08;如 NodeL…

书生大模型实战营第四期-入门岛-1. Linux前置基础

入门岛-Linux前置基础 书生大模型实战营-第四期-Linux前置基础&#xff1a; 任务&#xff1a;https://github.com/InternLM/Tutorial/blob/camp4/docs/L0/linux/task.md 文档&#xff1a;https://github.com/InternLM/Tutorial/tree/camp4/docs/L0/linux 任务描述完成所需时…

Webserver(4.9)本地套接字的通信

目录 本地套接字 本地套接字 TCP\UDP实现不同主机、网络通信 本地套接字实现本地的进程间的通信&#xff0c;类似的&#xff0c;一般采用TCP的通信流程 生成套接字文件 #include<arpa/inet.h> #include<stdio.h> #include<stdlib.h> #include<unistd.h&…

ubuntu22.04 docker-compose搭建apisix高可用

首先你得先确保每台主机安装了docker和docker-compose 3台主机 没有安装docker和docker-compose的可以看我前两篇博客 可以先克隆仓库 git clone https://github.com/apache/apisix-docker.git 进入example目录 拷贝dashboard配置文件 将all-in-one中apisix-dashboard文件夹拷…

stable diffusion 大模型

本节内容&#xff0c;给大家带来的是stable diffusion的基础模型课程。基础模型&#xff0c;我们有时候也称之为大模型。在之前的课程中&#xff0c;我们已经多次探讨过大模型&#xff0c;并且也见识过一些大模型绘制图片的独特风格&#xff0c;相信大家对stable diffusion大模…

AI-Prompt、RAG、微调还是重新训练?选择正确的生成式AI的使用方法

生成式人工智能正在快速发展&#xff0c;许多人正在尝试使用这项技术来解决他们的业务问题。一般情况下有4种常见的使用方法&#xff1a; Prompt Engineering Retrieval Augmented Generation (RAG 检索增强生成) 微调 从头开始训练基础模型(FM) 本文将试图根据一些常见的…

数字化装配助力柔性制造与快速换型,驱动效率飞跃

数字化装配是利用先进的数字化技术&#xff0c;如三维建模、仿真分析、物联网、大数据、人工智能等&#xff0c;对装配过程进行精确设计、优化控制和智能管理的一种现代化生产方式。它打破传统装配依赖于人工经验和物理样机的局限&#xff0c;通过模拟环境进行预装配验证&#…

软件测试学习笔记丨Vue常用指令-输入绑定(v-model)

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/23461 指令 指令是将一些特殊行为应用到页面DOM元素的特殊属性 格式都是以v-开始的&#xff0c;例如&#xff1a; v-model&#xff1a;双向绑定v-if和v-else&#xff1a;元素是否存在v-sho…

关于“浏览器”上不了网的问题

一、起因 小编的笔记本电脑浏览器又坏了&#xff0c;所有浏览器都上不了网&#xff1f;&#xff1f;&#xff1f;&#xff08;当然了WIFI已连接&#xff09; 但是微信可以正常发消息 因为上次也有过&#xff0c;这次又出现了&#xff0c;所以小编写篇文章记录一下解决方法 二…

自动化神器:如何用Markdown写自动化用例!

01 什么是Gauge Gauge是一款用于编写和运行验收测试的BDD框架&#xff0c;它有如下的特点&#xff1a; 使用Markdown的简单、灵活的语法来描述行为 支持多平台&#xff08;Windows、Linux、macOS&#xff09;、多语言(C#、Java、Javascript、Python、Ruby&#xff09; 支持插…

Facebook定位不准是什么原因?

不知道出海获客的小伙伴有没有人跟我遇到一样的问题&#xff1a;Facebook账号定位与IP地位不一致。定位不准确会导致无法看到账号好友&#xff0c;并且账号可能很快受限&#xff0c;无法正常使用。所以解决这个问题是当务之急&#xff0c;下面分享一下可能出现这个情况的原因以…