📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍
文章目录
- 有序集合(SortedSet)
有序集合(SortedSet)
【结构简介】
1、Sorted Set 类似于 Set,但和 Set 相比,Sorted Set 增加了一个 double 类型的分数,使得集合中的元素能够按分数进行有序排列。
2、Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加 hash表。
3、SortedSet具备下列特性:
- 可排序
- 元素不重复
- 查询速度快
总之,因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。
【应用场景】
要随机获取数据源中的元素根据某个权重进行排序的场景。
● 举例 :各种排行榜,还有周榜月榜的汇总实现。
● 相关命令 :ZINCR(每点击一次进行加一)、ZREVRANGE (从大到小排序)、ZUNIONSTORE(多日搜索汇总)。
【应用场景 - 补充】
ZSet(有序集合)是 Redis 中的一种数据结构,它结合了集合的特性和排序的能力。每个元素都有一个分数(score),根据分数的大小,元素会被自动排序。
- 排行榜:可以用 ZSet 来实现游戏的排行榜,玩家的分数作为分数,玩家的 ID 作为元素。
- 时间序列数据:可以用 ZSet 存储带有时间戳的数据,时间戳作为分数,比如存储商品的剩余库存,并根据剩余时间进行排序,优先展示剩余时间少的商品。
- 推荐系统:可以用 ZSet 来存储用户的偏好,分数可以表示用户对某个项目的喜好程度,也可以是商品、文章、视频等内容的热门推荐。
总之,ZSet 是 Redis 中一个功能强大的数据结构,它可以用于各种场景,例如排行榜、热门推荐、搜索结果排序、限时抢购等。通过使用 RedisTemplate,我们可以方便地操作 ZSet,实现各种功能。
//LeaderboardService 提供了添加玩家分数、获取前 N 名玩家和获取玩家分数的方法。
//使用 opsForZSet().add() 方法添加分数,使用 opsForZSet().reverseRange() 获取排名前 N 的玩家。
@Service
public class LeaderboardService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private final String LEADERBOARD_KEY = "game_leaderboard";
// 添加玩家分数
public void addScore(String playerId, double score) {
redisTemplate.opsForZSet().add(LEADERBOARD_KEY, playerId, score);
}
// 获取前 N 名玩家
public Set<String> getTopPlayers(int topN) {
return redisTemplate.opsForZSet().reverseRange(LEADERBOARD_KEY, 0, topN - 1);
}
// 获取玩家的分数
public Double getPlayerScore(String playerId) {
return redisTemplate.opsForZSet().score(LEADERBOARD_KEY, playerId);
}
}
//TimeSeriesService 提供了添加时间序列数据和获取指定时间范围内数据的方法。
//使用 opsForZSet().add() 方法添加数据,使用 opsForZSet().rangeByScore() 获取指定时间范围内的数据。
@Service
public class TimeSeriesService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private final String TIME_SERIES_KEY = "sensor_data";
// 添加时间序列数据
public void addData(long timestamp, String data) {
redisTemplate.opsForZSet().add(TIME_SERIES_KEY, data, timestamp);
}
// 获取指定时间范围内的数据
public Set<String> getDataInRange(long startTime, long endTime) {
return redisTemplate.opsForZSet().rangeByScore(TIME_SERIES_KEY, startTime, endTime);
}
}
【对比Java的SortedSet】
Redis 的 ZSet 类似于 Java 中的 SortedSet 结构,但又有一些区别:
相同点:
- 有序性: 两种结构都按照元素的排序规则进行排序,ZSet 按照分数排序,SortedSet 按照比较器定义的规则排序。
- 唯一性: 两种结构都保证元素的唯一性,不允许重复元素。
不同点:
- 数据结构: ZSet 是 Redis 自己的数据结构,而 SortedSet 是 Java 中的集合接口。
- 排序依据: ZSet 按照分数排序,而 SortedSet 按照比较器定义的规则排序。
- 分数: ZSet 中每个元素都有一个分数,用于排序和范围查询,而 SortedSet 没有分数的概念。
- 范围查询: ZSet 支持范围查询,例如获取分数在某个范围内的元素,而 SortedSet 不支持范围查询。
总结,虽然 ZSet 和 SortedSet 都具有有序性和唯一性,但 ZSet 更加强大,它支持分数排序、范围查询等功能,更适合用于需要排序和范围查询的场景。
【基础操作】
ZADD key score menber1 [ score2 menber2 ]:向有序集合添加一个或者多个成员,或者更新已存在的成员分数
ZCARD key:获取有序集合的元素个数
ZREM key menber [ member ]:移除有序集合中的一个或多个成员
ZSCORE key member:获取指定有序集合中指定元素的 score 值
ZRANGE key start stop:通过索引区间返回有序集合成指定区间内的成员(score 从低到高)
ZREVRANGE key start stop:通过索引区间返回有序集合成指定区间内的成员(score 从高到低)
● ZADD key score menber1 [ score2 menber2 ]:向有序集合添加一个或者多个成员,或者更新已存在的成员分数
● ZCARD key:获取有序集合的元素个数
● ZRANGE key start stop [ WITHSCORES ]:通过索引区间返回有序集合成指定区间内的成员
● ZREM key menber [ member ]:移除有序集合中的一个或多个成员
● ZSCORE key member1:获取指定有序集合中指定元素的 score 值
● ZREVRANGE key start end:
---------------------------------------------------分隔线---------------------------------------------------
● ZCOUNT key min max:可计算在有序集合中指定区间分数的成员
● ZINCRBY key increment menber:有序集合中对指定成员的分数加上增量increment
● ZINTERSTORE destination numkeys key [ key… ]:计算给定的一个或者多个有序集的交集并将结果集存储在新的有序集合key中
● ZUNIONSTORE destination numkeys key [ key… ]:计算给定的一个或者多个有序集的并集并将结果集存储在新的有序集合key中
● ZDIFF destination numkeys key [ key… ]:计算给定的一个或者多个有序集的差集并将结果集存储在新的有序集合key中
● ZRANGEBYSCORE key min max [ WITHSCORES ] [ LIMIT ]:通过分数返回有序集合指定区间内的成员
● ZLEXCOUNT key min max:在有序集合中计算指定字典区间内成员数量
● ZRANGEBYLEX key min max [ LIMIT offset count ]:通过字典区间返回有序集合的成员
● ZRANK key menber:返回有序集合中指定成员的索引
注意:所有的排名默认都是升序,如果要降序则在命令的Z后面添加REV即可,例如:
升序
获取sorted set 中的指定元素的排名:ZRANK key member降序
获取sorted set 中的指定元素的排名:ZREVRANK key memeber
【代码示例】