Redis实战 | 使用Redis 的有序集合(Sorted Set)实现排行榜功能,和Spring Boot集成

专栏集锦,大佬们可以收藏以备不时之需

Spring Cloud实战专栏:https://blog.csdn.net/superdangbo/category_9270827.html

Python 实战专栏:https://blog.csdn.net/superdangbo/category_9271194.html

Logback 详解专栏:https://blog.csdn.net/superdangbo/category_9271502.html

tensorflow专栏:https://blog.csdn.net/superdangbo/category_8691332.html

Redis专栏:https://blog.csdn.net/superdangbo/category_9950790.html

Spring Cloud实战:

Spring Cloud 实战 | 解密Feign底层原理,包含实战源码

Spring Cloud 实战 | 解密负载均衡Ribbon底层原理,包含实战源码

1024程序员节特辑文章:

1024程序员狂欢节特辑 | ELK+ 协同过滤算法构建个性化推荐引擎,智能实现“千人千面”

1024程序员节特辑 | 解密Spring Cloud Hystrix熔断提高系统的可用性和容错能力

1024程序员节特辑 | ELK+ 用户画像构建个性化推荐引擎,智能实现“千人千面”

1024程序员节特辑 | OKR VS KPI谁更合适?

1024程序员节特辑 | Spring Boot实战 之 MongoDB分片或复制集操作

Spring实战系列文章:

Spring实战 | Spring AOP核心秘笈之葵花宝典

Spring实战 | Spring IOC不能说的秘密?

国庆中秋特辑系列文章:

国庆中秋特辑(八)Spring Boot项目如何使用JPA

国庆中秋特辑(七)Java软件工程师常见20道编程面试题

国庆中秋特辑(六)大学生常见30道宝藏编程面试题

国庆中秋特辑(五)MySQL如何性能调优?下篇

国庆中秋特辑(四)MySQL如何性能调优?上篇

国庆中秋特辑(三)使用生成对抗网络(GAN)生成具有节日氛围的画作,深度学习框架 TensorFlow 和 Keras 来实现

国庆中秋特辑(二)浪漫祝福方式 使用生成对抗网络(GAN)生成具有节日氛围的画作

国庆中秋特辑(一)浪漫祝福方式 用循环神经网络(RNN)或长短时记忆网络(LSTM)生成祝福诗词

在这里插入图片描述

Redis 的有序集合(Sorted Set)是一个基于分数(score)排序的数据结构,它在 Redis 中非常重要,常用于实现排行榜、近似计数器等功能。

Redis 的有序集合(Sorted Set)是基于跳跃表(Skip List)实现的。跳跃表是一种高效的数据结构,其插入、删除和查找操作的平均时间复杂度都是 O(log n),相对于平衡树(如红黑树)的实现要简单很多。跳跃表的结构类似于链表,每个节点除了保存元素值外,还包含一个指针数组,分别指向对应层次的下一个节点。这种多级指针的设计,使得跳表可以跨越多个节点进行快速搜索,同时保证跳表结构的高效性和简洁性。
有序集合的底层数据结构由哈希(Hash)和跳跃表组成。在哈希中,存储了元素及其关联的评分(分数)。每个元素都有一个唯一的评分,用于确定其在跳跃表中的位置。当需要对有序集合进行操作时,Redis 首先通过哈希表找到元素及其评分,然后通过跳跃表进行相应的操作。
以下是 Redis 有序集合(Sorted Set)的一些核心操作及其对应的核心代码分析:

  1. 添加元素(ZADD):
    有序集合中的元素添加操作是通过哈希表和跳跃表协同完成的。首先,Redis 将元素值和评分存储在哈希表中。然后,根据评分在跳跃表中找到对应的位置,并将新元素插入到该位置。
  2. 获取元素(ZRANGE、ZREVRANGE):
    有序集合中的获取元素操作主要依赖于跳跃表。ZRANGE 操作从跳跃表的头部开始,按照给定的评分范围返回符合条件的元素。ZREVRANGE 操作则从跳跃表的尾部开始,按照给定的评分范围返回符合条件的元素。
  3. 删除元素(ZREM):
    删除元素操作首先通过哈希表找到对应元素,然后在跳跃表中删除该元素。Redis 只需要删除哈希表中的指向该元素的指针,跳跃表中的元素会自动上移。
  4. 更新元素评分(ZINCRBY):
    更新元素评分操作仅需修改哈希表中对应元素的评分,然后重新计算跳跃表中元素的位置。
  5. 获取有序集合长度(ZCARD):
    有序集合长度的操作直接查询哈希表中的键值对数量。
  6. 随机获取元素(ZRANDMEMBER):
    随机获取元素操作首先从哈希表中随机选择一个元素,然后在该元素所在的跳跃表区间内随机选择一个元素。
    通过以上操作,Redis 实现了高效有序集合(Sorted Set)的数据结构,提供了高性能的排序和范围查找功能。

