Spring Data Redis 教程

ZSetOperations 操作接口

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]


说说我的看法
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号