【Redis从头学-8】Redis中的ZSet数据类型实战场景之用户积分榜

news2025/1/13 13:27:10

🧑‍💻作者名称:DaenCode
🎤作者简介:啥技术都喜欢捣鼓捣鼓,喜欢分享技术、经验、生活。
😎人生感悟:尝尽人生百味,方知世间冷暖。
📖所属专栏:Redis从头学


在这里插入图片描述


文章目录

  • 🌟前言
  • 🌟ZSet数据类型分析
  • 🌟ZSet类型实战应用场景
    • 用户积分榜功能
      • 代码示例
      • 数据测试
      • 运行结果
  • 🌟写在最后

🌟前言

之前的篇章对Redis的String、List、Hash、Set数据类型已经做出了具体分析,并举例说明了其具体的实战场景。本文就结合Zset数据类型结构的特性,一起探讨其实战中的应用场景,并以积分榜功能为例来展示Zset数据类型的特点。

🌟ZSet数据类型分析

Redis中的ZSet(有序集合)数据类型是一种有序且不重复的集合,它在Set的基础上增加了一个分数(score)字段,用于对集合中的元素进行排序。下面对Redis ZSet数据类型进行一些分析:

  1. 有序性:ZSet中的元素按照其分数进行排序,使得元素在集合中有序存储。每个元素都有一个唯一的分数,可用于根据指定顺序进行范围查询或排序。
  2. 元素的唯一性:和Set一样,ZSet保证其中的元素都是唯一的,不会存在重复的元素。
  3. 高效的添加、删除和更新操作:ZSet提供了O(log N)时间复杂度的添加、删除和更新元素的操作。其中N为ZSet中元素的数量。这归功于Redis内部使用了跳表(Skip List)和哈希表两种结构实现ZSet。
  4. 支持范围查询和排名操作:ZSet支持根据分数范围进行查询,并可以按照分数大小对元素进行排名。通过排名操作,可以获取元素的排名以及根据排名返回一定范围的元素。

🌟ZSet类型实战应用场景

ZSet常用于需要根据分数进行排序的场景,例如排行榜、计分系统、有序任务队列等。它能够快速获取按照分数排序的元素,并且支持动态更新分数。

总而言之,Redis的ZSet数据类型提供了有序、唯一且高效的集合操作。它在排行榜、计分系统以及需要有序处理任务队列等场景中非常有用。通过对元素进行分数的设置和操作,可以灵活地满足各种实时数据排序和查询的需求。

用户积分榜功能

代码示例

我们使用了Spring Data Redis提供的RedisTemplate来操作Redis的ZSet。通过@Resource注解将RedisTemplate注入到LeaderboardService类中。

在LeaderboardService中,我们定义很多的功能方法来实现用户积分榜的功能,如添加用户积分、增加用户积分、获取用户排名、获取用户积分、获取排名靠前的用户列表以及获取积分在指定范围内的用户列表。

@Component
public class LeaderboardService {

    private static final String LEADERBOARD_KEY = "leaderboard";

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 添加用户积分
     *
     * @param user  用户名
     * @param score 积分
     */
    public void addScore(String user, double score) {
        ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
        zSetOperations.add(LEADERBOARD_KEY, user, score);
    }

    /**
     * 增加用户积分
     *
     * @param user  用户名
     * @param score 积分增加量
     */
    public void incrementScore(String user, double score) {
        ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
        zSetOperations.incrementScore(LEADERBOARD_KEY, user, score);
    }

    /**
     * 获取用户排名(从高到低)
     *
     * @param user 用户名
     * @return 用户的排名,如果用户不存在,则返回null
     */
    public Long getUserRank(String user) {
        ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
        return zSetOperations.reverseRank(LEADERBOARD_KEY, user);
    }

    /**
     * 获取用户积分
     *
     * @param user 用户名
     * @return 用户的积分,如果用户不存在,则返回null
     */
    public Double getUserScore(String user) {
        ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
        return zSetOperations.score(LEADERBOARD_KEY, user);
    }