2、实战

要使用 Spring Boot 和 Redis 实现排行榜功能,你可以遵循以下步骤:

  1. 引入依赖
    在你的 Spring Boot 项目的 pom.xml 文件中,添加以下依赖:
<dependencies>  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-data-redis</artifactId>  </dependency>  
</dependencies>  
  1. 配置 Redis
    在 application.properties 或 application.yml 文件中配置 Redis 连接信息:
# application.properties  
spring.redis.host=localhost  
spring.redis.port=6379  
# application.yml  
spring:  redis:  host: localhost  port: 6379  
  1. 创建 Redis 模板
    创建一个 RedisTemplate Bean:
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.data.redis.connection.RedisConnectionFactory;  
import org.springframework.data.redis.core.RedisTemplate;  
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;  
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration  
public class RedisConfig {@Bean  public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {  RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();  redisTemplate.setConnectionFactory(redisConnectionFactory);  redisTemplate.setKeySerializer(new StringRedisSerializer());  redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());  redisTemplate.setHashKeySerializer(new StringRedisSerializer());  redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());  return redisTemplate;  }  
}
  1. 创建排行榜实体类
    创建一个排行榜实体类,包含用户 ID、分数等信息:
import java.io.Serializable;
public class RankingEntity implements Serializable {private String userId;  private double score;// 构造方法、getter 和 setter  
}
  1. 实现 Redis 排行榜操作
    创建一个服务类,实现排行榜的相关操作,如添加分数、查询排名等:
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.data.redis.core.RedisTemplate;  
import org.springframework.data.redis.core.ValueOperations;  
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service  
public class RankingService {@Autowired  private RedisTemplate<String, Object> redisTemplate;private static final String RANKING_KEY = "ranking_list";/**  * 添加分数  * @param userId 用户 ID  * @param score 分数  */  public void addScore(String userId, double score) {  ValueOperations<String, RankingEntity> valueOperations = redisTemplate.opsForValue();  valueOperations.set(RANKING_KEY + ":" + userId, score, 60, TimeUnit.SECONDS);  }/**  * 查询排名  * @return 排名列表  */  public List<Object> getRankingList() {  List<Object> rankingList = redisTemplate.opsForList().range(RANKING_KEY, 0, -1);  return rankingList;  }/**  * 查询用户排名  * @param userId 用户 ID  * @return 用户排名  */  public Object getUserRanking(String userId) {  return redisTemplate.opsForValue().get(RANKING_KEY + ":" + userId);  }* @param userId 用户 ID  */  public void deleteUserScore(String userId) {  ValueOperations<String, RankingEntity> valueOperations = redisTemplate.opsForValue();  valueOperations.delete(RANKING_KEY + ":" + userId);  }/**  * 更新用户分数  * @param userId 用户 ID  * @param score 新的分数  */  public void updateUserScore(String userId, double score) {  ValueOperations<String, RankingEntity> valueOperations = redisTemplate.opsForValue();  valueOperations.set(RANKING_KEY + ":" + userId, score, 60, TimeUnit.SECONDS);  }/**  * 获取用户排名列表的长度  * @return 用户排名列表的长度  */  public long getUserRankingListSize() {  return redisTemplate.opsForList().size(RANKING_KEY);  }/**  * 在用户排名列表中插入用户分数  * @param userId 用户 ID  * @param score 分数  * @param index 插入位置,0 表示插入到列表头部,负数表示插入到列表尾部  */  public void insertUserScore(String userId, double score, long index) {  List<Object> rankingList = redisTemplate.opsForList().range(RANKING_KEY, 0, -1);  redisTemplate.opsForList().leftPush(RANKING_KEY, score, index);  }/**  * 在用户排名列表中删除用户分数  * @param userId 用户 ID  * @param index 删除位置,0 表示删除第一个元素,1 表示删除第二个元素,依此类推  */  public void deleteUserScore(String userId, long index) {  List<Object> rankingList = redisTemplate.opsForList().range(RANKING_KEY, 0, -1);  redisTemplate.opsForList().rightPop(RANKING_KEY, index);  }/**  * 获取用户排名列表中的最后一个元素  * @return 用户排名列表中的最后一个元素  */  public Object getLastUserScore() {  return redisTemplate.opsForList().rightPop(RANKING_KEY);  }/**  * 获取用户排名列表中的第一个元素  * @return 用户排名列表中的第一个元素  */  public Object getFirstUserScore() {  return redisTemplate.opsForList().leftPop(RANKING_KEY);  }/**  * 在用户排名列表中添加元素  * @param score 添加的分数  */  public void addUserScore(double score) {  redisTemplate.opsForList().rightPush(RANKING_KEY, score);  }/**  * 在用户排名列表中删除元素  * @param index 删除位置,0 表示删除第一个元素,1 表示删除第二个元素,依此类推  */  public void deleteUserScore(long index) {  redisTemplate.opsForList().rightPop(RANKING_KEY, index);  }/**  * 获取用户排名列表  * @return 用户排名列表  */  public List<Object> getUserRankingList() {  return redisTemplate.opsForList().range(RANKING_KEY, 0, -1);  }/**  * 设置用户排名列表的长度  * @param length 用户排名列表的新长度  */  public void setUserRankingListLength(long length) {  redisTemplate.opsForList().setSize(RANKING_KEY, length);  }/**  * 获取用户排名  *  * @param userId 用户 ID  * @return 用户排名,如果用户不存在,返回 -1  */  public int getUserRanking(String userId) {  List<Object> rankingList = getRankingList();  Object userScore = getUserRanking(userId);  if (userScore == null) {  return -1;  }int rank = 0;    for (Object score : rankingList) {    if (score.equals(userScore)) {    break;    }    rank++;    }    return rank;    }/**  * 获取用户排名列表中的指定位置的元素  *  * @param index 指定位置,从 0 开始  * @return 用户排名列表中的指定位置的元素  */  public Object getUserRankingListElement(long index) {  return redisTemplate.opsForList().range(RANKING_KEY, 0, -1).get(index);  }/**  * 获取用户排名列表中的用户分数  *  * @param userId 用户 ID  * @return 用户排名列表中的用户分数,如果用户不存在,返回 null  */  public Object getUserRanking(String userId) {  ValueOperations<String, RankingEntity> valueOperations = redisTemplate.opsForValue();  return valueOperations.get(RANKING_KEY + ":" + userId);  }/**  * 是否存在用户  *  * @param userId 用户 ID  * @return 是否存在用户  */  public boolean existsUser(String userId) {  ValueOperations<String, RankingEntity> valueOperations = redisTemplate.opsForValue();  return valueOperations.hasKey(RANKING_KEY + ":" + userId);  }/**  * 清除所有用户排名数据  */  public void clearAllUserRankingData() {  redisTemplate.delete(RANKING_KEY);  }  
}

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

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

