Spring Data Redis 中的 ZSetOperations 接口定义了操作 Redis 中 zset(sorted set 有序集合)数据类型数据的接口。
Redis 中 zset(有序集合)和 set(集合)一样也是 string 类型元素的集合,且不允许重复的成员。不同的是 zset 每个元素都会关联一个 double 类型的分数。Redis 通过分数来为集合中的成员进行从小到大的排序。
注意:zset 有序集合的成员是唯一的,但分数(score)却可以重复。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。 集合中最大的成员数为 2^32 - 1(4294967295, 每个集合可存储 40 多亿个成员)。
在 Spring Data Redis 中,可以通过 RedisTemplate 的 opsForZSet() 方法获取,如下:
ZSetOperations<String,String> ops = redisTemplate.opsForZSet();
使用 add() 方法向键的有序集合添加元素,方法定义如下:
Long add(K key, Set<ZSetOperations.TypedTuple<V>> tuples) 将元组添加到已排序的键集,或者如果它已经存在,则更新它的分数。
Boolean add(K key, V value, double score) 将值添加到已排序的集合key,如果已存在,则更新其分数。
示例:
ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 添加三个值到有序集合 ops.add("zset-key", "value1", 1.0D); ops.add("zset-key", "value2", 3.0D); ops.add("zset-key", "value3", 2.0D); Set<ZSetOperations.TypedTuple<String>> valSet = new HashSet<>(); valSet.add(new DefaultTypedTuple("value4", 3.0D)); valSet.add(new DefaultTypedTuple("value5", 4.0D)); long count = ops.add("zset-key", valSet); System.out.println("count=" + count); // 迭代有序集合 Cursor<ZSetOperations.TypedTuple<String>> cursor = ops.scan("zset-key", ScanOptions.scanOptions().match("*").build()); while(cursor.hasNext()) { ZSetOperations.TypedTuple<String> item = cursor.next(); System.out.println(item.getValue() + ", " + item.getScore()); }
运行示例,输出结果:
count=2 value1, 1.0 value3, 2.0 value2, 3.0 value4, 3.0 value5, 4.0
使用 count() 方法获取元素 score 在指定范围内的元素个数,方法定义如下:
Long count(K key, double min, double max) 计算排序集中得分 score 介于 min 和 max 之间的元素数。
示例:
ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 1.0D); ops.add("zset-key", "value2", 2.0D); ops.add("zset-key", "value3", 3.0D); ops.add("zset-key", "value4", 4.0D); ops.add("zset-key", "value5", 5.0D); // 获取集合元素 score 处于 2.0 和 3.0 之间元素的个数 Long count = ops.count("zset-key", 2.0D, 3.0D); System.out.println("count=" + count);
运行示例,输出结果:
count=2
使用 incrementScore() 方法对指定键的分数进行递增计算,方法定义如下:
Double incrementScore(K key, V value, double delta) 对键 key 中的 value 值的分数增加 delta。
示例:
ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 1.0D); // 将 value1 的分数加2 ops.incrementScore("zset-key", "value1", 2.0D); // 迭代有序集合 Cursor<ZSetOperations.TypedTuple<String>> cursor = ops.scan("zset-key", ScanOptions.scanOptions().match("*").build()); while(cursor.hasNext()) { ZSetOperations.TypedTuple<String> item = cursor.next(); System.out.println(item.getValue() + ", " + item.getScore()); }
运行示例,输出结果:
value1, 3.0
使用 intersectAndStore() 方法可以计算给定多个集合之间的交集,并将结果保存到目标集合中。方法定义如下:
Long intersectAndStore(K key, Collection<K> otherKeys, K destKey) 计算 key 和 otherKeys 排序集合的交集,并将结果存储在 destKey 集合中。
Long intersectAndStore(K key, K otherKey, K destKey) 计算 key 和 otherKey 排序集合的交集,并将结果存储在 destKey 集合中。
示例:
Set<String> values; ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 1.0D); ops.add("zset-key", "value2", 1.0D); ops.add("zset-key", "value3", 1.0D); ops.add("zset-key2", "value2", 1.0D); ops.add("zset-key2", "value4", 1.0D); ops.add("zset-key3", "value2", 1.0D); ops.add("zset-key3", "value3", 1.0D); ops.add("zset-key3", "value5", 1.0D); // 计算 zset-key 和 zset-key2 集合的交集,且将结果存储到 zset-result 中 Long count = ops.intersectAndStore("zset-key", "zset-key2", "zset-result"); System.out.println("count=" + count); values = ops.range("zset-result", 0, -1); System.out.println(Arrays.toString(values.toArray())); // 计算 zset-key、zset-key2 和 zset-key3 集合的交集,且将结果存储到 zset-result 中 count = ops.intersectAndStore("zset-key", Arrays.asList("zset-key2", "zset-key3"), "zset-result"); System.out.println("count=" + count); values = ops.range("zset-result", 0, -1); System.out.println(Arrays.toString(values.toArray()));
运行示例,输出结果:
count=1 [value2] count=1 [value2]
使用 range() 方法可以获取指定范围的元素,方法定义如下:
Set<V> range(K key, long start, long end) 从已排序集合中获取 start 和 end 之间的元素。
Set<V> rangeByLex(K key, RedisZSetCommands.Range range) 从 ZSET 获取元素,其值介于 RedisZSetCommands.Range.getMin() 和 RedisZSetCommands.Range.getMax() 之间。
Set<V> rangeByLex(K key, RedisZSetCommands.Range range, RedisZSetCommands.Limit limit) 从 ZSET 获取 n 个元素,其中 n = RedisZSetCommands.Limit.getCount(),从 RedisZSetCommands.Limit.getOffset() 开始,元素值介于 RedisZSetCommands.Range.getMin() 和 RedisZSetCommands.Range.getMax()。
示例:
Set<String> values; ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "A", 1.0D); ops.add("zset-key", "B", 2.0D); ops.add("zset-key", "C", 3.0D); ops.add("zset-key", "D", 4.0D); ops.add("zset-key", "C1", 5.0D); ops.add("zset-key", "D1", 6.0D); // 迭代所有元素 values = ops.range("zset-key", 0, -1); System.out.println(Arrays.toString(values.toArray())); // 使用非score分数排序取值 RedisZSetCommands.Range range = new RedisZSetCommands.Range() .gte("C") .lt("E"); values = ops.rangeByLex("zset-key", range); System.out.println(Arrays.toString(values.toArray()));
运行示例,输出结果:
[A, B, C, D, C1, D1] [C, D, C1, D1]
Set<V> rangeByScore(K key, double min, double max) 从 zset 中获取分数在 min 和 max 之间的元素
Set<V> rangeByScore(K key, double min, double max, long offset, long count) 从 zset 中获取分数在 min 和 max 之间的元素,从 offset 开始获取 count 个元素。
Set<ZSetOperations.TypedTuple<V>> rangeByScoreWithScores(K key, double min, double max) 从 zset 中获取分数在 min 和 max 之间的元素的 RedisZSetCommands.Tuples。
Set<ZSetOperations.TypedTuple<V>> rangeByScoreWithScores(K key, double min, double max, long offset, long count) 从 zset 中获取分数在 min 和 max 之间的元素的 RedisZSetCommands.Tuples,仅返回从 offset 开始 count 个元素。
Set<ZSetOperations.TypedTuple<V>> rangeWithScores(K key, long start, long end) 从 zset 中获取 start 和 end 之间的 RedisZSetCommands.Tuples。
示例:
Set<String> values; ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 1.0D); ops.add("zset-key", "value2", 2.0D); ops.add("zset-key", "value3", 3.0D); ops.add("zset-key", "value4", 4.0D); ops.add("zset-key", "value5", 5.0D); ops.add("zset-key", "value6", 6.0D); // 获取分数在 2 和 4 之间的元素 values = ops.rangeByScore("zset-key", 2,4); System.out.println(Arrays.toString(values.toArray())); // 获取分数在 2 和 4 之间的元素,从下标2开始,获取一个元素 values = ops.rangeByScore("zset-key", 2, 4, 2, 1); System.out.println(Arrays.toString(values.toArray())); // 获取分数在 2 和 4 之间的元素,包含元素的分数 Set<ZSetOperations.TypedTuple<String>> typedTuples = ops.rangeByScoreWithScores("zset-key", 2, 4); for(ZSetOperations.TypedTuple<String> typedTuple : typedTuples) { System.out.println(typedTuple.getValue() + " --> " + typedTuple.getScore()); }
运行示例,输出结果:
[value2, value3, value4] [value4] value2 --> 2.0 value3 --> 3.0 value4 --> 4.0
使用 rank() 方法可以获取指定键中指定元素的下标,方法定义如下:
Long rank(K key, Object o) 确定 zset 中指定值值的元素的索引。
Long reverseRank(K key, Object o) 当元素的得分从高到低排序时,确定排序集中指定值的元素的索引。
示例:
ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 1.0D); ops.add("zset-key", "value2", 2.0D); ops.add("zset-key", "value3", 3.0D); ops.add("zset-key", "value4", 4.0D); ops.add("zset-key", "value5", 5.0D); Long rank = ops.rank("zset-key", "value2"); System.out.println("rank=" + rank); rank = ops.reverseRank("zset-key", "value2"); System.out.println("rank=" + rank);
运行示例,输出结果:
rank=1 rank=3
使用 remove() 方法将值从指定键中移除,方法定义如下:
Long remove(K key, Object... values) 从指定的 zset 中移除 values
Long removeRange(K key, long start, long end) 从指定的 zset 中移除 start 到 end 之间的元素
Long removeRangeByScore(K key, double min, double max) 从指定的 zset 中移除分数位于 start 到 end 之间的元素
示例:
Set<String> values; Long count; ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 1.0D); ops.add("zset-key", "value2", 2.0D); ops.add("zset-key", "value3", 3.0D); ops.add("zset-key", "value4", 4.0D); ops.add("zset-key", "value5", 5.0D); ops.add("zset-key", "value6", 6.0D); // 从 zset-key 集合中删除 value1 和 value2 元素 count = ops.remove("zset-key", "value1", "value5"); System.out.println("count=" + count); values = ops.range("zset-key", 0, -1); System.out.println(Arrays.toString(values.toArray())); // 从 zset-key 集合中删除下标位于 1~2 之间的元素 count = ops.removeRange("zset-key", 1, 2); System.out.println("count=" + count); values = ops.range("zset-key", 0, -1); System.out.println(Arrays.toString(values.toArray())); // 从 zset-key 集合中删除分数大于等于 6~10 的元素 count = ops.removeRangeByScore("zset-key", 6, 10); System.out.println("count=" + count); values = ops.range("zset-key", 0, -1); System.out.println(Arrays.toString(values.toArray()));
运行示例,输出结果:
count=2 [value2, value3, value4, value6] count=2 [value2, value6] count=1 [value2]
Set<V> reverseRange(K key, long start, long end) 从排序集合中返回 start 到 end 之间的元素,元素从高到低的顺序进行排序。
Set<V> reverseRangeByScore(K key, double min, double max) 从排序集中返回分数位于 min 到 max 之间的元素,元素从高到低的顺序进行排序。
Set<V> reverseRangeByScore(K key, double min, double max, long offset, long count) 从排序集合中查询分数位于 min 和 max 之间的元素,然后从 offset 下标开始返回 count 个元素,元素按高->低的顺序排列。
Set<ZSetOperations.TypedTuple<V>> reverseRangeByScoreWithScores(K key, double min, double max) 从排序集合中返回分数介于 min 和 max 之间的 RedisZSetCommands.Tuple 元素,元素按高->低的顺序排列。
Set<ZSetOperations.TypedTuple<V>> reverseRangeByScoreWithScores(K key, double min, double max, long offset, long count) 从排序集合中查询分数介于 min 和 max 之间的 RedisZSetCommands.Tuple 元素,然后从 offset 下标开始返回 count 个元素,元素按高->低的顺序排列。
Set<ZSetOperations.TypedTuple<V>> reverseRangeWithScores(K key, long start, long end) 从排序集合中返回下标介于 start 到 end 之间的元素,元素按照高->低进行排序。
示例:
Set<String> values; Set<ZSetOperations.TypedTuple<String>> typedTuples; ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 10.0D); ops.add("zset-key", "value2", 20.0D); ops.add("zset-key", "value3", 30.0D); ops.add("zset-key", "value4", 40.0D); ops.add("zset-key", "value5", 50.0D); values = ops.reverseRange("zset-key", 2, 4); System.out.println(Arrays.toString(values.toArray())); typedTuples = ops.reverseRangeWithScores("zset-key", 1, 2); for(ZSetOperations.TypedTuple<String> typedTuple : typedTuples) { System.out.println(typedTuple.getValue() + " --> " + typedTuple.getScore()); }
运行示例,输出结果:
[value3, value2, value1] value4 --> 40.0 value3 --> 30.0
使用 scan() 方法迭代指定集合,方法定义如下:
Cursor<ZSetOperations.TypedTuple<V>> scan(K key, ScanOptions options) 迭代指定键的 zset 集合
示例:
ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 1.0D); ops.add("zset-key", "value2", 2.0D); ops.add("zset-key", "value3", 3.0D); // 迭代有序集合 Cursor<ZSetOperations.TypedTuple<String>> cursor = ops.scan("zset-key", ScanOptions.scanOptions().match("*").build()); while(cursor.hasNext()) { ZSetOperations.TypedTuple<String> item = cursor.next(); System.out.println(item.getValue() + ", " + item.getScore()); }
运行示例,输出结果:
value1, 1.0 value2, 2.0 value3, 3.0
使用 score() 方法获取指定元素的分数,方法定义如下:
Double score(K key, Object o) 使用键 key 从排序集中获取具有给定值的元素的分数。
示例:
ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 1.0D); ops.add("zset-key", "value2", 2.0D); ops.add("zset-key", "value3", 3.0D); // 获取元素 value2 的分数 Double score = ops.score("zset-key", "value2"); System.out.println("score=" + score
运行示例,输出结果:
score=2.0
使用 size() 可以返回指定集合的大小,方法定义如下:
Long size(K key) 返回给定键存储的有序集合的元素数
Long zCard(K key) 返回给定键存储的有序集合的大小
示例:
ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 1.0D); ops.add("zset-key", "value2", 2.0D); ops.add("zset-key", "value3", 3.0D); ops.add("zset-key", "value4", 4.0D); // 获取集合大小 Long size = ops.size("zset-key"); System.out.println("size=" + size); size = ops.zCard("zset-key"); System.out.println("size=" + size);
运行示例,输出结果:
size=4 size=4
使用 unionAndStore() 方法可以将多个集合的元素进行合并,然后将合并结果保存到目标键。方法定义如下:
Long unionAndStore(K key, Collection<K> otherKeys, K destKey) 将 key 和 otherKeys 集合的元素合并在一起,然后保存到 destKey 集合。
Long unionAndStore(K key, K otherKey, K destKey) 将 key 和 otherKeys 集合的元素合并在一起,然后保存到 destKey 集合。
示例:
Set<String> values; ZSetOperations<String,String> ops = redisTemplate.opsForZSet(); // 初始化数据 ops.add("zset-key", "value1", 10.0D); ops.add("zset-key", "value2", 20.0D); ops.add("zset-key2", "value2", 30.0D); ops.add("zset-key2", "value3", 40.0D); ops.add("zset-key2", "value4", 50.0D); ops.add("zset-key3", "value2", 60.0D); ops.add("zset-key3", "value5", 70.0D); // 合并 zset-key、zset-key2 集合元素,然后保存到 zset-result ops.unionAndStore("zset-key", "zset-key2", "zset-result"); values = ops.range("zset-result", 0, -1); System.out.println(Arrays.toString(values.toArray())); // 合并 zset-key、zset-key2 和 zset-key3 三个集合元素,然后保存到 zset-result ops.unionAndStore("zset-key", Arrays.asList("zset-key2", "zset-key3"), "zset-result"); values = ops.range("zset-result", 0, -1); System.out.println(Arrays.toString(values.toArray()));
运行示例,输出结果:
[value1, value3, value2, value4] [value1, value3, value4, value5, value2]