SpringBoot+Redis Bitmap实现活跃用户统计

 更新时间:2023年11月17日 10:40:25   作者:myprince003  
Redis的Bitmap数据结构是一种紧凑的位图,它可以用于实现各种场景,其中统计活跃用户是一种经典的业务场景,下面我们就来学习一下SpringBoot如何利用Redis中的Bitmap实现活跃用户统计吧

前言

Redis的Bitmap数据结构是一种紧凑的位图,它可以用于实现各种场景,其中统计活跃用户是一种经典的业务场景。

实现原理是,通过将每个用户表示为一个位,从而跟踪用户的活跃状态,使用位图记录用户每天是否登录,并计算月度或年度活跃用户数。

案例代码

以下是一个小例子,可以看到,使用SpringDataRedis,可以很轻松的实现BitMap的操作。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.BitSet;

@Service
public class UserLoginService {

    // 用户登录记录的键前缀
    private static final String LOGIN_KEY_PREFIX = "login:"; 
    // 月份格式化器
    private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM"); 
    // 年份格式化器
    private static final DateTimeFormatter YEAR_FORMATTER = DateTimeFormatter.ofPattern("yyyy"); 

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 记录用户登录
     *
     * @param userId 用户ID
     */
    public void recordLogin(String userId) {

        // 获取存储当天用户登录信息的键
        String loginKey = getLoginKey(); 
        // 计算位图偏移量,对应用户ID的哈希码
        int bitOffset = getUserIdHashCode(userId); 
        // 将用户ID对应的位设置为1,表示用户登录
        redisTemplate.opsForValue().setBit(loginKey, bitOffset, true); 
    }

    /**
     * 获取月度活跃用户统计数据
     *
     * @return 月度活跃用户统计数据
     */
    public BitSet getMonthlyActiveUsers() {

        // 获取存储月度活跃用户信息的键
        String monthlyKey = getMonthlyKey(); 
        // 从Redis中获取位图数据
        return retrieveBitSet(monthlyKey); 
    }

    /**
     * 获取年度活跃用户统计数据
     *
     * @return 年度活跃用户统计数据
     */
    public BitSet getYearlyActiveUsers() {

        // 获取存储年度活跃用户信息的键
        String yearlyKey = getYearlyKey(); 
        // 从Redis中获取位图数据
        return retrieveBitSet(yearlyKey); 
    }

    /**
     * 获取存储当天用户登录信息的键
     */
    private String getLoginKey() {

        LocalDate today = LocalDate.now();
        String dateKey = today.format(DateTimeFormatter.ISO_DATE);
        return LOGIN_KEY_PREFIX + dateKey;
    }

    /**
     * 计算用户ID的哈希码,保证非负数并适应位图长度
     */
    private int getUserIdHashCode(String userId) {

        int hashCode = userId.hashCode();
        // 1073741823是Redis位图最大支持长度(2^30-1),可根据实际需求调整
        return Math.abs(hashCode % 1073741823); 
    }

    /**
     * 获取存储月度活跃用户信息的键
     */
    private String getMonthlyKey() {

        LocalDate today = LocalDate.now();
        String monthKey = today.format(MONTH_FORMATTER);
        return LOGIN_KEY_PREFIX + "monthly:" + monthKey;
    }

    /**
     * 获取存储年度活跃用户信息的键
     */
    private String getYearlyKey() {

        LocalDate today = LocalDate.now();
        String yearKey = today.format(YEAR_FORMATTER);
        return LOGIN_KEY_PREFIX + "yearly:" + yearKey;
    }

    /**
     * 从Redis中获取位图数据
     */
    private BitSet retrieveBitSet(String key) {

        // 获取存储在Redis中的位图数据
        byte[] bytes = (byte[]) redisTemplate.opsForValue().get(key); 
        if (bytes != null) {
            // 将字节数组转换为BitSet
            return BitSet.valueOf(bytes); 
        } else {
            // 若不存在,则返回空的BitSet
            return new BitSet(); 
        }
    }
}

其中有几个地方解释一下:

1、recordLogin方法用于记录用户登录情况。每天的登录情况被保存在以"login:日期"为键的位图中,用户的登录状态由位图中对应的位表示;

2、countMonthlyActiveUsers方法用于计算月度活跃用户数量。每个月的活跃用户数保存在以"login:monthly:年月"为键的位图中,通过Redis的bitCount方法统计位图中置为1的位数,即月度活跃用户数;

3、ountYearlyActiveUsers方法用于计算年度活跃用户数量,原理同上,只是统计的键变为"login:yearly:年份";

