Redis实现排行榜
作者:互联网
Redis怎么去实现排行榜的功能呢?这实际上也是非常有意思的一个需求,我们先来确定一下 Redis 实现排行榜都需要准备什么样子的工作。
Redis实现排行榜
为什么 Redis 可以实现排行榜的功能呢?
这也是和数据结构有一定的关系,因为我们大家的认知里面,都知道 Redis 支持各种数据类型的存储,有 String 有 List,还有 Set ,而 Redis 中就是因为有了这个 Set 所以实现排行榜就相对来说比较简单了,因为 Set 是有序的。
Sorted Sets数据类型就像是set和hash的混合,与sets一样,Sorted Sets是唯一的,不重复的字符串组成。可以说Sorted Sets也是Sets的一种。
Sorted Sets是通过Skip List(跳跃表)和hash Table(哈希表)的双端口数据结构实现的,因此每次添加元素时,Redis都会执行O(log(N))操作。所以当我们要求排序的时候,Redis根本不需要做任何工作了,早已经全部排好序了。元素的分数可以随时更新。
使用 Redis 实现排行榜
我们使用 Springboot 来整合一下 Redis 然后使用 Sorted Sets 来实现一下我们想做的这个排行榜。
- 创建 Springboot 项目,导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
我们在这里就使用 RedisTemplate,
2.增加配置
server:
port: 9001
spring:
redis:
host: 127.0.0.1
port: 6379
password: 123456
jedis:
pool:
max-active: 8
max-wait: -1
max-idle: 500
min-idle: 0
lettuce:
shutdown-timeout: 0
给 Redis 中存数据信息
@Test
public void batchAdd() {
Set<ZSetOperations.TypedTuple<String>> tuples = new HashSet<>();
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
DefaultTypedTuple<String> tuple = new DefaultTypedTuple<>("chuyikeji" + i, 1D + i);
tuples.add(tuple);
}
System.out.println("循环时间:" +( System.currentTimeMillis() - start));
Long num = redisTemplate.opsForZSet().add(SCORE_RANK, tuples);
System.out.println("批量新增时间:" +(System.currentTimeMillis() - start));
System.out.println("受影响行数:" + num);
}
运行我们的测试可以看到
循环时间:56
批量新增时间:1015
受影响行数:100000
获取前10名(根据分数倒序)
@Test
public void list() {
Set<String> range = redisTemplate.opsForZSet().reverseRange(SCORE_RANK, 0, 10);
System.out.println("获取到的排行列表:" + JSON.toJSONString(range));
Set<ZSetOperations.TypedTuple<String>> rangeWithScores = redisTemplate.opsForZSet().reverseRangeWithScores(SCORE_RANK, 0, 10);
System.out.println("获取到的排行和分数列表:" + JSON.toJSONString(rangeWithScores));
}
这时候我们就能看到数据信息
获取到的排行列表:["chuyikeji99999","chuyikeji99998","chuyikeji99997","chuyikeji99996","chuyikeji99995","chuyikeji99994","chuyikeji99993","chuyikeji99992","chuyikeji99991","chuyikeji99990","chuyikeji99989"]
获取到的排行和分数列表:[{"score":100000.0,"value":"chuyikeji99999"},{"score":99999.0,"value":"chuyikeji99998"},{"score":99998.0,"value":"chuyikeji99997"},{"score":99997.0,"value":"chuyikeji99996"},{"score":99996.0,"value":"chuyikeji99995"},{"score":99995.0,"value":"chuyikeji99994"},{"score":99994.0,"value":"chuyikeji99993"},{"score":99993.0,"value":"chuyikeji99992"},{"score":99992.0,"value":"chuyikeji99991"},{"score":99991.0,"value":"chuyikeji99990"},{"score":99990.0,"value":"chuyikeji99989"}]
我们在开头使用了批量新增的方式直接给把所有的数据都填充进去了,实际上肯定不是这个样子的,因为大部分的数据我们肯定都是一条记录一条记录增加的,比如现在有个新人 aaaa 他的得分是777 这时候我们要插入到 Redis 中
@Test
public void add() {
redisTemplate.opsForZSet().add(SCORE_RANK, "aaaa", 777);
}
这时候我们获取一下 aaaa 的排名情况。
@Test
public void find(){
Long rankNum = redisTemplate.opsForZSet().reverseRank(SCORE_RANK, "aaaa");
System.out.println("aaaa的个人排名:" + rankNum);
Double score = redisTemplate.opsForZSet().score(SCORE_RANK, "aaaa");
System.out.println("aaaa的分数:" + score);
}
这时候我们看一下打印出来的结果
aaaa的个人排名:99224
aaaa的分数:777.0
如果我们在其中想查询 700分到800分之间的人数?
@Test
public void count(){
Long count = redisTemplate.opsForZSet().count(SCORE_RANK, 701, 800);
System.out.println("统计700-800之间的人数:" + count);
}
统计700-800之间的人数:101
Redis 中的 Sorted Sets
Sorted Set有点像Set和Hash的结合体。
和Set一样,它里面的元素是唯一的,类型是String,所以它可以理解为就是一个Set。
但是Set里面的元素是无序的,而Sorted Set里面的元素都带有一个浮点值,叫做分数(score),所以这一点和Hash有点像,因为每个元素都映射到了一个值。
标签:Set,实现,Redis,System,value,aaaa,排行榜,score 来源: https://blog.csdn.net/yinlidong77/article/details/121148044