Redis BitMap(位图)

这里是小咸鱼的技术窝(CSDN板块),我又开卷了

在这里插入图片描述

之前经手的项目运行了10多年,基于重构,里面有要实现一些诸如签到的需求,以及日历图的展示,可以用将签到信息存到传统的关系型数据库(MySql、Oracle) 然后用 Sql 进行统计、也可以借助 Redis 中的 BitMap来实现签到需求。俩者的区别就在于,一个签到了100万年的项目,你用Mysql无论如何进行分库分表,落地到磁盘的上的数据体量都很大,且查询速度会变慢,但是用 Redis 存储数据占用的内存小,且统计效率更快。当然如果你怕Redis挂,也可以存俩份数据,一份放Mysql一份放Redis,利用 Redis 缓存考勤结果加快查询效率,但是占用的机器磁盘过大的问题还是没解决,下面介绍用 BitMap 如何实现下面这个签到日历。

在这里插入图片描述

这个项目的签到用到了海康的人脸识别SDK靠每天进行人脸识别打卡,然后记录签到信息的,就拿手动点击签到来说。整个流程如下。

用户点击签到按钮,发起一个签到请求给我们,先调用 getbit 命令,判断今天有没有进行签到过,没有然后调用 setbit 命令,把签到结果存入 BitMap(期间用户重复点击签到也没事,BitMap多次重复设置值的操作是幂等的)

BitMap 介绍 https://redis.io/commands/bitop/

下面的这段洋文是官网对BitMap的介绍

Bitmaps are not an actual data type, but a set of bit-oriented operations defined on the String type which is treated like a bit vector. Since strings are binary safe blobs and their maximum length is 512 MB, they are suitable to set up to 2^32 different bits.

在这里插入图片描述

位图不是实际的数据类型,而是在字符串类型上定义的一组面向位的操作,该操作被视为位向量。由于字符串是二进制安全blob,字符串最大为512 MB,因此它们适合设置为2^32个不同的位。从这段话中我们可以知道,BitMap 其实就是一个二进制的容器,并且他的二进制位最大为 2^32 位(512Mb = 512 * 1024 * 1024 * 8 = 2^32个bit位),当然我们签到只用的到31 bit 位,因此针对于签到需求来说,Bitmap初始结构长这样

0000000000|0000000000|0000000000|0

联想一下我们一个月最大 31 天,1号签到了我们在第一bit位设置为1就好了,同理在第2,3,4,5天签到了,在对应的bit位设置值为1就好了,BitMap是不是很适合签到场景。并且它提供了很多统计API。

在这里插入图片描述

SETBIT key offset value:将指定偏移量上的位设置为10GETBIT key offset:获取指定偏移量上的位的值。
BITCOUNT key start end:计算指定key的Bitmap中1的数量。
BITOP operation destkey key [key...]:对多个key进行位运算,并将结果存储到destkey中。operation可以是ANDORXORNOT等。
BITPOS key 1 start end:查找指定key的Bitmap中第一个1的偏移量。
BITPOS key 0 start end:查找指定key的Bitmap中第一个0的偏移量。
BITPOS key 0 start:从start的位置开始,查找指定key的Bitmap中第一个0的偏移量。
SET key value:将指定key的Bitmap设置为指定的值。
GET key:获取指定key的Bitmap的值。
//类型u代表无符号十进制,i代表带符号十进制
BITFIELD key get u3 0:从偏移量offset=0开始取3位,获取无符号整数的值,返回的值是一个十进制数
INCRBY u4 4 1:从偏移量offset=4后开始取4位,得到一个对应的二进制数,然后转换成10进制加1
  • 利用 bitcount 命令我们可以快速统计出用户,本月签到了多少天
  • 利用 setbit 命令我们可以快速记录签到信息
  • 利用 getbit 命令我们可以快速判断用户今天是否已经签到

值得注意的是 BITCOUNT key start end 命令中的 start end 指的是 byte 的区间,而 1 byte = 8 bit。那么执行如下命令

BITCOUNT key start end

bitcount char 0 8的结果是10就不奇怪了,统计范围是 0-8 byte区间,转换成 bit 区间就是 0-64。0-64范围内有 10个1。因此结果是10而不是3!!!!!

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

