使用 Redis Zset 有序集合实现排行榜功能(SpringBoot环境)

news2024/11/25 4:43:38

目录

    • 一、前言
    • 二、Redis Zset 的基本操作
    • 三、通过Redis 命令模拟排行榜功能
      • 3.1、排行榜生成
      • 3.2、排行榜查询
    • 四、SpringBoot 使用 Redis Zset 有序集合实现排行榜功能

一、前言

      排行榜功能是非常常见的需求,例如商品售卖排行榜单、游戏中的积分排行榜、配送员完单排行榜等。实现排行榜功能需要高效地对大量数据进行排序和查询,如果直接进行数据库查询对应业务排行榜资源开销会非常大,一般会将对应榜单需要的数据做单独存储记录,查询时只要对榜单数据表进行遍历排序即可,因为榜单数据表的数据是无序的,还要对具体数据进行排序,并且每次数据变动都要更新表中数据,当数据量过大或者高并发时性能一般,要想高效地实现排行榜功能需要使用 Redis Zset 有序集合,可以非常高效方便地实现排行榜功能。

需要Redis常用命令集文章可以查看:https://blog.csdn.net/weixin_44606481/article/details/133672258

二、Redis Zset 的基本操作

# 添加以一个过着多个元素,score为评分,集合按照从低到高及进行排序,评分可以重复
zadd  <key> <score1> <value1> <score2> <value2>

# 获取有序集合中成员的数量
zcard <key>

# 统计score评分在某个范围内的数据的数量
zcount <key> <min> <max>

# 查一定范围的元素,end为-1时,查询所有,按照分数从小到大排序,withscores加上他,连着评分一起查出
zrange <key> <start> <end> [LIMIT offset count] [withscores]

# 查一定范围的元素,end为-1时,查询所有,按照分数从大到小排序,withscores加上他,连着评分一起查出
zrevrange <key> <start> <end> [LIMIT offset count] [withscores]

# 查询score评分在某个范围内的数据,从小到大排序,min 和 max 可以是 -inf 和 +inf来表示无穷小和无穷大,withscores加上他,连着评分一起查出
zrangebyscore <key> <min> <max> [withscores] [limit offset count]

# 查询score评分在某个范围内的数据,从大到小排序,min 和 max 可以是 -inf 和 +inf来表示无穷小和无穷大,withscores加上他,连着评分一起查出
zrevrangebyscore  <key> <max> <min> [withscores] [limit offset count]

# 为元素的score加上指定的增量
zincrby  <key> <increment> <value>

# 删除数据
zrem <key> <value1> <value2>

# 返回集合中value的排名,按分数递增排序。分数值最小者排名为0
zrank  <key> <value>

# 返回集合中value的排名,按分数递减排序。分数值最大者排名为0
zrevrank  <key> <value>

三、通过Redis 命令模拟排行榜功能

       这里模拟一个商品销量排行榜缓存key为PRODUCT:RANK:SALES,假设有6个商品,商品ID分别为 P001-P006。

3.1、排行榜生成

  • 1、初始化排行榜数据(为了演示这里先给每个商品销量设置0,一般在业务中会先将数据库中的销量数据查询出来初始化到排行榜中)
127.0.0.1:6379> zadd  PRODUCT:RANK:SALES 0 P001 0 P002 0 P003 0 P004 0 P005 0 P006
(integer) 6
  • 2、给商品ID为P002、P005、P006的商品分别添加销量7、2、9
127.0.0.1:6379> zincrby PRODUCT:RANK:SALES 7 P002
"7"
127.0.0.1:6379> zincrby PRODUCT:RANK:SALES 2 P005
"2"
127.0.0.1:6379> zincrby PRODUCT:RANK:SALES 9 P006
"9"

3.2、排行榜查询

  • 1、查询排行榜全部数据按照分数从大到小排序
