
4.5 sorted set4.5.1 概述核心基础有序集合sorted set是在普通集合set的基础上做了扩展为集合中的每一个元素都关联了一个对应的分数score。基于这个特性它不仅支持普通集合的核心操作插入、删除、判断元素是否存在还额外支持一系列与分数相关的专属操作如获取分数最高 / 最低的前 N 个元素、获取指定分数范围的元素等。与列表list类型的异同一相同点二者均具备有序性、范围查询能力二者存储的元素都是有序的二者都支持获取指定范围的元素。二核心区别底层实现与功能特性差异对比维度列表list有序集合sorted set底层实现双向链表散列表访问性能靠近两端的数据访问速度极快元素增多后访问中间数据速度变慢无论首尾还是中间数据访问速度都很快高效元素位置调整无法简单调整单个元素的位置可通过修改元素关联的分数灵活调整元素位置内存消耗内存占用相对较低内存消耗更高因需额外存储分数及维护有序结构总结sorted set 基于普通 set 扩展核心特性是「元素唯一 关联分数 有序排列」与 list 同为有序且支持范围查询但底层实现、访问性能、功能灵活性、内存消耗均有显著差异sorted set 更适合需要基于分数排序、高效查询中间数据的场景代价是更高的内存占用。4.5.2 命令增加元素向有序集合中加入一个元素和该元素的分数如果该元素已经存在则会用新的分数替换原有的分数。返回值是新加入到集合中的元素个数不包含之前已经存在的元素。ZADD key score member [score member ...]2.获取元素的分数ZSCORE key member获取排名在某个范围的元素列表按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素包含两端的元素。ZRANGE key start stop [WITHSCORES]先将该有序集合的所有元素按照分数score从小到大升序进行排序形成一个有序的 “虚拟列表”这个排序后的 “虚拟列表”下标从 0 开始和 Redis List、Java 数组下标规则一致按照 start 和 stop 指定的下标范围返回该范围内的所有元素包含 start 和 stop 对应的元素可选参数 WITHSCORES加上该参数后返回结果会同时携带元素的值member和对应的分数score不加则只返回元素值。照元素分数从大到小的顺序返回索引从start到stop之间的所有元素包含两端的元素ZREVRANGE key start stop [WITHSCORES]获得指定分数范围的元素ZRANGEBYSCORE key min max [WITHSCORES][LIMIT offset count](min / (max给 min 或 max 加上括号代表不包含该边界值默认是包含边界值的。offset是在符合分数范围的结果列表里的起始下标从 0 开始。增加某个元素的分数返回值是更改后的分数ZINCRBY key increment member6.获得集合中元素的数量ZCARD key7.获得指定分数范围内的元素个数ZCOUNT key min max8.按照排名范围删除元素按分数从小到大升序排序ZREMRANGEBYRANK key start stop按照分数范围删除元素ZREMRANGEBYSCORE key min max10.获取元素的排名#从小到大 ZRANK key member #从大到小 ZREVRANK key member4.5.3 方法sorted set类型核心操作Redis 命令StringRedisTemplate 核心方法功能说明zaddopsForZSet().add(key, member, score)添加 / 更新有序集合元素zscoreopsForZSet().score(key, member)获取元素对应的分数zrangeopsForZSet().range(key, start, stop)升序获取指定排名范围元素zrange withscoresopsForZSet().rangeWithScores(key, start, stop)升序获取元素并携带分数zrevrangeopsForZSet().reverseRange(key, start, stop)降序获取指定排名范围元素zrangebyscoreopsForZSet().rangeByScore(key, min, max)按分数范围获取元素zrangebyscore withscoresopsForZSet().rangeByScoreWithScores(key, min, max)按分数范围获取元素并携带分数zincrbyopsForZSet().incrementScore(key, member, increment)给元素增加指定分数zcardopsForZSet().size(key)获取有序集合元素总数zcountopsForZSet().count(key, min, max)获取指定分数范围的元素个数zremopsForZSet().remove(key, member)删除有序集合中的指定元素zremrangebyrankopsForZSet().removeRange(key, start, stop)按排名范围删除元素zremrangebyscoreopsForZSet().removeRangeByScore(key, min, max)按分数范围删除元素zrankopsForZSet().rank(key, member)升序获取元素的排名从 0 开始zrevrankopsForZSet().reverseRank(key, member)降序获取元素的排名从 0 开始总结SpringBoot 中操作 Redis Sorted Set 的核心套路是 stringRedisTemplate.opsForZSet().xxx()。代码package com.qcby.springbootredis; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ZSetOperations; import java.util.Set; import java.util.stream.Collectors; SpringBootTest public class SortedSetTest { Autowired private StringRedisTemplate stringRedisTemplate; Test public void testSortedSetCoreCommands() { String scoreboardKey scoreboard; String hackersKey hackers; String zsetKey zset; try { // 10.2.1 增加元素ZADD 获取元素分数ZSCORE Boolean add1 stringRedisTemplate.opsForZSet().add(scoreboardKey, zhangsan, 80); stringRedisTemplate.opsForZSet().add(scoreboardKey, lisi, 89); stringRedisTemplate.opsForZSet().add(scoreboardKey, wangwu, 94); System.out.println(新增 zhangsan add1); Boolean add2 stringRedisTemplate.opsForZSet().add(scoreboardKey, lisi, 97); System.out.println(更新 lisi 分数 add2); Double lisiScore stringRedisTemplate.opsForZSet().score(scoreboardKey, lisi); System.out.println(lisi 的分数 lisiScore); // 10.2.2 获得排名范围的元素列表ZRANGE / ZREVRANGE SetString zrangeResult stringRedisTemplate.opsForZSet().range(scoreboardKey, 0, 2); System.out.println(升序排名 0-2 元素 zrangeResult); SetZSetOperations.TypedTupleString zrangeWithScores stringRedisTemplate.opsForZSet().rangeWithScores(scoreboardKey, 0, 1); SetString withScoresStr zrangeWithScores.stream() .map(t - t.getValue() ( t.getScore() )) .collect(Collectors.toSet()); System.out.println(升序带分数 withScoresStr); SetString zrevrangeResult stringRedisTemplate.opsForZSet().reverseRange(scoreboardKey, 0, 2); System.out.println(降序排名 0-2 元素 zrevrangeResult); // 10.2.3 获得指定分数范围的元素ZRANGEBYSCORE SetZSetOperations.TypedTupleString zrangeByScore1 stringRedisTemplate.opsForZSet().rangeByScoreWithScores(scoreboardKey, 90, 97); SetString scoreWithStr1 zrangeByScore1.stream() .map(t - t.getValue() ( t.getScore() )) .collect(Collectors.toSet()); System.out.println(分数 90-97 带分数 scoreWithStr1); // 半开区间 90 score 97 SetZSetOperations.TypedTupleString zrangeByScore2 stringRedisTemplate.opsForZSet().rangeByScoreWithScores(scoreboardKey, 90, 96.999); SetString scoreWithStr2 zrangeByScore2.stream() .map(t - t.getValue() ( t.getScore() )) .collect(Collectors.toSet()); System.out.println(分数 90-(97) 带分数 scoreWithStr2); // 分页 LIMIT 1 2 SetString zrangeByScore3 stringRedisTemplate.opsForZSet().rangeByScore(scoreboardKey, 70, 100, 1, 2); System.out.println(分数 70-100 分页 zrangeByScore3); // 10.2.4 增加元素分数ZINCRBY 集合元素数量ZCARD 分数范围元素个数ZCOUNT Double newLisiScore stringRedisTemplate.opsForZSet().incrementScore(scoreboardKey, lisi, 4); System.out.println(lisi 加4分后 newLisiScore); Long zcardCount stringRedisTemplate.opsForZSet().size(scoreboardKey); System.out.println(集合元素个数 zcardCount); Long zcount stringRedisTemplate.opsForZSet().count(scoreboardKey, 80, 90); System.out.println(分数 80-90 元素个数 zcount); stringRedisTemplate.opsForZSet().add(hackersKey, Alan Kay, 1940); stringRedisTemplate.opsForZSet().add(hackersKey, Richard Stallman, 1953); stringRedisTemplate.opsForZSet().add(hackersKey, Yukihiro Matsumoto, 1965); stringRedisTemplate.opsForZSet().add(hackersKey, Claude Shannon, 1916); stringRedisTemplate.opsForZSet().add(hackersKey, Linus Torvalds, 1969); stringRedisTemplate.opsForZSet().add(hackersKey, Alan Turing, 1912); SetString hackersZrange stringRedisTemplate.opsForZSet().range(hackersKey, 0, -1); System.out.println(hackers 升序 hackersZrange); SetString hackersZrevrange stringRedisTemplate.opsForZSet().reverseRange(hackersKey, 0, -1); System.out.println(hackers 降序 hackersZrevrange); // 清空当前数据库 stringRedisTemplate.getConnectionFactory().getConnection().flushDb(); System.out.println(清空数据库成功); // zset 示例 stringRedisTemplate.opsForZSet().add(zsetKey, hello, 10.1); stringRedisTemplate.opsForZSet().add(zsetKey, :, 10.0); stringRedisTemplate.opsForZSet().add(zsetKey, zset, 9.0); stringRedisTemplate.opsForZSet().add(zsetKey, zset!, 11.0); Long zsetCard stringRedisTemplate.opsForZSet().size(zsetKey); System.out.println(zset 元素个数 zsetCard); Double zsetScore stringRedisTemplate.opsForZSet().score(zsetKey, zset); System.out.println(zset 的分数 zsetScore); SetString zsetZrange stringRedisTemplate.opsForZSet().range(zsetKey, 0, -1); System.out.println(zset 升序 zsetZrange); Long zremCount stringRedisTemplate.opsForZSet().remove(zsetKey, zset!); System.out.println(删除 zset! zremCount); Long zsetZcount stringRedisTemplate.opsForZSet().count(zsetKey, 9.5, 10.5); System.out.println(分数 9.5-10.5 元素个数 zsetZcount); SetString zsetFinal stringRedisTemplate.opsForZSet().range(zsetKey, 0, -1); System.out.println(zset 删除后 zsetFinal); // 10.2.5 其他命令ZREMRANGEBYRANK / ZREMRANGEBYSCORE / ZRANK / ZREVRANK stringRedisTemplate.opsForZSet().add(scoreboardKey, zhangsan, 80); stringRedisTemplate.opsForZSet().add(scoreboardKey, lisi, 97); stringRedisTemplate.opsForZSet().add(scoreboardKey, wangwu, 94); Long zremByRankCount stringRedisTemplate.opsForZSet().removeRange(scoreboardKey, 0, 1); System.out.println(按排名删除 0-1 zremByRankCount); SetString scoreboardAfterRankDel stringRedisTemplate.opsForZSet().range(scoreboardKey, 0, -1); System.out.println(删除后元素 scoreboardAfterRankDel); stringRedisTemplate.opsForZSet().add(scoreboardKey, zhangsan, 84); Long zremByScoreCount stringRedisTemplate.opsForZSet().removeRangeByScore(scoreboardKey, 80, 100); System.out.println(按分数删除 80-100 zremByScoreCount); stringRedisTemplate.opsForZSet().add(scoreboardKey, zhangsan, 80); stringRedisTemplate.opsForZSet().add(scoreboardKey, lisi, 97); Long lisiRank stringRedisTemplate.opsForZSet().rank(scoreboardKey, lisi); System.out.println(lisi 升序排名 lisiRank); Long zhangsanRevRank stringRedisTemplate.opsForZSet().reverseRank(scoreboardKey, zhangsan); System.out.println(zhangsan 降序排名 zhangsanRevRank); } catch (Exception e) { e.printStackTrace(); } } }