相关文章

[架构之路-244]:目标系统 - 设计方法 - 软件工程 - 软件开发方法:结构化、面向对象、面向服务、面向组件的开发方法

目录 前言&#xff1a; 一、概述: 软件聚合的程度由简单到复杂 二、主要开发方法详见 2.1 结构化的开发方法 2.2 面对对象的开发方法 2.3 面向服务的开发方法 2.4 面向组件的开发方法 三、不同开发方法比较 3.1 结构化开发方法 3.2 面向对象(OOP)开发方法 3.3 面向服…

【计算机网络】网络层IP协议

文章目录 1. IP协议介绍2. IP报头3. IP的分片和组装4. IP地址网段划分特殊的IP地址子网、局域网、网段的区别IP地址的数量限制 5. 公网IP和私有IP6. NAT技术7. 路由Route 1. IP协议介绍 IP协议&#xff08;Internet Protocol&#xff09;是一种最常用的网络层协议&#xff0c;…

CSS 边框、轮廓线

一、CSS边框&#xff1a; CSS边框属性允许指定一个元素边框的样式和颜色。 1&#xff09;、边框样式&#xff1a;border-style属性用来定义边框的样式&#xff0c;border-style值&#xff1a; 2&#xff09;、边框宽度&#xff1a;border-width属性用于指定边框宽度。指定变宽…

