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

目录

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 值。

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

    如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

    相关文章

    【数据结构】(12) 反射、枚举、lambda 表达式

    一、反射 1、反射机制定义及作用 反射是允许程序在运行时检查和操作类、方法、属性等的机制&#xff0c;能够动态地获取信息、调用方法等。换句话说&#xff0c;在编写程序时&#xff0c;不需要知道要操作的类的具体信息&#xff0c;而是在程序运行时获取和使用。 2、反射机制…

    【初探数据结构】时间复杂度和空间复杂度

    &#x1f4ac; 欢迎讨论&#xff1a;在阅读过程中有任何疑问&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;如果你觉得这篇文章对你有帮助&#xff0c;记得点赞、收藏&#xff0c;并分享给更多对数据结构感…

    基于 MySQL 递归 CTE 实现表,父级id与子级id拼接

    1、函数 xr_test.tb_content替换成自己的表 CREATE DEFINERroot% FUNCTION get_related_ids(start_id BIGINT) RETURNS varchar(1000) CHARSET utf8mb4 COLLATE utf8mb4_general_ciDETERMINISTIC BEGINDECLARE result_ids VARCHAR(1000);-- 使用递归 CTE 查找所有相关的 idWI…

    Redission可重试、超时续约的实现原理(源码分析)

    Redission遇到其他进程已经占用资源的时候会在指定时间waitTime内进行重试。实现过程如下&#xff1a; 执行获取锁的lua脚本时&#xff0c;会返回一个值&#xff0c; 如果获取锁成功&#xff0c;返回nil&#xff0c;也就是java里的null 如果获取锁失败&#xff0c;用语句“PT…

    ue----git局域网内部署裸仓库,别的机器进行访问

    最近由于经常迁移项目到另一台机器上进行部署更新一点就要整个迁移 弄得麻烦了 就在网上学了一下这个方式 首先我们在想要建立裸仓库的电脑上找到一个文件夹放置我们的裸仓库 在此点击鼠标右键选择 open git bash here 输入命令 创裸仓库 git init --bare gitTestName.git…

    输入搜索、分组展示选项、下拉选取,el-select 实现:即输入关键字检索,返回分组选项,选取跳转到相应内容页 —— VUE 项目-全局模糊检索

    后端数据代码写于下一篇&#xff1a;输入搜索、分组展示选项、下拉选取&#xff0c;全局跳转页&#xff0c;el-select 实现 —— 后端数据处理代码&#xff0c;抛砖引玉展思路 【效果图】&#xff1a;分组展示选项 >【提供界面操作体验】 【录制效果视频展示】&#xff1a…

    【UCB CS 61B SP24】Lecture 11 - Inheritance 4: Iterators, Object Methods学习笔记

    本文内容为集合&#xff08;Set&#xff09;的介绍与使用&#xff0c;并通过数组手动实现集合&#xff0c;接着介绍了迭代器&#xff0c;使用迭代器我们能够更方便地遍历集合中的元素。 1. Set 1.1 Set介绍与Java实现类的使用 集合&#xff08;Set&#xff09;是一种常见的数…

    玩机日记 12 fnOS使用lucky反代https转发到外网提供服务

    目录 1、安装lucky 2、更新lucky 3、上传ssl证书 4、设置安全入口&#xff0c;替换fnOS的应用url 5、添加https反代 这一篇主要是解决一下飞牛反代https的问题。可以先看玩机日记 12.5 在PVE Windows11上部署本地AI模型&#xff0c;使用群晖反代https转发到外网提供服务&a…

    神经网络八股(3)

    1.什么是梯度消失和梯度爆炸 梯度消失是指梯度在反向传播的过程中逐渐变小&#xff0c;最终趋近于零&#xff0c;这会导致靠前层的神经网络层权重参数更新缓慢&#xff0c;甚至不更新&#xff0c;学习不到有用的特征。 梯度爆炸是指梯度在方向传播过程中逐渐变大&#xff0c;…

    【ARM】MDK如何生成指定大小的bin文件,并指定空区域的填充数据

    1、 文档目标 解决MDK如何生成指定大小的bin文件&#xff0c;并指定空区域的填充数据 2、 问题场景 客户有这样的需求&#xff0c;客户本身的工程编译生成bin文件后&#xff0c;bin文件大小为200k。整体芯片的内存有512k。客户想要最终生成的bin文件可以达到512k的一个情况&a…

    Linux-----进程间通信

    一、按通信范围分类 同一主机进程通信 传统IPC方式&#xff1a; 管道&#xff08;无名管道、有名管道&#xff09;信号&#xff08;Signal&#xff09; System V IPC&#xff1a; 共享内存&#xff08;效率最高&#xff09;消息队列信号量 POSIX IPC&#xff08;较新标准&#…

    Part 3 第十二章 单元测试 Unit Testing

    概述 第十二章围绕单元测试展开&#xff0c;阐述了单元测试的实践与重要性&#xff0c;通过对比其他测试类型&#xff0c;突出其特点&#xff0c;还介绍了单元测试的最佳实践、避免的反模式以及与测试替身相关的内容&#xff0c;为编写高质量单元测试提供指导。 章节概要 1…

    Windows10配置C++版本的Kafka,并进行发布和订阅测试

    配置的环境为&#xff1a;Release x64下的环境 完整项目&#xff1a;https://gitee.com/jiajingong/kafka-publisher 1、首先下载相应的库文件&#xff08;.lib&#xff0c;.dll&#xff09; 参考链接&#xff1a; GitHub - eStreamSoftware/delphi-kafka GitHub - cloade…

    Deepseek引爆AI热潮 防静电地板如何守护数据中心安全

    近期&#xff0c;Deepseek的爆火将人工智能推向了新的高度&#xff0c;也引发了人们对AI背后基础设施的关注。作为AI运行的“大脑”&#xff0c;数据中心承载着海量数据的存储、处理和传输&#xff0c;其安全稳定运行至关重要。而在这背后&#xff0c;防静电地板扮演着不可或缺…

    Spring框架基本使用(Maven详解)

    前言&#xff1a; 当我们创建项目的时候&#xff0c;第一步少不了搭建环境的相关准备工作。 那么如果想让我们的项目做起来方便快捷&#xff0c;应该引入更多的管理工具&#xff0c;帮我们管理。 Maven的出现帮我们大大解决了管理的难题&#xff01;&#xff01; Maven&#xf…

    QSplashScreen --软件启动前的交互

    目录 QSplashScreen 类介绍 使用方式 项目中使用 THPrinterSplashScreen头文件 THPrinterSplashScreen实现代码 使用代码 使用效果 QSplashScreen 类介绍 QSplashScreen 是 Qt 中的一个类&#xff0c;用于显示启动画面。它通常在应用程序启动时显示&#xff0c;以向用户显…

    【Vscode 使用】集合1

    一、使用make工具管理工程 windows下&#xff0c;下载mingw64&#xff0c;配置好mingw64\bin 为 Win10系统全局变量后。 在mingw64/bin目录下找到mingw32-make.exe工具。复制一份改名为&#xff1a;make.exe&#xff0c;没错&#xff0c;就是那么简单&#xff0c;mingw64自带m…

    PHP-create_function

    [题目信息]&#xff1a; 题目名称题目难度PHP-create_function2 [题目考点]&#xff1a; create_function ( string args , string args , string code )[Flag格式]: SangFor{wWx5dEGHHhDUwmST4bpXwfjSzq43I6cz}[环境部署]&#xff1a; docker-compose.yml文件或者docker …

    golang内存泄漏

    golang也用了好几年了&#xff0c;趁着有空 整理归纳下&#xff0c;以后忘了好看下 一般认为 Go 10次内存泄漏&#xff0c;8次goroutine泄漏&#xff0c;1次是真正内存泄漏&#xff0c;还有1次是cgo导致的内存泄漏 1:环境 go1.20 win10 2:goroutine泄漏 单个Goroutine占用内存&…

    Python Seaborn库使用指南:从入门到精通

    1. 引言 Seaborn 是基于 Matplotlib 的高级数据可视化库,专为统计图表设计。它提供了更简洁的 API 和更美观的默认样式,能够轻松生成复杂的统计图表。Seaborn 在数据分析、机器学习和科学计算领域中被广泛使用。 本文将详细介绍 Seaborn 的基本概念、常用功能以及高级用法,…