Redis——用户签到BitMap,UV统计

news/2025/2/25 21:20:46

目录

BitMap

使用场景

1. 用户签到系统

2. 用户行为标记

3. 布隆过滤器(Bloom Filter)

BitMap介绍 

Redis中的使用 

Redis功能示例

添加: 

获取:

批量获取:

 java中实现

 统计本月连续签到次数

 UV统计

 UV 统计的核心需求

使用 HyperLogLog

UV 统计的常见场景

场景 1:每日 UV 统计

场景 2:月度 UV 统计


BitMap

使用场景

在开发中,Bitmap 经常被用于以下场景:

1. 用户签到系统

场景描述
用户每天签到一次,系统需要记录用户每月的签到情况,并支持快速查询连续签到天数、总签到天数等。

实现方式

  • 使用一个 Bitmap,每一位代表一天(1表示签到,0表示未签到)。

  • 例如,用户ID为1的用户在2023年10月的签到记录可以用一个31位的 Bitmap 表示。

优点

  • 存储空间极小:一个月的签到记录只需要4字节(32位)。

  • 查询效率高:可以通过位运算快速计算连续签到天数、总签到天数等。


2. 用户行为标记

场景描述
系统需要标记用户是否完成了某些行为(例如是否阅读了某篇文章、是否参与了某个活动等)。

实现方式

  • 使用一个 Bitmap,每一位代表一个行为(1表示完成,0表示未完成)。

  • 例如,用户ID为1的用户完成了行为A、B、D,可以用 0b1101 表示。

优点

  • 节省存储空间:一个用户的所有行为标记可以用一个整数表示。

  • 支持快速查询:通过位运算可以快速判断用户是否完成了某个行为。


3. 布隆过滤器(Bloom Filter)

场景描述
布隆过滤器是一种概率型数据结构,用于快速判断某个元素是否存在于一个集合中(可能存在误判,但不会漏判)。

实现方式

  • 使用一个 Bitmap 作为布隆过滤器的底层存储结构。

  • 通过多个哈希函数将元素映射到 Bitmap 的不同位置,并将这些位置标记为1。

优点

  • 空间效率极高:适合海量数据的去重和查询。

  • 查询速度快:时间复杂度为 O(1)。

BitMap介绍 

 

 如果是使用表来储存,需要耗费大量的内存,数据库压力山大

因此我们换一种方式来存储,一个月最多有31天,因此,如果某一天签到了,那么对应的位为1,没有则为0。这种方式只需要31bit,也就是8字节,大大节省了空间。

Redis中的使用 

Redis功能示例
添加: 

储存为11100111

获取:

批量获取:

u2中的u表示储存的为无符号,2表示只截取两个比特位,截取结果为11,转化为十进制就是3

 java中实现

    public Result sign() {
        // 获取登录用户
        Long userId = UserHolder.getUser().getId();
        // 获取日期
        LocalDateTime now = LocalDateTime.now();
        // 拼接用户和日期变成key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
//        String key = "sign:"+userId+keySuffix;
        String key = USER_SIGN_KEY+userId+keySuffix;
        // 获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();
        // 写入Redis setbit key offset 1
        stringRedisTemplate.opsForValue().setBit(key,dayOfMonth-1,true); // 注意这里需要减一因为在储存中字节是从0开始的
        return Result.ok();
    }

 统计本月连续签到次数

    @Override
    public Result signCount() {
        // 获取登录用户
        Long userId = UserHolder.getUser().getId();
        // 获取日期
        LocalDateTime now = LocalDateTime.now();
        // 拼接用户和日期变成key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
//        String key = "sign:"+userId+keySuffix;
        String key = USER_SIGN_KEY+userId+keySuffix;
        // 获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();

        //获取本月为止的所有的签到记录,返回的是一个十进制的数字 BITFIELD key GET udayOfMonth 0
        List<Long> result = stringRedisTemplate.opsForValue().bitField(key,
                BitFieldSubCommands.create()
                        .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)) // 子命令
                        .valueAt(0)
        );

        if(result == null || result.isEmpty()){
            return Result.ok(0);
        }
        //  为什么需要 get(0)?get(0) 是从 List<Long> 中获取第一个元素。
        //  stringRedisTemplate.opsForValue().bitField(...) 返回的是一个 List<Long>,
        //  即使你只请求了一个值,它也会以列表的形式返回。
        //  因此,result.get(0) 获取的是这个列表中的第一个元素,也就是你请求的签到记录的值。
        Long num = result.get(0);
        if(num == null || num == 0){
            return  Result.ok(0);
        }

        // 遍历循环
        int cnt = 0;
        while(cnt < dayOfMonth){
            if ((num & 1) == 0) {
                break;
            }
            cnt++;
            // 把数字右移一位,抛弃最后一个bit位,继续下一个bit位
            num >>>=1;
        }
        return Result.ok(cnt);

    }

 UV统计