127.0.0.1:6379> zrevrange PRODUCT:RANK:SALES 0 -1 withscores
 1) "P006"
 2) "9"
 3) "P002"
 4) "7"
 5) "P005"
 6) "2"
 7) "P004"
 8) "0"
 9) "P003"
10) "0"
11) "P001"
12) "0"
  • 2、查询排行榜销量前三的数据按照分数从大到小排序
127.0.0.1:6379> zrevrange PRODUCT:RANK:SALES 0 2 withscores
1) "P006"
2) "9"
3) "P002"
4) "7"
5) "P005"
6) "2"
  • 3、查询排行榜销量大于等于1的数据从小到大排序,并且进行分页,每页2条数据查询第1页
# 不分页
127.0.0.1:6379> zrangebyscore PRODUCT:RANK:SALES 1 +inf withscores
1) "P005"
2) "2"
3) "P002"
4) "7"
5) "P006"
6) "9"
# 分页 limit 0 2 (0:代表偏移量 2:显示条数)
127.0.0.1:6379> zrangebyscore PRODUCT:RANK:SALES 1 +inf withscores limit 0 2
1) "P005"
2) "2"
3) "P002"
4) "7"

四、SpringBoot 使用 Redis Zset 有序集合实现排行榜功能

需要SpringBoot集成Redis文章可以查看:https://blog.csdn.net/weixin_44606481/article/details/133907103

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.HashSet;
import java.util.Set;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class RedisZSetTest {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    // 商品排行榜key
    private String cacheKey = "PRODUCT:RANK:SALES";

    /**
     * 初始化排行榜
     */
    @Test
    public void initRank() {
        // 初始化前先删除对应key
        redisTemplate.delete(cacheKey);
        // 创建一个存储 TypedTuple 的集合 用于批量添加,也可以单独添加
        Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
        tuples.add(new DefaultTypedTuple<>("P001", 0D));
        tuples.add(new DefaultTypedTuple<>("P002", 0D));
        tuples.add(new DefaultTypedTuple<>("P003", 0D));
        tuples.add(new DefaultTypedTuple<>("P004", 0D));
        tuples.add(new DefaultTypedTuple<>("P005", 0D));
        tuples.add(new DefaultTypedTuple<>("P006", 0D));
        Long add = redisTemplate.opsForZSet().add(cacheKey, tuples);
        System.out.println("初始化成功:"+ add);
    }

    /**
     * 添加排行榜数据
     */
    @Test
    public void addRank() {
        redisTemplate.opsForZSet().incrementScore(cacheKey,"P002",7D);
        redisTemplate.opsForZSet().incrementScore(cacheKey,"P005",2D);
        redisTemplate.opsForZSet().incrementScore(cacheKey,"P006",9D);
        System.out.println("添加排行榜数据成功");
    }

    /**
     * 查询排行榜数据
     */
    @Test
    public void queryRank() {
        // 查询排行榜全部数据按照分数从大到小排序
        Set<ZSetOperations.TypedTuple<Object>> set1 = redisTemplate.opsForZSet().reverseRangeWithScores(cacheKey, 0L, -1L);
        System.out.println("查询排行榜全部数据按照分数从大到小排序:");
        set1.forEach(tuple -> {
            System.out.println(tuple.getValue() + " : " + tuple.getScore());
        });

        // 查询排行榜销量前三的数据按照分数从大到小排序
        Set<ZSetOperations.TypedTuple<Object>> set2 = redisTemplate.opsForZSet().reverseRangeWithScores(cacheKey, 0L, 2L);
        System.out.println("查询排行榜销量前三的数据按照分数从大到小排序:");
        set2.forEach(tuple -> {
            System.out.println(tuple.getValue() + " : " + tuple.getScore());
        });

        // 查询排行榜销量大于等于1的数据从小到大排序,并且进行分页,每页2条数据查询第1页
        Set<ZSetOperations.TypedTuple<Object>> set3 = redisTemplate.opsForZSet().rangeByScoreWithScores(cacheKey, 1D, Double.MAX_VALUE, 0L, 2L);
        System.out.println("查询排行榜销量大于等于1的数据从小到大排序,并且进行分页,每页2条数据查询第1页:");
        set3.forEach(tuple -> {
            System.out.println(tuple.getValue() + " : " + tuple.getScore());
        });
    }
}

