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

news2025/2/25 22:45:53

目录

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.coloradmin.cn/o/2306050.html

    如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

    相关文章

    pycharm技巧--鼠标滚轮放大或缩小 Pycharm 字体大小

    1、鼠标滚轮调整字体 设置 Ctrl 鼠标滚轮调整字体大小 备注&#xff1a; 第一个是活动窗口&#xff0c;即缩放当前窗口 第二个是所有编辑器窗口&#xff0c;即缩放所有窗口的字体 2、插件 汉化包&#xff1a; Chinese Simplified 包

    数字信任的底层逻辑:密码学核心技术与现实应用

    安全和密码学 --The Missing Semester of Your CS Education 目录 熵与密码强度密码散列函数密钥体系 3.1 对称加密 3.2 非对称加密信任模型对比典型应用案例安全实践建议扩展练习杂项 密码学是构建数字信任的基石。 本文浅析密码学在现实工具中的应用&#xff0c;涵盖 1&…

    全面理解-深拷贝与浅拷贝

    在 C 中&#xff0c;深拷贝&#xff08;Deep Copy&#xff09; 和 浅拷贝&#xff08;Shallow Copy&#xff09; 是两种完全不同的对象拷贝策略&#xff0c;主要区别在于对指针和动态分配资源的处理方式。正确理解二者的区别是避免内存泄漏、悬空指针和程序崩溃的关键。 一、核…

    Redis分布式锁故障处理:当Redis不可用时的应对策略

    Redis分布式锁故障处理&#xff1a;当Redis不可用时的应对策略 在分布式系统中&#xff0c;Redis因其高性能和丰富的特性常被用于实现分布式锁。但当加锁过程中Redis服务不可用时&#xff0c;系统将面临严重挑战。本文将深入探讨这一问题&#xff0c;并提供多维度解决方案。 目…

    WordPress平台如何接入Deepseek,有效提升网站流量

    深夜改代码到崩溃&#xff1f;《2024全球CMS生态报告》揭露&#xff1a;78%的WordPress站长因API对接复杂&#xff0c;错失AI内容红利。本文实测「零代码接入Deepseek」的保姆级方案&#xff0c;配合147SEO的智能发布系统&#xff0c;让你用3个步骤实现日均50篇EEAT合规内容自动…

    ROS ur10机械臂添加140夹爪全流程记录

    ROS ur10机械臂添加140夹爪 系统版本&#xff1a;Ubuntu20.04 Ros版本&#xff1a;noetic Moveit版本&#xff1a;moveit-noetic 参考博客&#xff1a; ur3robotiq ft sensorrobotiq 2f 140配置rviz仿真环境_有末端力传感器的仿真环境-CSDN博客 UR5机械臂仿真实例&#xf…

    FFMPEG编码容错处理解决办法之途径----升级库文件

    在qt开发环境下接收网络数据&#xff0c;调用ffmpeg解码播放视频&#xff0c;出现闪屏现象&#xff0c;具体现象可以使用操作系统自带的ffplay播放器播放原始视频流可复现&#xff1b;而使用操作系统自带的mpv播放器播放视频则不会出现闪屏&#xff1b;闪屏时会报Could not fin…

    uniapp h5端和app端 使用 turn.js

    前提:添加页后,添加页与当前页会重叠在一起,不知道为什么,没有找到解决办法 1.h5端 <template><view class"container"><view id"flipbook"><view class"page page1">Page 1</view><view class"page pag…

    【入门音视频】音视频基础知识

    &#x1f308;前言&#x1f308; 这个系列在我学习过程中&#xff0c;对音视频知识归纳总结的笔记。因为音视频相关讲解非常稀少&#xff0c;所以我希望通过这个音视频系列&#xff0c;跟大家一起学习音视频&#xff0c;希望减少初学者在学习上的压力。同时希望也欢迎指出文章的…

    数据结构☞泛型

    一.基础定义与应用方向 1.定义&#xff1a; 一般的类和方法&#xff0c;只能使用具体的类型 : 要么是基本类型&#xff0c;要么是自定义的类。如果要编写可以 应用于多种类型 的代码&#xff0c;这种刻板的限制对代码的束缚就会很大。----- 来源《 Java 编程思想》对泛型的介…

    hot100-二叉树

    二叉树 二叉树递归 相当于这个的顺序来回调换 class Solution {private List<Integer> res new ArrayList<>();public List<Integer> inorderTraversal(TreeNode root) {if(root null)return res;inorderTraversal(root.left);res.add(root.val);inorde…

    嵌入式项目:STM32刷卡指纹智能门禁系统

    本文详细介绍基于STM32的刷卡指纹智能门禁系统。 获取资料/指导答疑/技术交流/选题/帮助&#xff0c;请点链接&#xff1a; https://gitee.com/zengzhaorong/share_contact/blob/master/stm32.txt 1 系统功能 1.1 功能概述 本系统由STM32硬件端&#xff08;下位机&#xff09;…

    短剧小程序系统源码

    短剧小程序系统源码 今天我要向大家介绍的是最新作品——短剧小程序系统源码。这不仅仅是一款简单的播放工具&#xff0c;它背后蕴含的强大功能能够帮助你的短剧业务实现质的飞跃&#xff01; 为什么说这款源码很厉害&#xff1f; 首先&#xff0c;在当今竞争激烈的市场环境…

    C#中级教程(2)——走进 C# 面向对象编程:从基础到进阶的深度探索

    一、为什么选择面向对象编程 在软件开发的演进过程中&#xff0c;随着程序规模和复杂度的不断增加&#xff0c;传统的编程方式逐渐暴露出局限性。面向对象编程应运而生&#xff0c;它就像是一位智慧的组织者&#xff0c;将程序中的功能进行模块化划分。每个模块各司其职&#x…

    基于SpringBoot的“流浪动物救助系统”的设计与实现(源码+数据库+文档+PPT)

    基于SpringBoot的“流浪动物救助系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 局部E-R图 系统首页界面 系统…

    基于WebRTC与AI大模型接入EasyRTC:打造轻量级、高实时、强互动的嵌入式音视频解决方案

    随着物联网和嵌入式技术的快速发展&#xff0c;嵌入式设备对实时音视频通信的需求日益增长。然而&#xff0c;传统的音视频解决方案往往存在体积庞大、实时性差、互动体验不佳等问题&#xff0c;难以满足嵌入式设备的资源限制和应用场景需求。 针对以上痛点&#xff0c;本文将介…

    Windows - 通过ssh打开带有图形界面的程序 - 一种通过计划任务的曲折实现方式

    Windows(奇思妙想) - 通过ssh打开带有图形界面的程序 - 一种通过计划任务的曲折实现方式 前言 Windows启用OpenSSH客户端后就可以通过SSH的方式访问Windows了。但是通过SSH启动的程序&#xff1a; 无法显示图形界面会随着SSH进程的结束而结束 于是想到了一种通过执行“计划…

    RT-Thread+STM32L475VET6——USB鼠标模拟

    文章目录 前言一、板载资源二、具体步骤1.配置icm20608传感器2.打开CubeMX进行USB配置3. 配置USB3.1 打开USB驱动3.2 声明USB3.3 剪切stm32xxxx_hal_msp.c中的void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)和void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)函数至board.c3.…

    计算机毕业设计SpringBoot+Vue.js母婴商城(源码+LW文档+PPT+讲解+开题报告)

    温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

    Teigha(ODA<Open Design Alliance>_开放设计联盟)——cad c# 二次开发

    需将dll库文件与exe文件放同一路径下&#xff0c;运行exe即可执行。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Thread…