在 Redis 中,UV(Unique Visitor)统计 是指统计某个时间段内访问某个资源的独立用户数量。UV 统计是许多应用场景(如网站访问量统计、广告点击统计等)中的核心需求。Redis 提供了多种数据结构和方法来实现高效的 UV 统计。

以下是 Redis 中 UV 统计的相关知识点介绍:

 UV 统计的核心需求

  • 去重:同一个用户在同一时间段内的多次访问只算作一次。

  • 高效存储:需要支持海量用户的统计。

  • 快速查询:能够快速获取某个时间段内的 UV 数据。

使用 HyperLogLog

原理

  • HyperLogLog 是一种概率算法,用于估算大量数据的基数(去重后的数量)。

  • 它通过极小的存储空间(每个 HyperLogLog 键只需要 12 KB)来统计 UV。

命令

  • PFADD key user_id:将用户 ID 添加到 HyperLogLog 中。

  • PFCOUNT key:获取 UV 的估算值。

优点

  • 存储空间极小,适合海量用户的 UV 统计。

  • 查询速度快。

缺点

  • 结果是估算值,存在一定的误差(标准误差约为 0.81%)

    UV 统计的常见场景

    场景 1:每日 UV 统计

    需求

    • 统计每天的独立访问用户数。

    实现

    • 使用 HyperLogLog,每天创建一个新的键(例如 uv:2023-10-01),将当天的用户 ID 添加到键中。

    • 每天结束时,使用 PFCOUNT 获取当天的 UV 值。

    场景 2:月度 UV 统计

    需求

    • 统计每月的独立访问用户数。

    实现

    • 使用 HyperLogLog,将整个月的用户 ID 添加到同一个键中(例如 uv:2023-10)。

    • 每月结束时,使用 PFCOUNT 获取当月的 UV 值。


    http://www.niftyadmin.cn/n/5865952.html

    相关文章

    架构师论文《论湖仓一体架构及其应用》

    软考论文-系统架构设计师 摘要 作为某省级商业银行数据中台建设项目技术负责人&#xff0c;我在2020年主导完成了从传统数据仓库向湖仓一体架构的转型。针对日益增长的支付流水、用户行为埋点及信贷审核影像文件等多模态数据处理需求&#xff0c;原有系统存在存储成本激增、实…

    部署若依微服务遇到的坑

    一、用Windows部署nacos 1、启动失败&#xff0c;因为nacos默认开启为器群模式。单体需要加上图下代码 2、nacos配置内置MySQL时需要执行config文件夹下的SQL文件 3、springboot启动报错 java.nio.charset.MalformedInputException: Input length 1或Input length 2-CSDN博…

    C#中开发OCR应用时,以下是一些推荐的开源库和工具

    在C#中开发OCR应用时&#xff0c;以下是一些推荐的开源库和工具&#xff0c;以及它们的简要使用指南&#xff1a; 1. Tesseract OCR (最主流推荐) 简介: Google 开源的OCR引擎&#xff0c;支持多语言&#xff0c;历史悠久且社区活跃。NuGet包: Tesseract (纯C#封装) 优点: 完全…

    【前端】Axios AJAX Fetch

    不定期更新&#xff0c;建议关注收藏点赞。 目录 AxiosAJAX Axios axios 是一个基于 Promise 的 JavaScript HTTP 客户端&#xff0c;用于浏览器和 Node.js 中发送 HTTP 请求。它提供了一个简单的 API 来发起请求&#xff0c;并处理请求的结果。axios 主要用于与服务器进行数据…

    一周学会Flask3 Python Web开发-Jinja2模板访问对象

    锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 如果渲染模板传的是对象&#xff0c;如果如何来访问呢&#xff1f; 我们看下下面示例&#xff1a; 定义一个Student类 cla…

    开源基准测试模拟器:BlueROV2 水下机器人的控制

    拜读An Open-Source Benchmark Simulator: Control of a BlueROV2 Underwater Robot 非常感谢Esben Uth的帮助。 本文介绍了在 Simulink™ 中实现的常用且低成本的遥控潜水器 &#xff08;ROV&#xff09; BlueROV2 的仿真模型环境&#xff0c;该环境已针对水下航行器的基准控…

    深入理解Redis:从线程模型到应用场景的全面解析

    在当今快速发展的技术领域&#xff0c;高效的内存数据存储解决方案对于提升应用性能至关重要。Redis 作为一款开源的内存数据结构存储系统&#xff0c;不仅能够用作数据库、缓存&#xff0c;还能作为消息中间件&#xff0c;在实现高速数据处理和复杂数据结构操作方面提供了强大…

    【论文阅读】distilling cognitive backdoor patterns within an image

    本文是输入级别的后门检测 认知蒸馏&#xff08;Cognitive Distillation, CD&#xff09;用于提取和检测图像中的后门模式。 其核心思想是从输入图像中提取出对模型预测起决定性作用的“最小本质”。CD通过优化输入掩码&#xff0c;从输入图像中提取出一个小的模式&#xff0…