查询结果
在这里插入图片描述

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

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

相关文章

原创文章生成器-批量原文高质量伪原创

在信息爆炸的时代&#xff0c;创作者们面临的挑战愈发严峻。写一篇原创文章&#xff0c;不仅需要脑洞大开&#xff0c;还得担心自己的文字是否能够迎合读者口味。原创文章生成器只需输入标题或关键词&#xff0c;即可轻松生成原创文章。而与此同时&#xff0c;147SEO改写软件也…

FLASK博客系列8——我也有后台管理

上次我们学习了如何往数据库里插入数据&#xff0c;显示我们自己的文章。 有些朋友可能会问&#xff0c;django有后台管理&#xff0c;插入不用这么麻烦&#xff0c;那flask有类似的吗&#xff1f;当然有&#xff0c;而且还挺多的。今天我们就用一个最常用的包来完成 flask-adm…

数据库系统原理与实践 笔记 #10

文章目录 数据库系统原理与实践 笔记 #10存储管理与索引(续)数据字典存储系统元数据的关系表示 数据缓冲区存储访问缓冲区管理器缓冲区替换策略 顺序索引基本概念索引技术评价指标顺序索引稠密索引稀疏索引索引多级索引辅助索引主索引与辅助索引多码索引 B树索引B树索引文件B树…

机器学习的复习笔记2-回归

一、什么是回归 机器学习中的回归是一种预测性分析任务&#xff0c;旨在找出因变量&#xff08;目标变量&#xff09;和自变量&#xff08;预测变量&#xff09;之间的关系。与分类问题不同&#xff0c;回归问题关注的是预测连续型或数值型数据&#xff0c;如温度、年龄、薪水…

如何通过内网穿透实现远程访问Linux SVN服务

文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…

mysql文本类型的最大长度限制

mysql支持很多类型&#xff0c;不同的文本有不同的长度限制。可以根据实际需要进行选择。 TINYBLOB, TINYTEXT L 1 bytes, where L < 2^8 (255 Bytes) BLOB, TEXT L 2 bytes, where L < 2^16 (64 Kilobytes) MEDIUMBLOB, MEDIUMTEXT L 3 b…

怎样禁止邮件发送附件

入侵电子邮件并获取其承载信息成为网络攻击的主要目标之一&#xff0c;因此&#xff0c;掌握基本的电子邮件安全常识显得尤为重要。 “涉密不上网&#xff0c;上网不涉密”是国家秘密安全底线&#xff0c;电子邮件作为互联网应用之一&#xff0c;绝不能存储、传输涉密信息和敏感…

Docker-简介、基本操作

目录 Docker理解 1、Docker本质 2、Docker与虚拟机的区别 3、Docker和JVM虚拟化的区别 4、容器、镜像的理解 5、Docker架构 Docker客户端 Docker服务器 Docker镜像 Docker容器 镜像仓库 Docker基本操作 1、Docker镜像仓库 镜像仓库分类 镜像仓库命令 docker lo…

骑行三家村赏红杉之旅:挑战与汗水共存,美景和惊喜同行的路线

2023年11月25日&#xff0c;一个冬日里阳光明媚的周末&#xff0c;校长骑行队的骑友们相约&#xff0c;共同踏上了骑行三家村赏红杉林的旅程。这次骑行路线从大观公园门口开始&#xff0c;途径大观湿地公园、干勾尾、碧鸡关加油站、太平、水沟盖板路、明朗、绝望坡、山顶、三家…

SWT技巧

实现控件的刷新 问题可以简化如下&#xff0c;点击上方按钮&#xff0c;使下方按钮移动&#xff0c;但要求在监听事件里新建按钮对象&#xff0c;而不是使用原来的按钮&#xff08;原来的按钮被移除了&#xff09;。 解决代码如下&#xff1a; public class TestUI {protecte…

