当前位置: 首页 > news >正文

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);  }  
}

相关文章:

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

专栏集锦&#xff0c;大佬们可以收藏以备不时之需 Spring Cloud实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏&#xff1a;https:/…...

基于信号功率谱特征和GRNN广义回归神经网络的信号调制类型识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ................................................................ %调制识别 len1 func_f…...

matplotlib从起点出发(10)_Tutorial_10_Layout

使用受约束的绘图干净整洁地将图形合适排列。 受约束的布局会自动调整子图&#xff0c;以便刻度标签、图例和颜色条等装饰不会重叠&#xff0c;同时仍保留用户请求的逻辑布局。 受约束布局类似于“紧密布局”&#xff0c;但它要更灵活。它处理放置在多个轴上的Axes(放置颜色条…...

HTTP头部信息解释分析(详细整理)(转载)

这篇文章为大家介绍了HTTP头部信息&#xff0c;中英文对比分析&#xff0c;还是比较全面的&#xff0c;若大家在使用过程中遇到不了解的&#xff0c;可以适当参考下 HTTP 头部解释 1. Accept&#xff1a; 告诉WEB服务器自己接受什么介质类型&#xff0c;/ 表示任何类型&#…...

集线器、交换机、网桥、路由器、网关

目录 集线器(HUB)交换机(SWITCH)网桥(BRIDGE)路由器(ROUTER)网关(GATEWAY)交换机和路由器的区别参考 集线器(HUB) 功能 集线器对数据的传输起到同步、放大和整形的作用 属于物理层设备 工作机制 使用集线器互连而成的以太网被称为共享式以太网。当某个主机要给另一个主机发送单…...

项目实战:新增@Controller和@Service@Repository@Autowire四个注解

1、Controller package com.csdn.mymvc.annotation; import java.lang.annotation.*; Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Inherited public interface Controller { }2、Service package com.csdn.mymvc.annotation; import java.lang.annotation.*…...

校验 ChatGPT 4.0 真实性的三个经典问题:快速区分 GPT3.5 与 GPT4,并提供免费测试网站

现在已经有很多 ChatGPT 的套壳网站&#xff0c;以下分享验明 GPT-4 真身的三个经典问题&#xff0c;帮助你快速区分套壳网站背后到底用的是 GPT-3.5 还是 GPT-4。 大家可以在这个网站测试&#xff1a;https://ai.hxkj.vip&#xff0c;免登录可以问三条&#xff0c;登录之后无限…...

Jetpack:030-Jetpack中的状态

文章目录 1. 概念介绍2. 使用方法2.1 可监听对象2.2 获取状态值2.3 修改状态值2.4 重组函数 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack中网格布局相关的内容&#xff0c;本章回中主要 介绍状态。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xff0…...

AD教程 (七)元件的放置

AD教程 &#xff08;七&#xff09;元件的放置 第一种放置方法 点击右下角Panels&#xff0c;选择SCH Library&#xff0c;调出原理图库器件列表选中想要放置的元件&#xff0c;点击放置&#xff0c;就会自动跳转到原理图&#xff0c;然后放置即可这种方法需要不断打开元件库…...

ubuntu22.04为什么鼠标会自动丢失焦点

排查的步骤 在Ubuntu 22.04中&#xff0c;鼠标自动丢失焦点可能由多种原因引起&#xff0c;包括系统错误、驱动问题、软件冲突或者某些特定的系统设置。以下是一些可能的原因和相应的解决方法&#xff1a; 触控板干扰&#xff1a; 如果你使用的是笔记本电脑&#xff0c;触控板可…...

FastBond2阶段2——基于ESP32C3开发的简易IO调试设备

1. 项目介绍 之前买了许多国产单片机esp32c3一直在吃灰&#xff0c;没有发挥它的真实价值。非常感谢硬禾组织的Fastbond2活动&#xff0c;刚好两者经过微妙的碰撞。恰可以用于FastBond2活动主题4 - 测量仪器&#xff08;单片机开发测试领域&#xff09;&#xff0c;或者用于国…...

