Redis使用Bitmap实现数据统计

一、概念

什么是二值状态?二值状态就是元素只有0和1这两种情况,比如在签到的场景中只有签到和未签到两种,或者登陆的场景中只有已登录和未登录的情况。

Bitmap 的底层数据结构用的是 String 类型的 SDS 数据结构来保存位数组,Redis 把每个字节数组的 8 个 bit 位利用起来,每个 bit 位 表示一个元素的二值状态(不是 0 就是 1)。

可以将 Bitmap 看成是一个 bit 为单位的数组,数组的每个单元只能存储 0 或者 1,数组的下标在 Bitmap 中叫做 offset 偏移量。

8 个 bit 组成一个 Byte,所以 Bitmap 会极大地节省存储空间。 这就是 Bitmap 的优势。

二、判断登录状态场景

我们使用Bitmap来判断某个用户是否登录。Bitmap提供了GETBIT和SETBIT操作,通过一个偏移量offset对bit数组的offset位置的bit位进行读写操作,这个offset从0开始,我们还需要一个key来标记数据,将用户ID做为offset,已登录就设置1,未登录就设置0.

SETBIT命令:

SETBIT <key> <offset> <value>

GETBIT 命令:

GETBIT <key> <offset>

使用:

 

 我们执行SETBIT loginStatus 1001 1 表示ID为1001的用户是已登录状态。接下来我们执行GETBIT loginStatus 1001 获取ID为1001的用户的登录状态。SETBIT loginStatus 1001 0设置ID为1001的用户退出登录。

三、用户每个月都签到场景

在签到统计中,每个用户每天的签到用 1 个 bit 位表示,一年的签到只需要 365 个 bit 位。一个月最多只有 31 天,只需要 31 个 bit 位即可。

key 可以设计成 uid:{userId}:{yyyyMM},月份的每一天的值 - 1 可以作为 offset(因为 offset 从 0 开始,所以 offset = 日期 - 1)。

第一步:执行下面的指令表示记录用户在2023年6月25号打卡。

SETBIT uid:1001:202306 24 1

第二步:判断ID为1001的以后在2023年6月25号是否打卡

GETBIT uid:1001:202306 24

 如何统计这个月首次打卡时间呢?

Redis 提供了 BITPOS key bitValue [start] [end]指令,返回数据表示 Bitmap 中第一个值为 bitValue 的 offset 位置。

BITPOS命令:

BITPOS key bit  [start] [end]

我们可以执行BITPOS uid:1001:202306 1 命令来获取2023年6月第一次打卡的时间

BITPOS uid:1001:202306 1

 

需要注意的是,我们需要将返回的 value + 1 ,因为 offset 从 0 开始。比如现在返回的是24我们需要加上1等于25,我们在前面设置是6月25号第一次打卡的。

四、小结

当我们遇到的统计场景只需要统计数据的二值状态,比如用户是否存在、 ip 是否是黑名单、以及签到打卡统计等场景就可以考虑使用 Bitmap。

只需要一个 bit 位就能表示 0 和 1。在统计海量数据的时候将大大减少内存占用。

在SpringBoot项目中,使用RedisBitMap数据结构可以有效地实现用户的签到与签到统计功能。RedisBitMap是一种特殊的数据类型,它通过一个二进制位数组来存储数据,可以将每一位看作一个开关,用来表示一个布尔值。这种方法在处理连续日期或者大规模数据时,可以极大程度地节省空间。 ### 实现步骤如下: 1. **引入依赖**:首先确保你的SpringBoot项目中已经引入了Spring Data Redis的依赖。 2. **配置Redis连接**:在`application.properties`或`application.yml`文件中配置Redis的连接信息。 3. **签到功能**: - 使用用户的唯一标识(例如用户ID)来作为BitMap的key。 - 使用日期(通常是年月日,可以转换为一个整数)作为offset,这个offset就是BitMap中的位置。 - 使用`SETBIT`命令将对应日期的offset设置为1,表示用户当天签到。 4. **签到统计功能**: - 使用`GETBIT`命令可以检查用户在特定日期是否签到,返回1表示签到,返回0表示未签到。 - 使用`BITCOUNT`命令可以统计某个用户在一定时间范围内的签到天数。 - 使用`BITOP`命令可以实现复杂的逻辑操作,比如统计连续签到天数。 5. **接口实现**: - 在SpringBoot中创建相应的Controller来处理签到请求。 - 在Service层调用RedisTemplate操作BitMap进行签到和统计。 - 在Repository层定义Redis操作的方法。 ### 示例代码片段: ```java // Controller @RestController @RequestMapping("/api/signin") public class SignInController { @Autowired private SignInService signInService; @PostMapping("/checkin") public ResponseEntity<?> userCheckIn(@RequestParam Long userId) { signInService.userCheckIn(userId); return ResponseEntity.ok("Sign in successful."); } // 其他方法... } // Service @Service public class SignInService { @Autowired private StringRedisTemplate stringRedisTemplate; public void userCheckIn(Long userId) { LocalDate today = LocalDate.now(); String key = "signin:" + userId; int offset = today.toEpochDay(); stringRedisTemplate.opsForValue().setBit(key, offset, true); } // 其他方法... } ``` ### 注意事项: - 在使用BitMap时需要注意offset的有效范围,通常应该在一个合理的日期范围内,否则可能会有数据错位的风险。 - BitMap中每个位只能表示0或1两种状态,因此在设计时需要确定好这两种状态的意义。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qinxun2008081

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值