    /**
     * 获取排名靠前的用户列表
     *
     * @param count 列表数量
     * @return 排名靠前的用户列表
     */
    public Set<String> getTopUsers(int count) {
        ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
        Set<String> topUsers = zSetOperations.reverseRange(LEADERBOARD_KEY, 0, count - 1);
        return topUsers;
    }

    /**
     * 获取积分在指定范围内的用户列表
     *
     * @param minScore 最低积分
     * @param maxScore 最高积分
     * @return 积分在指定范围内的用户列表
     */
    public Set<String> getUsersInRange(double minScore, double maxScore) {
        ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
        Set<String> usersInRange = zSetOperations.rangeByScore(LEADERBOARD_KEY, minScore, maxScore);
        return usersInRange;
    }

    /**
     * 获取积分在指定范围内的用户列表,并返回用户及其对应的积分信息
     *
     * @param minScore 最低积分
     * @param maxScore 最高积分
     * @return 包含用户及其对应积分的用户列表
     */
    public Set<String> getUsersWithScoresInRange(double minScore, double maxScore) {
        ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
        Set<ZSetOperations.TypedTuple<String>> usersWithScoresInRange = zSetOperations
                .rangeByScoreWithScores(LEADERBOARD_KEY, minScore, maxScore);
        // 将TypedTuple转换为只包含用户的Set
        Set<String> usersSet = usersWithScoresInRange.stream()
                .map(ZSetOperations.TypedTuple::getValue)
                .collect(Collectors.toSet());
        return usersSet;
    }

}

数据测试

使用了 Spring Boot 框架来启动应用程序,并通过上下文获取 LeaderboardService 类的实例。然后,我们按照需求调用 LeaderboardService 类中的方法。

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        LeaderboardService leaderboardService = context.getBean(LeaderboardService.class);

        // 添加用户积分
        leaderboardService.addScore("User1", 100);
        leaderboardService.addScore("User2", 200);
        leaderboardService.addScore("User3", 300);
        leaderboardService.addScore("User4", 400);
        leaderboardService.addScore("User5", 500);

        // 增加用户积分
        leaderboardService.incrementScore("User1", 50);
        leaderboardService.incrementScore("User3", 150);

        // 获取用户排名
        Long user1Rank = leaderboardService.getUserRank("User1");
        System.out.println("User1 Rank: " + user1Rank);

        // 获取用户积分
        Double user3Score = leaderboardService.getUserScore("User3");
        System.out.println("User3 Score: " + user3Score);

        // 获取排名靠前的用户列表
        Set<String> topUsers = leaderboardService.getTopUsers(3);
        System.out.println("Top Users: " + topUsers);

        // 获取积分在指定范围内的用户列表
        Set<String> usersInRange = leaderboardService.getUsersInRange(200, 400);
        System.out.println("Users in Range: " + usersInRange);

        // 获取积分在指定范围内的用户列表,并返回用户及其对应的积分信息
        Set<String> usersWithScoresInRange = leaderboardService.getUsersWithScoresInRange(200, 400);
        System.out.println("Users with Scores in Range: " + usersWithScoresInRange);
    }
}

运行结果

User1 Rank: 4
User3 Score: 450.0
Top Users: [User5, User4, User3]
Users in Range: [User4, User3, User2]
Users with Scores in Range: [User4, User3]

🌟写在最后

有关于Redis中的ZSet数据类型实战应用场景到此就结束了。功能演示代码的逻辑简单,目的是理解ZSet数据类型的应用,实际场景的逻辑根据具体需求而定。感谢大家的阅读,希望大家在评论区对此部分内容散发讨论或者有什么其他场景也可以在评论区提出。


请添加图片描述

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

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

相关文章

Day8.22 E. Unforgivable Curse (easyhard version)

