Redis数据结构--有序集合ZSet
和无序集合的主要区别在于每一个元素除了值之外,还会多一个分数
1、分数是一个浮点数,在 Java 中是使用双精度表示的,根据分数, Redis 就可以支持对分数从小到大或者从大到小的排序
2、和无序集合一样,对于每一个元素都是唯一的 ,但是对于不同元素而言,它的分数可以一样
3、元素也是 String 数据类型,也是一种基于 hash 的存储结构。
4、集合是通过哈希表实现的,所以添加、删除、 查找的复杂度都是 0(1)
5、集合中最大的成员数为 2的32次方减 1 ( 40 多亿个成员)
有序集合的数据结构

有序集合是依赖 key 标示是属于哪个集合,依赖分数进行排序,所以值和分数是必须的,而实际上不仅可以对分数进行排序,在满足一定的条件下,也可以对值进行排序 。






先介绍一个主要的接口一一TypedTuple,它不是一个普通的接口,而一个内部接口.org.springframework . data. redis.core .ZSetOperations 接口的内部接口,它定义了两个方

- getValue()是获取值, getScore()是获取分数,但是它只是一个接口,而不是一个实现类
- spring-data-red is 提供了 一个默认的实现类一DefaultTypedTuple

在默认的情况下 Spring 就会把带有分数的有序集合的值和分数封装到这个类中 ,这样就可以通过这个类对象读取对应的值和分数了 .
Spring 不仅对有序集合元素封装,而且对范围也进行了封装,方便使用.它是使用接口 org.springframe.work.data.redis.connection.RedisZSetCommands 下的内部类 Range 进行封装的,它有一个静态的 range()方法,使用它就可以生成一个 Range 对象了,只是要清楚 Range对象的几个方法才行.
// 设置大于等于 min public Range gte(Object min) // 设置大于 min public Range gt(Object min) // 设置小于等于 max public Range lte(Object max) // 设置小于 max public Range lt(Object max)
package com.artisan.redis.baseStructure.zset; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; import org.springframework.data.redis.core.DefaultTypedTuple; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ZSetOperations; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; public class SpringRedisZSetDemo { private static final String ZSET1 = "zset1"; private static final String ZSET2 = "zset2"; @SuppressWarnings({ "unchecked", "rawtypes" }) public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:spring/spring-redis-zset.xml"); RedisTemplate redisTemplate = (RedisTemplate) ctx.getBean("redisTemplate"); // 方便测试,清空数据 redisTemplate.delete(ZSET1); redisTemplate.delete(ZSET2); // Spring 提供接口 TypedTuple 操作有序集合 Set<TypedTuple> set1 = new HashSet<ZSetOperations.TypedTuple>(); Set<TypedTuple> set2 = new HashSet<ZSetOperations.TypedTuple>(); // 构造数据 // 127.0.0.1:6379> // # zadd key score1 value1 [score2 value2 …] 向有序集合zset1 ,增加9个成员 // >ZADD zset1 1 x1 2 x2 3 x3 4 x4 5 x5 6 x6 7 x7 8 x8 9 x9 // (integer) 9 // # zadd key score1 value1 [score2 value2 …] 向有序集合zset2 ,增加9个成员 // > ZADD zset2 1 y1 2 x2 3 y3 4 x4 5 y5 6 x6 7 y7 8 x8 9 y9 // (integer) 9 int j = 9; String value1, value2 = null; double score1, score2 = 0.0; for (int i = 1; i <= 9; i++) { // 计算分数和值 score1 = Double.valueOf(i); value1 = "x" + i; if (j > 0) { score2 = Double.valueOf(j); value2 = j % 2 == 1 ? "y" + j : "x" + j; j--; } // 使用 Spring提供的默认 TypedTuple-DefaultTypedTuple TypedTuple typedTuplel = new DefaultTypedTuple(value1,score1); set1.add(typedTuplel); TypedTuple typedTuple2 = new DefaultTypedTuple(value2,score2); set2.add(typedTuple2); } // 写入redis redisTemplate.opsForZSet().add(ZSET1, set1); redisTemplate.opsForZSet().add(ZSET2, set2); // 统计总数 Long size = redisTemplate.opsForZSet().size(ZSET1); System.out.println(ZSET1 + "的size为" + size); // 计分数为 score ,那么下面的方法就是求 3<=score<=6 的元素 Long count = redisTemplate.opsForZSet().count(ZSET1, 3, 6); System.out.println(ZSET1 + "中3<=score<=6 的count为" + count); // 从下标一开始截驭 5 个元素,但是不返回分数 , 每一个元素是 String Set set = redisTemplate.opsForZSet().range(ZSET1, 1, 5); printSet(set); // 截取集合所有元素,并且对集合按分数排序,并返回分数 , 每一个元素是 TypedTuple Set<TypedTuple> typedTuples = redisTemplate.opsForZSet().rangeWithScores(ZSET1, 0, -1); printTypedTuple(typedTuples); // 将 zsetl 和 zset2 两个集合的交集放入集合 inter_zset size = redisTemplate.opsForZSet().intersectAndStore(ZSET1, ZSET2, "inter_zset"); System.out.println("inter_zset size:" + size); // 查看交集inter_zset中的数据 set = redisTemplate.opsForZSet().range("inter_zset", 0, redisTemplate.opsForZSet().size("inter_zset")); printSet(set); // 区间 Range range = Range.range(); range.lt("x8");// 小于 range.gt("x1");// 大于 set = redisTemplate.opsForZSet().rangeByLex(ZSET1, range); printSet(set); range.lte("x8");// 小于等于 range.gte("x1");// 大于等于 set = redisTemplate.opsForZSet().rangeByLex(ZSET1, range); printSet(set); // 限制返回个数 Limit limit = Limit.limit(); // 限制返回个数 limit.count(4); // 限制从第2个开始截取 limit.offset(2); // 求区间内的元素,并限制返回 4 条 set = redisTemplate.opsForZSet().rangeByLex(ZSET1, range, limit); printSet(set); // 求排行,排名第 1 返回 0 ,第 2 返回 1 Long rank = redisTemplate.opsForZSet().rank(ZSET1, "x4"); System.out.println("rank=" + rank); // 删除元素 , 返回删除个数 size = redisTemplate.opsForZSet().remove(ZSET1, "x5", "x6"); System.out.println("remove " + size + " 个元素"); // 按照排行删除从 0 开始算起,这里将删除第排名第 2 和第 3 的元素 size = redisTemplate.opsForZSet().removeRange(ZSET1, 1, 2); System.out.println("removeRange " + size + " 个元素"); // 获取所有集合的元索和分数 , 以 -1 代表全部元素 typedTuples = redisTemplate.opsForZSet().rangeWithScores(ZSET1, 0, -1); printTypedTuple(typedTuples); // 删除指定的元素 size = redisTemplate.opsForZSet().remove(ZSET2, "y3", "y5"); System.out.println("remove " + size + " 个元素"); // 给集合中的一个元素的分数加上 11 Double double1 = redisTemplate.opsForZSet().incrementScore(ZSET2, "y1", 11); printTypedTuple(redisTemplate.opsForZSet().rangeWithScores(ZSET2, 0, redisTemplate.opsForZSet().size(ZSET2))); // 从大到小排列 typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(ZSET2, 0, 99); printTypedTuple(typedTuples); } @SuppressWarnings("rawtypes") public static void printTypedTuple(Set<TypedTuple> typedTuples) { if (typedTuples != null && typedTuples.isEmpty()) { return; } Iterator<TypedTuple> iterator = typedTuples.iterator(); while (iterator.hasNext()) { TypedTuple typedTuple = iterator.next(); System.out.println("{value =" + typedTuple.getValue() + ", score=" + typedTuple.getScore() + "}"); } System.out.println("----------------------"); } @SuppressWarnings("rawtypes") public static void printSet(Set set) { if (set != null && set.isEmpty()) { return; } Iterator iterator = set.iterator(); while (iterator.hasNext()) { Object val = iterator.next(); System.out.println(val + "\t"); } System.out.println("----------------------"); } }
浙公网安备 33010602011771号