4、getLoginKey、getUserIdHashCode、getMonthlyKey和getYearlyKey是辅助方法,负责生成对应的Redis键或计算用户ID的哈希码。

转换

上面的例子最终返回的是BitSet对象,通过这个对象我们经过转换后可以获取到许多经典的统计数据,这里列举一些经典常用的统计结果示例。

大家可以根据这里面列举的统计数据,针对上面的代码进行替换,得到自己想要的结果。

import java.util.BitSet;

// 获取月度活跃用户统计数据
BitSet monthlyActiveUsers = userLoginService.getMonthlyActiveUsers();

// 获取年度活跃用户统计数据
BitSet yearlyActiveUsers = userLoginService.getYearlyActiveUsers();

// 统计月度活跃用户数量
int monthlyActiveUserCount = monthlyActiveUsers.cardinality();

// 统计年度活跃用户数量
int yearlyActiveUserCount = yearlyActiveUsers.cardinality();

// 判断某个用户是否为月度活跃用户
String userId = "user123";
boolean isMonthlyActiveUser = monthlyActiveUsers.get(userLoginService.getUserIdHashCode(userId));

// 判断某个用户是否为年度活跃用户
boolean isYearlyActiveUser = yearlyActiveUsers.get(userLoginService.getUserIdHashCode(userId));

// 输出统计结果
System.out.println("月度活跃用户数量: " + monthlyActiveUserCount);
System.out.println("年度活跃用户数量: " + yearlyActiveUserCount);
System.out.println("用户user123是否为月度活跃用户: " + isMonthlyActiveUser);
System.out.println("用户user123是否为年度活跃用户: " + isYearlyActiveUser);

总结

Redis的Bitmap数据结构非常灵活,可以根据具体需求实现各种位操作,但平时在项目中很多人没有机会使用到,这个案例非常简单,希望能让大家对此有个认识,未来用到了不会感到陌生。

以上就是SpringBoot+Redis Bitmap实现活跃用户统计的详细内容,更多关于SpringBoot Redis Bitmap用户统计的资料请关注脚本之家其它相关文章!

相关文章

  • java中乐观锁与悲观锁区别及使用场景分析

    java中乐观锁与悲观锁区别及使用场景分析

    本文主要介绍了java中乐观锁与悲观锁区别及使用场景分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-08-08
  • Nacos通过RefreshScope实现配置自动更新的方式分享

    Nacos通过RefreshScope实现配置自动更新的方式分享

    这篇文章主要给大家介绍了Nacos如何通过RefreshScope实现配置自动更新,文中给了两种实现方式供大家参考,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2023-09-09
  • SpringBoot Maven Clean报错解决方案

    SpringBoot Maven Clean报错解决方案

    这篇文章主要介绍了SpringBoot Maven Clean报错解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • SpringBoot+VUE实现前后端分离的实战记录

    SpringBoot+VUE实现前后端分离的实战记录

    这篇文章主要介绍了SpringBoot+VUE实现前后端分离的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • 使用SpringDataJpa创建中间表

    使用SpringDataJpa创建中间表

    这篇文章主要介绍了使用SpringDataJpa创建中间表,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • Java 中的内存映射 mmap

    Java 中的内存映射 mmap

    这篇文章主要介绍了Java 中的内存映射,mmap 是一种内存映射文件的方法,即将一个文件映射到进程的地址空间,实现文件磁盘地址和一段进程虚拟地址的映射,下面来看看详细内容,需要的朋友可以参考一下
    2021-11-11
  • Java Collections集合继承结构图_动力节点Java学院整理

    Java Collections集合继承结构图_动力节点Java学院整理

    这篇文章主要介绍了Java Collections集合继承结构图_动力节点Java学院整理,需要的朋友可以参考下
    2017-04-04
  • Java 读取文件方法大全

    Java 读取文件方法大全

    这篇文章主要介绍了Java 读取文件方法大全,需要的朋友可以参考下
    2014-11-11
  • spring boot定时任务接收邮件并且存储附件的方法讲解

    spring boot定时任务接收邮件并且存储附件的方法讲解

    今天小编就为大家分享一篇关于spring boot定时任务接收邮件并且存储附件的方法讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • 3行代码快速实现Spring Boot Oauth2服务功能

    3行代码快速实现Spring Boot Oauth2服务功能

    oauthserver是一个基于Spring Boot Oauth2的完整的独立的Oauth服务器。仅仅需要创建相关数据表,修改数据库的连接信息,你就可以得到一个Oauth服务器。这篇文章给大家介绍3行代码快速实现Spring Boot Oauth2服务功能,需要的朋友参考下吧
    2018-04-04

最新评论