文章目录 E1. Unforgivable Curse (easy version)E2. Unforgivable Curse (hard version) E1. Unforgivable Curse (easy version) Problem - 1800E1 - Codeforces 将s串转换成t串&#xff0c;每次能交换s串中下标绝对值差3或差4的字符 有点像bfs最小步数&#xff0c;但是字…

时序分解 | MATLAB实现基于SWD群体分解的信号分解分量可视化

时序分解 | MATLAB实现基于SWD群体分解的信号分解分量可视化 目录 时序分解 | MATLAB实现基于SWD群体分解的信号分解分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于SWD群体分解的分量可视化&#xff0c;基于群体分解的信号分解技术&#xff0c;MATLAB程序…

软考高级系统架构设计师(二)计算机操作系统

【原文链接】软考高级系统架构设计师&#xff08;二&#xff09;计算机操作系统 2.1 进程管理 2.1.1 操作系统的三个重要作用 管理计算机中运行的程序和分配各种软硬件资源为用户提供友善的人机界面为应用程序的开发和运行提供一个高效的平台 2.1.2 操作系统的四个特征 并…

Android开发基础知识总结(四)简单控件(下)

一.按钮触控 最常见的按钮button类继承自Textview类。 需要注意的是&#xff0c;在Button中显示的单词默认全部大写 ~ public void onClick(View v){s1et1.getText().toString();//有一些小bug&#xff0c;好像变量必须声明在Onclick方法内部才有效&#xff1f;&#xff1f;&am…

数据结构-----树的易错点

1.树的度和m叉树 •度为m的树&#xff08;度表示该结点有多少个孩子&#xff08;分支&#xff09;&#xff09; 任意结点的度<m(最多m个孩子) 至少又一个结点度m(有m个孩子) 一定是非空树&#xff0c;至少有m1个结点 •m叉树 任意结点的度<m(最多有m个孩子) 允许所…

Shell 编程快速入门 之 数学计算和函数基础

目录 1. 求两数之和 整数之和 浮点数之和 2. 计算1-100的和 for...in C风格for循环 while...do until...do while和until的区别 关系运算符 break与continue的区别 3. shell函数基础知识 函数定义 函数名 函数体 参数 返回值 return返回值的含义 return与…

2023大数据专业建设解决方案

打造产教融合的就业育人综合服务平台。 随着大数据产业链与技术链的逐步成熟&#xff0c;整体人工智能岗位将从原来的以算法人才为主&#xff0c;开始转向以应用型人才与数字 蓝领人才为主&#xff0c;形成金字塔型人才结构。应用型本科与职业院校的学生也将逐渐在人工智能领域…

Docker(一) 安装Docker

一、安装 安装前置条件 yum install -y yum-utils device-mapper-persistent-data lvm2 更换数据源 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 1、指定版本安装 yum list docker-ce --showduplicates | sort -r yum …

深入浅出理解卡尔曼滤波

重要说明&#xff1a;本文从网上资料整理而来&#xff0c;仅记录博主学习相关知识点的过程&#xff0c;侵删。 一、参考资料 我所理解的卡尔曼滤波 图说卡尔曼滤波&#xff0c;一份通俗易懂的教程 卡尔曼滤波简单分析 How a Kalman filter works, in pictures 说说卡尔曼滤波…

Java【手撕双指针】LeetCode 611. “有效三角形个数“, 图文详解思路分析 + 代码

文章目录 前言一、有效三角形个数1, 题目2, 思路分析1, 从左往右 or 从右往左?3, 代码展示 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统等 &#x1…

一文了解Gin对Cookie的支持z

1. 引言 本文将从Web应用程序处理请求时需要用户信息&#xff0c;同时HTTP又是无状态协议这个矛盾点出发。从该问题出发&#xff0c;简单描述了解决该问题的Token 机制&#xff0c;进而引出Cookie的实现方案。 基于此我们将详细描述Cookie的规范&#xff0c;然后详细描述具体…