签到场景里面一般都不会直接去给Bitmap设置字符串,设置字符串还要去转换成对应的ACSII码然后存入BitMap,而是用 setbit 命令按bit设置值。

在这里插入图片描述

注意点二 例如 执行 setbit key 8 1 命令,存储的是 0000000010000000 而不是 000000001,低bit 位会用 0 补齐,因为 byte 是最小的存储单元。这些个个细节要搞清楚哦。

在这里插入图片描述

另外BitMap也支持二进制数(与、或运算),平常很少用这个。跟着我大声朗读运算法则,与运算都是1才为1,或运算有1就是1。

mac:0>set a a (01100001)
"OK"
mac:0>set b b (01100010)
"OK"
mac:0>bitop and andres a b (a、b与运算,结果设置到anres)
"1"
mac:0>bitop or orres a b (a、b或运算,结果设置到orres)

BitMap的源码,自行去翻阅redis安装目录下的 src里面的c文件,蹲一个c语言大佬

在这里插入图片描述

在这里插入图片描述

BitMap签到脚手架

接着用Jedis实现,因为Api命名和原始redis命令很接近。实际开发中合理织入自己的业务逻辑即可。

@Slf4j
@Api(tags = "Bit签到")
@RestController
@RequestMapping("/bit")
public class BitController {@Autowiredprivate Jedis jedis;@ApiOperation("获取签到天数")@PostMapping("/userSignCount")public Result userSignCount(@RequestBody RedisRequest redisRequest) {//相当于执行 bitcount user:sign:uid:yyyyMM 0 31 命令return Result.success(jedis.bitcount(buildSignKey(redisRequest.getUid(),getDate(redisRequest.getDateStr())), 0, 31));}@ApiOperation("签到/补签")@PostMapping("/userSign")public Result sign(@RequestBody RedisRequest redisRequest) {//日期字符串转DateDate date = getDate(redisRequest.getDateStr());//该日期该月的第几天int offset = DateUtil.dayOfMonth(date) - 1;//user:sign:uid:yyyyMMString signKey = buildSignKey(redisRequest.getUid(), date);Assert.isFalse(jedis.getbit(signKey, offset), "今天以及签到过了");//相当于执行 setbit user:sign:uid:yyyyMM offset 1 命令jedis.setbit(signKey, offset, true);return Result.success(getContinuousSignCount(redisRequest.getUid(), date));}/*** 统计截止日之前连续签到的天数* @param userId 用户id* @param date 截止日* @return*/private int getContinuousSignCount(Integer userId, Date date) {int dayOfMonth = DateUtil.dayOfMonth(date);//相当于执行 bitfield user:sign:uid:yyyyMM u10 0 命令List<Long> list = jedis.bitfield(buildSignKey(userId, date), "get", "u" + dayOfMonth, "0");if (list == null || list.isEmpty()) {return 0;}int signCount = 0;long v = list.get(0) == null ? 0 : list.get(0);// i 表示位移操作次数for (int i = dayOfMonth; i > 0; i--) {// 右移再左移,如果等于自己说明最低位是 0,表示未签到if (v >> 1 << 1 == v) {// 低位 0 且非当天说明连续签到中断了if (i != dayOfMonth) {break;}} else {signCount++;}// 右移一位并重新赋值,相当于把最低位丢弃一位v >>= 1;}return signCount;}private String buildSignKey(Integer userId, Date date) {return String.format("user:sign:%d:%s", userId,DateUtil.format(date, "yyyyMM"));}/*** 获取日期*/private Date getDate(String dateStr) {if (StrUtil.isBlank(dateStr)) {return new Date();}try {return DateUtil.parseDate(dateStr);} catch (Exception e) {throw new RuntimeException("请传入yyyy-MM-dd的日期格式");}}}

BitMaq去重

因为字符串最大为512mb,因此可以算出BitMap的最大长度是2的32次方。约42亿个bit位。去重也很简单,就拿我的QQ号去重来说,QQ: 3273448110,在 3273448110 的bit位置上设置为1就好了,同理其他QQ号在自己的Bit位上设置为1,最终统计BitMap有多少个1就得到了,不重复QQ号的个数。

总结

本文涵盖了BitMap从Api使用,到落地到常用场景的上的真实业务体现。以及使用上的注意事项。

爱我你就关注我,这里是小咸鱼的技术窝

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2017年第六届数学建模国际赛小美赛A题飓风与全球变暖解题全过程文档及程序

2017年第六届数学建模国际赛小美赛 A题 飓风与全球变暖 原题再现&#xff1a; 飓风&#xff08;也包括在西北太平洋被称为“台风”的风暴以及在印度洋和西南太平洋被称为“严重热带气旋”&#xff09;具有极大的破坏性&#xff0c;往往造成数百人甚至数千人死亡。   许多气…

【Transformer框架代码实现】

Transformer Transformer框架注意力机制框架导入必要的库Input Embedding / Out EmbeddingPositional EmbeddingTransformer EmbeddingScaleDotProductAttention(self-attention)MultiHeadAttention 多头注意力机制EncoderLayer 编码层Encoder多层编码块&#xff0f;前馈网络层…

CentOS安装Python解释,CentOS设置python虚拟环境,linux设置python虚拟环境

一、安装python解释器 1、创建解释器安装的目录&#xff1a;/usr/local/python39 cd /usr/local mkdir python39 2、下载依赖 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make libffi-devel xz-devel …

【蓝桥杯】专题练习

前缀和 3956. 截断数组 - AcWing题库 一看到题目很容易想到的思路是对数组求前缀和&#xff0c;然后枚举两个分段点就好&#xff0c;时间复杂度是On^2&#xff0c;n是1e5会t&#xff0c;需要优化。 朴素的代码&#xff0c;会超时&#xff1a; #include <bits/stdc.h> u…

【小白专用】php pdo sqlsrv 类,php连接sqlserver

1.找到自己版本&#xff0c;我的程序是64位的。 注意&#xff1a;ts与nts的区别&#xff0c;查看phpinfo信息&#xff0c;如下 <?phpecho phpinfo();?> 2.运行后&#xff0c;可以查看到如下数据&#xff1a; ① PHP 的版本是8.2.13&#xff1b; ② 属于线程安全版 ts…

Axure中继器的使用

目录 一. 中继器 概述 作用 运用场景 二. 中继器的使用 三. 三列表格增删改查案例展示 一. 中继器 概述 在Axure软件中&#xff0c;中继器&#xff08;Repeater&#xff09;是一种特殊的控件&#xff0c;它的作用是允许用户创建重复的数据项&#xff0c;并以列表或表格…

Kubernetes 容器编排(6)

企业级镜像仓库Harbor 上传harbor安装包并安装 $ tar xf harbor-offline-installer-v2.5.3.tgz $ cp harbor.yml.tmpl harbor.yml $ vim harbor.yml hostname: 192.168.246.217# http related config http:# port for http, default is 80. If https enabled, this port will…

计算机组成原理第4章-(主存储器)【中】

只读存储器ROM分类 对于只读存储器ROM来说&#xff0c;共有三类&#xff1a;“PROM”、“EPROM”、“EEPROM”。 存储器的扩展【重要】 首先&#xff0c;我们要明白存储器为什么要扩展&#xff1f;&#xff1f; 因为单片存储芯片的容量是有限的&#xff0c;很那满足实际的需…

神经网络:池化层知识点

1.CNN中池化的作用 池化层的作用是对感受野内的特征进行选择&#xff0c;提取区域内最具代表性的特征&#xff0c;能够有效地减少输出特征数量&#xff0c;进而减少模型参数量。按操作类型通常分为最大池化(Max Pooling)、平均池化(Average Pooling)和求和池化(Sum Pooling)&a…

回归烟火气,中国烹饪正在进行一场重构

当前的中国厨电行业&#xff0c;急需一场前所未有的变革。 近几年&#xff0c;厨电行业已告别以往的跨越式增长&#xff0c;多数厨电企业陷入迷茫&#xff0c;如何才能打破增长瓶颈&#xff1f;《一点财经》认为&#xff0c;只有积极适应新形势&#xff0c;探索新的经营方式&a…

基于Antd4 和React-hooks的项目开发

基于Antd4 和React-hooks的项目开发 https://github.com/dL-hx/react-cnode 项目依赖使用 react 16.13react-redux 7.xreact-router-dom 5.xredux 4.xantd 4axiosmoment 2.24 (日期格式化)qs 项目视图说明 首页主题详情用户列表用户详情关于 配置按需加载 https://3x.an…

DC-8靶场

目录 DC-8靶场链接&#xff1a; 首先进行主机发现&#xff1a; sqlmap得到账号密码&#xff1a; 反弹shell&#xff1a; exim4提权&#xff1a; Flag&#xff1a; DC-8靶场链接&#xff1a; https://www.five86.com/downloads/DC-8.zip 下载后解压会有一个DC-8.ova文件…

自动气象监测站助力生活生产

随着科技的发展&#xff0c;我们的生活和生产方式正在发生着日新月异的变化。其中&#xff0c;WX-CQ12 自动气象监测站作为一项气象监测设备&#xff0c;正在发挥着越来越重要的作用。它不仅为我们提供了更加准确、实时的天气信息&#xff0c;还为农业、交通、旅游等领域提供了…

studioone 6.5中文版功能特点

studioone 6.5中文版是一款强大的音乐编曲软件,可以帮助您使用灵活的和弦轨道功能实现音乐创作&#xff0c;该软件更加人性化的贴近人们使用的习惯&#xff0c;增加了很多专业性的功能&#xff0c;在完成简单的编辑操作后&#xff0c;会得到直观的修改过程&#xff0c;有需要的…

实验:使用ADC读取烟雾传感器的值

CubeMX 配置 3.3/4096 * smoke_value 这个表达式的含义是将ADC的原始数值 smoke_valuesmoke_value 转换成相应的电压值&#xff0c;假设ADC的范围是0到4095&#xff0c;电源电压是3.3V。这是一个将ADC的数字值映射到实际电压值的线性转换。 具体来说&#xff1a; 3.33.3 是电…

《论文阅读28》Unsupervised 3D Shape Completion through GAN Inversion

GAN&#xff0c;全称GenerativeAdversarialNetworks&#xff0c;中文叫生成式对抗网络。顾名思义GAN分为两个模块&#xff0c;生成网络以及判别网络&#xff0c;其中 生成网络负责根据随机向量产生图片、语音等内容&#xff0c;产生的内容是数据集中没有见过的&#xff0c;也可…

excel导出,post还是get请求?

1&#xff0c;前提 今天在解决excel导出的bug时&#xff0c;因为导出接口查询参数较多&#xff0c;所以把原来的get请求接口修改为post请求 原代码&#xff1a; 修改后&#xff1a; 2&#xff0c;修改后 postman请求正常&#xff0c;然后让前端对接口进行同步修改&#xff0…

【CSS @property】CSS自定义属性说明与demo

CSS property property - CSS: Cascading Style Sheets | MDN At 规则 - CSS&#xff1a;层叠样式表 | MDN Custom properties (–*): CSS variables - CSS: Cascading Style Sheets | MDN CSS Houdini - Developer guides | MDN &#x1f4da; 什么是property? property CSS…

2023优秀开源项目获选榜名单(开放原子开源基金会)|JeecgBoot 成功入选

JeecgBoot 是一个开源的企业级低代码开发平台&#xff0c;它成功入选2023年度生态开源项目&#xff0c;这是对其十年坚持开源的认可。作为一个开源项目&#xff0c;JeecgBoot 在过去的十年里一直秉承着开放、共享、协作的理念&#xff0c;不断推动着开源社区的发展。 2023年开放…

计算机视觉的应用22-基于计算机视觉领域与VR虚拟现实眼镜,构思考虑远程协助独居老人生活起居的应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用22-基于计算机视觉领域与VR虚拟现实眼镜&#xff0c;构思考虑远程协助独居老人生活起居的应用&#xff0c;在当下信息科技飞速发展的社会背景下&#xff0c;老龄化问题日益凸显。越来越多的老年人选…