一、前言
排行榜功能是非常常见的需求,例如商品售卖排行榜单、游戏中的积分排行榜、配送员完单排行榜等。实现排行榜功能需要高效地对大量数据进行排序和查询,如果直接进行数据库查询对应业务排行榜资源开销会非常大,一般会将对应榜单需要的数据做单独存储记录,查询时只要对榜单数据表进行遍历排序即可,因为榜单数据表的数据是无序的,还要对具体数据进行排序,并且每次数据变动都要更新表中数据,当数据量过大或者高并发时性能一般,要想高效地实现排行榜功能需要使用 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、排行榜生成
127.0.0.1:6379> zadd PRODUCT:RANK:SALES 0 P001 0 P002 0 P003 0 P004 0 P005 0 P006
(integer) 6
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"
# 不分页
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进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。