一、前言

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

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

二、Redis Zset基本操作

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

# 获取有序集合成员的数量
zcard <key&gt;

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

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

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

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

# 查询score评分在某个范围内的数据,从大到小排序,minmax 可以是 -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、排行榜生成

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

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

原文地址:https://blog.csdn.net/weixin_44606481/article/details/134468751

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_12453.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注