阻塞队列及简单实现,生产者消费者模型

文章目录 阻塞队列阻塞队列是什么生产者消费者模型阻塞队列的实现 阻塞队列 阻塞队列是什么 阻塞队列是一种特殊的队列. 也遵守 “先进先出” 的原则. 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素当队列空的时候, 继续出队列也会阻塞, 直到有其他线…

B 树和 B+树 的区别

文章目录 B 树和 B树 的区别 B 树和 B树 的区别 了解二叉树、AVL 树、B 树的概念 B 树和 B树的应用场景 B 树是一种多路平衡查找树&#xff0c;为了更形象的理解。 二叉树&#xff0c;每个节点支持两个分支的树结构&#xff0c;相比于单向链表&#xff0c;多了一个分支。 …

边缘计算网关:智能制造的“智慧大脑”

一、智能制造的崛起 随着科技的飞速发展&#xff0c;智能制造已经成为了制造业的新趋势。智能制造不仅能够提高生产效率&#xff0c;降低生产成本&#xff0c;还能够实现个性化定制&#xff0c;满足消费者多样化的需求。然而&#xff0c;智能制造的实现离不开大量的数据处理和分…

警惕!AI正在“吞食”你的数据

视觉中国供图 □ 科普时报记者 陈 杰 AI大模型的热度&#xff0c;已然开始从产业向日常生活渗透&#xff0c;并引起不小的舆论旋涡。近日&#xff0c;网友指出国内某智能办软件有拿用户数据“投喂”AI之嫌&#xff0c;引发口水的同时&#xff0c;再度把公众对AI的关注转移到数…

AWR294x收发器的干扰抑制(TI文档)

摘要&#xff1a; AWR294x收发器是一种集成的片上雷达设备&#xff0c;不仅具有RF&#xff0c;模拟和ADC电路&#xff0c;而且在芯片上还有许多处理器核。它有一个专门的雷达信号处理加速器(称为硬件加速器或HWA)&#xff0c;具有能够探测和减缓雷达-雷达干扰的特点。本文档介绍…

MySQL死锁,死锁产生的4个必要条件,死锁案例, 如何避免死锁

文章目录 MySQL死锁了怎么办&#xff08;死锁的产生及解决方案&#xff09;&#xff1f;1、 死锁与产生死锁的四个必要条件1.1 什么是死锁1.2 死锁产生的4个必要条件 2、死锁案例2.1 表锁死锁2.2 行锁死锁2.3 共享锁转换为排他锁 3、死锁排查4、 如何避免死锁5、死锁的排查6、 …

抖音餐饮门店点餐外卖小程序作用是什么

餐饮从业商家、各种餐品饮料线下门店众多&#xff0c;随着线上订餐、团购、预约、点餐等方式发展&#xff0c;线下门店经营痛点明显&#xff0c;不少商家选择搭建餐饮门店小程序一方面是品牌传播拓客及提升服务效率&#xff0c;另一方面则是赋能客户完善消费及覆盖进店前后路径…

教师如何高质量备课

备课是教学工作中不可或缺的一部分。高质量的备课不仅可以提高课堂效率&#xff0c;还可以更好地激发学生的学习兴趣和积极性。那么&#xff0c;如何高质量备课呢&#xff1f; 深入了解学生 备课的目的是教授知识&#xff0c;让学生掌握知识。因此&#xff0c;了解学生的需求和…

使用脚手架创建Vue3项目

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Vue ✨特色专栏&#xff1a; MySQL学习…

【MySQL | TCP】宝塔面板结合内网穿透实现公网远程访问

文章目录 前言1.Mysql服务安装2.创建数据库3.安装cpolar3.2 创建HTTP隧道4.远程连接5.固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 宝塔面板的简易操作性&#xff0c;使得运维难度降低&#xff0c;简化了Linux命令行进行繁琐的配置&#x…