Bitmap实现签到功能

文章介绍了如何利用Bitmap数据结构,特别是Redis中的Bitmap实现大规模用户签到功能。通过SETBIT和GETBIT命令可以判断用户登录状态,BITCOUNT用于统计签到次数。对于连续签到用户数量的统计,可以通过多个Bitmap的位运算来实现。此外,还提到如何计算单个用户的连续签到天数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

bitmap实现签到功能🚩

用BitMap实现亿级数据统计:

  • 常见场景:二值状态统计

    • 给一个 userId ,判断用户登陆状态;
    • 显示用户某个月的签到次数和首次签到时间;
    • 两亿用户最近 7 天的签到情况,统计 7 天内连续签到的用户总数
  • Bitmap 的底层数据结构用的是 String 类型的 SDS 数据结构来保存位数组,Redis 把每个字节数组的 8 个 bit 位利用起来,每个 bit 位 表示一个元素的二值状态(不是 0 就是 1)。

  • 判断用户登陆状态:SETBIT <key> <offset> <value> GETBIT <key> <offset>

    判断 ID = 10086 的用户的登陆情况:

    1. 表示用户已登录:SETBIT login_status 10086 1

    2. 检查该用户是否登陆:GETBIT login_status 10086

    3. 登出:SETBIT login_status 10086 0

  • 用户每个月的签到情况:

    用户在 2021 年 5 月 16 号打卡:

    1. 用户在 2021 年 5 月 16 号打卡:SETBIT uid:sign:89757:202105 15 1
    2. 判断编号 89757 用户在 2021 年 5 月 16 号是否打卡:GETBIT uid:sign:89757:202105 15
    3. 统计该用户在 5 月份的打卡次数:BITCOUNT uid:sign:89757:202105
  • 连续签到用户总数:

    在记录了一个亿的用户连续 7 天的打卡数据,如何统计出这连续 7 天连续打卡用户总数呢?

    把每天的日期作为Bitmap的 key,userId 作为 offset,若是打卡则将 offset 位置的 bit 设置成 1。

    一共有 7 个这样的 Bitmap,如果我们能对这 7 个 Bitmap 的对应的 bit 位做 『与』运算。

    同样的 UserID offset 都是一样的,当一个 userID 在 7 个 Bitmap 对应对应的 offset 位置的 bit = 1 就说明该用户 7 天连续打卡。

    结果保存到一个新 Bitmap 中,我们再通过 BITCOUNT 统计 bit = 1 的个数便得到了连续打卡 7 天的用户总数了。

  • 统计单个用户的连续签到天数:

    • 查到bitmap里的所有记录:BITFIELD sign:5:202203 GET u14 0(无符号14个数据,从0开始)

    • 循环遍历这个数和1与运算,为0则未签到,结束,为1则签到了,计数器加一。

    • 最后再右移一位。

      int count = 0;
      while(true){
          if(num & 1 == 0){
              break;
          }else{
              count++;
          }
          num >>>= 1;
      }
      

### 如何使用 Redis Bitmap 实现签到功能 #### 使用场景说明 Redis Bitmap 特别适合用于记录二元状态的数据,比如用户的每日签到情况。通过将每一天映射到位图中的某一位(bit),可以高效地管理和查询签到信息。 #### 关键概念解释 - **位图索引**:每一位代表一天的状态(0 或 1),其中 `1` 表示已签到,而 `0` 则表示未签到。 - **时间戳转换**:通常会把日期转化为 Unix 时间戳来作为位的位置参数[^2]。 #### 核心操作介绍 为了实现这一功能,主要依赖以下几个命令: - `SETBIT key offset value`: 设置指定位置上的比特值为给定的新值。 - `GETBIT key offset`: 获取指定位置上的比特值。 - `BITCOUNT key [start end]`: 计算某个范围内被设置成 `1` 的比特数量,可用于统计总签到次数。 - `BITPOS key bit [start] [end]`: 查找第一个匹配的比特位置,可用来查找最近一次签到的时间点[^3]。 #### 示例代码展示 (Java) 下面是一个简单的 Java 方法演示如何利用上述命令完成基本的签到逻辑: ```java import redis.clients.jedis.Jedis; public class SigninService { private final Jedis jedis; public SigninService(String host, int port){ this.jedis = new Jedis(host,port); } /** * 用户签到方法 */ public void signin(long userId, long timestamp) { String key = "signin:" + userId; // 构建唯一标识符 jedis.setbit(key, timestamp / 86400, true); // 将当天对应的位设为true(即1),假设timestamp是以秒计数的一天起始时刻 } } ``` 此段代码创建了一个名为 `SigninService` 的类,它接收主机名和端口号初始化连接池,并定义了 `signin()` 函数来进行具体的签到动作。这里假定传入的时间戳是基于每天零点计算得到的结果,因此可以直接除以一天的秒数 (`86400`) 来获取相对于年初以来经过了多少整天,从而定位到具体哪一位应该被置为 `1`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Guanam_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值