2023-11-07 C语言链接库编译命令

点击 <C 语言编程核心突破> 快速C语言入门 C语言链接库编译命令 前言一、引入库文件, 包括头文件和lib库二、简单示例总结 前言 要解决问题: 一般没有给新手的链接库编译命令学习资料, 然而, 不解决这个问题, 调用库就能折腾到劝退, 我近日回答一个问题, 很简单, 调用…

【 Docker: 数据卷挂载】

背景 Docker只提供了容器运行的必备依赖&#xff0c;但是一些编辑等操作的依赖是不支持的&#xff0c;如vi操作容器内部文件、将静态资源拷贝到容器内来等。 docker pull nginx docker run -d -p 81:80 --namemynginx -v D:/docker/nginx/www:/usr/share/nginx/www -v D:/dock…

Angular 中的数据交互GET POST

1 Angular get 请求数据 Angular5.x 以后 get、post 和和服务器交互使用的是 HttpClientModule 模块 在 app.module.ts 中引入 HttpClientModule 并注入 import {HttpClientModule} from angular/common/http imports: [ BrowserModule, HttpClientModule ]在用到的地方引入…

柯桥英语培训,商务英语学习,常用口语

欢迎各位小伙伴来到 ——“每个单词我都认识&#xff0c;但我又不认识整个短语”的时候啦&#xff01; “dog”是“狗” “breakfast”是早餐 那“a dogs breakfast”是“狗的早餐”&#xff1f; 狗听了都摇头。 a dogs breakfast是一句英文俚语&#xff0c;指的是无序、混…

要做CMMI认证?什么是CMMI资质认证?

CMMI官方为美国CMMI Institute。CMMI资质主要包括三种&#xff1a;研发模型CMMI for Development资质&#xff0c;服务模型CMMI for Serivce资质&#xff0c;采购模型CMMI for Acquisition资质。在所有已过级企业中有99.5%以上的企业为研发模型CMMI for Development资质&#x…

Evaluating Large Language Models: A Comprehensive Survey

本文是LLM系列文章&#xff0c;针对《Evaluating Large Language Models: A Comprehensive Survey》的翻译。 评估大型语言模型&#xff1a;一项综合调查 摘要1 引言2 分类和路线图3 知识和能力评估4 对齐评估5 安全评估6 专业LLM评估7 评估组织8 未来方向9 结论 摘要 大型语…

LeetCode | 面试题 02.02. 返回倒数第 k 个节点

LeetCode | 面试题 02.02. 返回倒数第 k 个节点 OJ链接 思路&#xff1a;定义两个快慢指针&#xff0c;让快指针先提前走k个节点&#xff0c;然后再让慢结点和快结点一起走&#xff0c;当快指针 NULL时&#xff0c;慢指针就是倒数第k个节点 代码如下&#xff1a; int kthT…

java list set map日子记录