UE4如何连接dmx---摇头矩阵灯具的创建

UE4如何连接dmx---摇头矩阵灯具的创建 开始创建库&#xff01; 然后我们开始创建多少个灯珠&#xff08;注意了&#xff1a;这是矩阵灯&#xff0c;是看灯珠的&#xff09; 那么这里我们创建6X6灯珠 下面设置灯珠的属性&#xff0c;灯珠有什么属性呢&#xff0c;只有颜色属性&…

高忆管理:沪指震荡跌0.24%,医药、酿酒等板块走低,数据要素概念逆市活跃

22日早盘&#xff0c;两市股指高开低走&#xff0c;沪指盘中冲高回落&#xff0c;创业板指走势疲弱&#xff1b;北向资金净卖出超40亿元。 到午间收盘&#xff0c;沪指跌0.24%报3085.48点&#xff0c;深成指跌0.73%&#xff0c;创业板指跌1.3%&#xff1b;两市合计成交4510亿元…

Python 自定义装饰器与上下文管理

1、定义装饰器实现计算函数运行时间 # 自定义装饰器 def compute_time(func):def compute(*args, **kwargs):st time.time()result func(*args, **kwargs)et time.time()print(消费时间 %.6f s % (et - st))return resultreturn compute# 使用 compute_time def work(work_i…

(2018,解释可视化)GAN 解剖:可视化和理解生成对抗网络

GAN dissection: Visualizing and understanding generative adversarial networks 公众号&#xff1a;EDPJ 目录 0. 摘要 1. 简介 2. 相关工作 3. 方法 3.1 通过解剖表征单元 3.2 使用干预措施衡量因果关系 4. 结果 4.1 跨数据集、层和模型的单位比较 4.2 诊断和改…

VMware 使用U盘进入PE系统,下划线光标闪烁

一、前言 vmware虚拟机各种原因崩溃&#xff0c;然后又没有快照&#xff0c;怎么办&#xff1f; 或者 密码忘记了无法开机&#xff0c;这时候就想到使用PE了。 二、分析 但是使用U盘进入PE的时候&#xff0c;遇到了各种问题&#xff1a; 加载U盘修改启动顺序启动后出现下划线…

DiscuzQ 二开教程(7)——二次开发版本部署文档

DiscuzQ 二开教程&#xff08;7&#xff09;——二次开发版本部署文档 源码&#xff1a;Discuz-Q-V3: 本仓库为Discuz-Q V3.0.211111 版本的二次开发版本&#xff0c;是将DiscuzQ官方仓库进行合并代码&#xff08;All in One&#xff09;整理后的仓库&#xff0c;使用更方便。…

【2023年11月第四版教材】《第6章-项目管理概论》(合集篇)

《第6章-项目管理概论》 1 章节内容2 项目基础3 项目经理的角色3.1 项目经理的影响力范围3.2 项目经理领导力风格 4 价值驱动的项目管理知识体系4.1 开发生命周期类型 5 五大过程组6 五个过程组和十大知识领域 1 章节内容 【本章分值预测】大部分为新增内容&#xff0c;预计选…

ARL资产侦察灯塔 指纹增强

项目&#xff1a;https://github.com/loecho-sec/ARL-Finger-ADD 下载项目后运行 python3 ARl-Finger-ADD.py https://你的vpsIP:5003/ admin password该项目中的finger.json可以自己找到其他的指纹完善&#xff0c;然后运行脚本添加指纹。

微信开发之一键修改群聊备注的技术实现

修改群备注 修改群名备注后&#xff0c;如看到群备注未更改&#xff0c;是手机缓存问题&#xff0c;可以连续点击进入其他群&#xff0c;在点击进入修改的群&#xff0c;再返回即可看到修改后的群备注名&#xff0c;群名称的备注仅自己可见 请求URL&#xff1a; http://域名地…