03、SpringBoot + 微信支付 ---- 创建订单、保存二维码url、显示订单列表

目录 Native 下单1、创建课程订单保存到数据库1-1&#xff1a;需求&#xff1a;1-2&#xff1a;代码&#xff1a;1-3&#xff1a;测试结果&#xff1a; 2、保存支付二维码的url2-1&#xff1a;需求&#xff1a;2-2&#xff1a;代码&#xff1a;2-3&#xff1a;测试&#xff1a;…...

【echarts基础】在柱形图上设置文本

一、需求描述 在柱状图上设置文本标签&#xff0c;按需修改它的颜色、大小、边框、阴影等&#xff0c;如下。 二、代码展示 series:[{name:"螺蛳粉",type:"bar",data:data.data.chartData.chartData.num.螺蛳粉,label:{//图形上显示文本标签formatter:&q…...

小户型工业风,陌生上开花知书香。福州中宅装饰,福州装修

漫步陌上 只因陌上花开 花是自然的那种 朴素而恬淡&#xff0c;不落尘俗。—徐志摩 小户型工业风格 满足业主需求 筑造书香押韵家 从动线、色彩、选材、定制等各个环节 与业主一起畅谈家的构造 形成别“居”一格的温暖品质家 以书做墙 告别电视墙 这是一个实用性很强的…...

Gorm 中的迁移指南

探索使用 GORM 在 Go 中进行数据库迁移和模式更改的世界 在应用程序开发的不断变化的景观中&#xff0c;数据库模式更改是不可避免的。GORM&#xff0c;强大的 Go 对象关系映射库&#xff0c;通过迁移提供了一种无缝的解决方案来管理这些变化。本文将作为您全面的指南&#xf…...

基于.NET、Uni-App开发支持多平台的小程序商城系统 - CoreShop

前言 小程序商城系统是当前备受追捧的开发领域&#xff0c;它可以为用户提供一个更加便捷、流畅、直观的购物体验&#xff0c;无需下载和安装&#xff0c;随时随地轻松使用。今天给大家推荐一个基于.NET、Uni-App开发支持多平台的小程序商城系统&#xff08;该商城系统完整开源…...

[python] 在多线程中将`logging.info`输出到不同的文件中 (生产者消费者)

在多线程中将logging.info输出到不同的文件中&#xff0c;可以使用Python标准库中的Queue和Thread模块。具体实现步骤如下&#xff1a; 创建多个Queue队列用于不同线程的日志输出&#xff0c;每个队列对应一个日志文件。 import queue# 创建三个队列用于不同线程的日志输出 l…...

MySQL进阶_5.逻辑架构和SQL执行流程

文章目录 第一节、逻辑架构剖析1.1、服务器处理客户端请求1.2、Connectors1.3、第1层&#xff1a;连接层1.4、第2层&#xff1a;服务层1.5、 第3层&#xff1a;引擎层1.6、 存储层1.7、小结 第二节、SQL执行流程2.1、查询缓存2.2、解析器2.3、优化器2.4、执行器 第三节、数据库…...

【油猴脚本】学习笔记

目录 新建用户脚本模板源注释 测试代码获取图标 Tampermonkey v4.19.0 原教程&#xff1a;手写油猴脚本&#xff0c;几分钟学会新技能——王子周棋洛   Tampermonkey首页   面向 Web 开发者的文档   Greasy Fork 新建用户脚本 打开【管理面板】 点击【】&#xff0c;即…...

宝塔面板使用Supervisor进程守护插件,配置守护Mysql的操作教程。

本篇文章主要讲解&#xff0c;在宝塔面板中使用Supervisor进程守护插件&#xff0c;配置守护Mysql的操作教程。 作者&#xff1a;任聪聪 日期&#xff1a;2023年11月5日 一、安装守护进程插件 安装插件一、进程守护插件 安装说明&#xff1a;在软件商店中搜索“进程守护”&am…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...