Redis数据结构---------有序集合
- 有序集合和集合类似,只是说它是有序的,和无序集合的主要区别在于每一个元素除了值之外,它还会多一个分数。分数是一个浮点数,在Java中是 使用双精度表示的,对于每一个元素都是唯一的,但是对于不同元素而言,它的分数可以一样。元素也是String数据类型,也是一种基于hash的存储 结构。集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是O(1)。集合中最大的成员数为2^32 - 1,有序集合的数据结构。有序集合是依赖 key标示它是属于哪个集合,依赖分数进行排序,所以值和分数是必须的,而实际上不仅可以对分数进行排序,在满足一定条件下,也可以对值进行排序。
Reids基础命令
- 有序集合和无序集合的命令是接近的,只是在这些命令的基础上,会增加对于排序的操作,这些是我们在使用的时候需要注意的细节。下面讲解这些常 用的有序集合的部分命令。有些时候Redis借助数学区间的表示方法来表示包含或者不包含,比如在数学的区间表示中,[2,5]表示包含2,但是不包含 5的区间。
Redis基础命令
1 ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— 2 命令 说明 备注 3 zadd key score1 value1 [score1 value2...] 向有序集合的key,增加一个或者多个成员 如果还不存在对应key,则创建键为key的有序集合 4 5 zcard key 获取有序集合的成员数 ------------ 6 7 zcount key min max 根据分数返回对应的成员列表 默认为包含min和max值,采用数学区间表示的方法,如果需要不包含, 8 则在分数前面加入"(",注意注意不支持"【"表示。 9 zincrby key increment member 给有序集合成员值为member的分数增加increment ------------ 10 11 zinterstore desKey numKeys key1[key2 key3....] 求多个有序集合的交集,并且将结果保存到desKey中 numKeys是一个整数,表示多少个有序集合 12 13 zlexcount key min max 求有序集合key成员值在min和max的范围 这里范围为key的成员值,Redis借助数学区间的表示方法,"【"表示 14 包含该值,"("表示不包含该值 15 zrange key start stop [withscores] 按照分值的大小(从小到大)返回成员,加入start和stop参 这里记集合最大长度为len,则Redis会将集合排序后,形成一个从0到 16 数,可以截取某一段返回。如果输入可选项wirhscores,则连 len-1的下标,然后根据start和stop控制的下标(包含start和stop)返回 17 内分数返回 18 zrank key menber 按从小到大有序集合的排行 排名第一的为0,第二的为1...... 19 20 zrangebylex key min max [limit offset count] 根据值的大小,从小到大排序,min为最小值,max为最大值; 这里范围为key的成员值,Redis借助数学区间的表示方法,"["表示包含该值, 21 limit选项可选,当Redis求出范围集合后,会生产下标0到n, "("表示不包含该值。 22 然后根据偏移量offset和限定返回数count,返回对应的成员 23 zrangebyscore key min max [withscores] 根据分数大小,从小到大求取范围,选项withscores和limit 根据分析求取集合的范围。这里默认包含min和max,如果不想包含,则在参数前 24 [limit offset coount] 请参考zrange命令和zrangebylex说明 加入"("表示不包含该值。 25 26 zremrangebyscore key start stop 根据分数区间进行删除 按照socre进行排序,然后排除0到len-1的下标,然后根据start和stop进行删除。 27 28 zremrangebyrank key start stop 按照分数排行从小到大的排序删除,从0开始计算 ----------------- 29 30 zremrangebylex key min max 按照值的分布进行删除 ------------------ 31 32 zrevrange key start stop [withscores] 从大到小的按分数排序,参数请参见zrange 与zrange相同,只是排序是从大到小 33 34 zrevrangebyscore key max min [withscores] 从大到小的按分数排序,参数请参见zrangebyscore 与zrangebyscore相同,只是排序从大到小 35 36 zrevrank key member 按从大到小的顺序,求元素的排行 排名第一位0,第二位1....... 37 38 zscore key member 返回成员的分数值 返回成员的分数 39 40 zunionstore desKey numKeys key1 [key2 key3 key4...] 求多个有序集合的并集,其中numKeys是有序集合的个数 ------- 41 42 ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
spring-data-redis对有序集合的封装
-
在Spring中使用Redis的有序集合,需要注意的是Spring对Redis有序集合的元素的值和分数的范围(Range)和限制(Limit)进行了封装,在演示如 何使用Spring操作有序集合前要进一步了解它的封装。
-
先介绍一个主要的接口----TypedTuple,它不是一个普通的接口,而是一个内部接口它是org.spingframework.data.redis.core.ZSetOperations 接口的内部接口,它定义了两个方法。
public interface ZSetOperations<K, V> {
1public interface TypedTuple<V> extends Comparable<ZSetOperations.TypedTuple<V>> { 2 V getValue(); 3 4 Double getScore(); 5 } 6}
-
这里getValue()是获取值,而getScore()是获取分数,但是它只是一个接口,而不是一个实现类。spring-data-redis提供了一个默认的实现类-- DefaultTypedTuple,同样它会实现TypeTuple接口,在默认的情况下Spring就会把带有分数的有序集合的值和分数封装到这个类中,这样就可以通 过这个类对象读取对应的值和分数了。
-
Spring不仅对有序集合元素封装,而且对范围也进行了封装,方便使用。它是使用接口org.springframework.data.redis.connection.RedisZ- SetCommands下的内部类Range进行封装的,它有一个静态的range()方法,使用它就可以生成一个Range对象了,只是要清楚Range对象的几个方法 才行。 伪代码:
//设置大于等于min public Range get(Object min) //设置大于min public Range gt(Object min) //设置小于等于max public Range lte(Object max) //设置小于max public Reange lt(Objectt max)
使用Spring操作有序集合
- 在测试代码前,要把RedisTemplate的keySerializer和valueSerializer属性都修改为字符串序列化器StringRedisSerializer,然后就可以测 试代码。
通过Spring操作有序集合
1 /** 2 * 通过Spring操作有序集合 3 */ 4 @Test 5 public void testZset() { 6 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); 7 RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class); 8 //Spring提供接口TypedTuple操作有序集合 9 Set<TypedTuple> set1 = new HashSet<TypedTuple>(); 10 Set<TypedTuple> set2 = new HashSet<TypedTuple>(); 11 int j = 9; 12 for (int i = 1; i <= 9; i++) { 13 //计算分数和值 14 Double score1 = Double.valueOf(i); 15 String value1 = "x" + i; 16 Double score2 = Double.valueOf(j); 17 String value2 = j % 2 == 1 ? "Y" + j : "X" + j; 18 //使用Spring提供的默认TypedTuple----DefaultTypedTuple 19 TypedTuple typedTuple1 = new DefaultTypedTuple(value1, score1); 20 set1.add(typedTuple1); 21 TypedTuple typedTuple2 = new DefaultTypedTuple(value2, score2); 22 set2.add(typedTuple2); 23 } 24 //将元素插入有序集合zset1 25 redisTemplate.opsForZSet().add("zset1", set1); 26 redisTemplate.opsForZSet().add("zset2", set2); 27 //统计总数 28 Long size = null; 29 size = redisTemplate.opsForZSet().zCard("zset1"); 30 //计分数为score,那么下面的方法就是求3<= score <=6 的元素 31 size = redisTemplate.opsForZSet().count("zset1", 3, 6); 32 Set set = null; 33 //从下标一开始截取5个元素,但是不返回分数,每一个元素是String 34 set = redisTemplate.opsForZSet().range("zset1", 1, 5); 35 printSet(set); 36 //截取集合所有元素,并且对集合按分数排序,并返回分数,每一个元素是TypedTuple 37 set = redisTemplate.opsForZSet().rangeWithScores("zset1", 0, -1); 38 printTypedTuple(set); 39 //将zset1和zset2两个集合的交集放入集合inter_zset 40 size = redisTemplate.opsForZSet().intersectAndStore("zset1", "zset2", "inter_zset"); 41 //区间 42 Range range = Range.range(); 43 range.lt("x8"); //小于 44 range.gt("x1"); //大于 45 set = redisTemplate.opsForZSet().rangeByLex("zset1", range); 46 printSet(set); 47 range.lte("x8"); //小于等于 48 range.gte("x1"); //大于等于 49 set = redisTemplate.opsForZSet().rangeByLex("zset1", range); 50 printSet(set); 51 //限制返回个数 52 Limit limit = Limit.limit(); 53 limit.count(4); 54 //限制从第五个开始截取 55 limit.offset(5); 56 //求区间内的元素,并限制返回4条 57 set = redisTemplate.opsForZSet().rangeByLex("zset1", range, limit); 58 printSet(set); 59 //求排行,排名第1返回0,第2返回1 60 Long rank = redisTemplate.opsForZSet().rank("zset1", "x4"); 61 System.err.println("rank = " + rank); 62 //删除元素,返回删除个数 63 size = redisTemplate.opsForZSet().remove("zset1", "x5", "x6"); 64 System.err.println("delete = " + size); 65 //按照排行删除从0开始算起,这里将删除排名第2和第3的元素 66 size = redisTemplate.opsForZSet().removeRange("zset2", 1, 2); 67 //获取所有集合的元素和分数,以-1代表全部元素 68 set = redisTemplate.opsForZSet().rangeWithScores("zset2", 0, -1); 69 printTypedTuple(set); 70 //删除指定的元素 71 size = redisTemplate.opsForZSet().remove("zset2", "y5", "y3"); 72 System.err.println(size); 73 //给集合中的一个元素的分数加上11 74 Double db1 = redisTemplate.opsForZSet().incrementScore("zset1", "x1", 11); 75 redisTemplate.opsForZSet().removeRangeByScore("zset1", 1, 2); 76 set = redisTemplate.opsForZSet().reverseRangeWithScores("zset2", 1, 10); 77 printTypedTuple(set); 78 } 79 80 /** 81 * 打印TypedTuple集合 82 * @param set --Set<TypedTuple> 83 */ 84 private static void printTypedTuple(Set<TypedTuple> set) { 85 if (set != null && set.isEmpty()) 86 return; 87 Iterator iterator = set.iterator(); 88 while (iterator.hasNext()) { 89 TypedTuple val = (TypedTuple) iterator.next(); 90 System.err.print("{value = " + val.getValue() + ", score = " + val.getScore() + "}\n"); 91 } 92 } 93 94 /** 95 * 打印普通集合 96 * @param set 97 */ 98 public static void printSet(Set set) { 99 if (set != null && set.isEmpty()) 100 return; 101 Iterator iterator = set.iterator(); 102 while (iterator.hasNext()) { 103 Object val = iterator.next(); 104 System.out.print(val+ "\t"); 105 } 106 System.out.println(); 107 }