List集合 概念 是一个容器,作用为存放多个数据,通常用来替代数组 特点 只能存放引用类型 所有集合都来自于java.util包 List , Set , Map都是接口 List的存储特点 有序,有下标,元素可以重复 List的常用实现类 ArrayList (常用) JDK1.2 底层数组实现 查询快,增删慢 线程不…

计算机毕业设计java+springboot+vue的旅游攻略平台

项目介绍 本系统结合计算机系统的结构、概念、模型、原理、方法&#xff0c;在计算机各种优势的情况下&#xff0c;采用JAVA语言&#xff0c;结合SpringBoot框架与Vue框架以及MYSQL数据库设计并实现的。员工管理系统主要包括个人中心、用户管理、攻略管理、审核信息管理、积分…

STM32Cube +VSCode开发环境搭建

STM32Cube VSCode开发环境搭建 0.前言一、各种方式对比1.STM32CubeMX CLion2.STM32CubeIDE VSCode STM32 VSCode Extension3.VSCode EIDE插件 二、STM32CubeIDE VSCode STM32 VSCode Extension环境搭建1.需要安装的软件2.相关配置3.编译测试 三、总结 0.前言 工欲善其事&…

解决:openpyxl.utils.exceptions.IllegalCharacterError

使用python写excel遇到非法字符&#xff0c;本来用的是openpyxl发现有报错&#xff0c;查了一下xlsxwriter可以自动处理非法字符&#xff0c;写起来更方便。 注意使用前安装xlsxwriter: pip install xlsxwriterimport pandas as pddef write_to_xlsx(data, filename):# 表头he…

最新Next14 路由处理器 Route Handlers

四、使用Next路由处理程序 Next.js Route Handlers I. Next中路由处理程序是什么 ​ 路由处理程序是在用户访问站点路由时执行的功能。它们负责处理对定义的URL或路由的传入HTTP请求&#xff0c;以生成所需的数据。从本质上讲&#xff0c;当用户访问Next.js应用程序中的特定页…

vim手册(vim cheatsheet)

vim手册&#xff08;vim cheatsheet&#xff09; 1. 命令模式 1). 移动光标 在命令模式下&#xff0c;可以使用以下命令来移动光标&#xff1a; - h&#xff1a;向左移动一个字符。 - j&#xff1a;向下移动一行。 - k&#xff1a;向上移动一行。 - l&#xff1a;向右移动一个…

Docker 从构建开始导出一个镜像

docker build docker build命令用于从Dockerfile创建一个镜像。它的基本格式如下&#xff1a; docker build [OPTIONS] PATH | URL | -这里的PATH是Dockerfile所在的路径&#xff0c;URL是一个Git仓库地址&#xff0c;-表示从标准输入读取Dockerfile。 docker build命令的一…

chatglm3-6b部署及微调

chatglm3-6b部署及微调 modelscope: https://modelscope.cn/models/ZhipuAI/chatglm3-6b/filesgithub: https://github.com/THUDM/ChatGLM3镜像: ubuntu20.04-cuda11.8.0-py38-torch2.0.1-tf2.13.0-1.9.4v100 16G现存 单卡 安装 软件依赖 pip install --upgrade pippip ins…

使用IDEA让文本对比不在变的困难

文章目录 前言操作1、IDEA与电脑磁盘任意文件的比较2、项目内部的文件比较3、剪切板比较4、IDEA本地历史比较5、IDEA版本历史对比 前言 在日常实际开发当中我们常常会对一些代码或内容进行比对查看是否有差异&#xff0c;这个时候不需要借用第三方比对插件&#xff0c;在IDEA中…

2022 icpc杭州站 C. No Bug No Game - 背包dp

题面 分析 能拿整个 p i p_i pi​的就拿整个的&#xff0c;不能拿了可以拿一部分的&#xff0c;因此可以分成0和1两种情况&#xff0c;0表示拿整个的&#xff0c;1表示还可以拿部分的&#xff0c;两种情况放在一起做一遍01背包&#xff0c;找到最大价值。 代码 #include &l…