Redis数据结构---------有序集合
- 有序集合和集合类似,只是说它是有序的,和无序集合的主要区别在于每一个元素除了值之外,它还会多一个分数。分数是一个浮点数,在Java中是 使用双精度表示的,对于每一个元素都是唯一的,但是对于不同元素而言,它的分数可以一样。元素也是String数据类型,也是一种基于hash的存储 结构。集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是O(1)。集合中最大的成员数为2^32 - 1,有序集合的数据结构。有序集合是依赖 key标示它是属于哪个集合,依赖分数进行排序,所以值和分数是必须的,而实际上不仅可以对分数进行排序,在满足一定条件下,也可以对值进行排序。
Reids基础命令
- 有序集合和无序集合的命令是接近的,只是在这些命令的基础上,会增加对于排序的操作,这些是我们在使用的时候需要注意的细节。下面讲解这些常 用的有序集合的部分命令。有些时候Redis借助数学区间的表示方法来表示包含或者不包含,比如在数学的区间表示中,[2,5]表示包含2,但是不包含 5的区间。
Redis基础命令
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
命令 说明 备注
zadd key score1 value1 [score1 value2...] 向有序集合的key,增加一个或者多个成员 如果还不存在对应key,则创建键为key的有序集合
zcard key 获取有序集合的成员数 ------------
zcount key min max 根据分数返回对应的成员列表 默认为包含min和max值,采用数学区间表示的方法,如果需要不包含,
则在分数前面加入"(",注意注意不支持"【"表示。
zincrby key increment member 给有序集合成员值为member的分数增加increment ------------
zinterstore desKey numKeys key1[key2 key3....] 求多个有序集合的交集,并且将结果保存到desKey中 numKeys是一个整数,表示多少个有序集合
zlexcount key min max 求有序集合key成员值在min和max的范围 这里范围为key的成员值,Redis借助数学区间的表示方法,"【"表示
包含该值,"("表示不包含该值
zrange key start stop [withscores] 按照分值的大小(从小到大)返回成员,加入start和stop参 这里记集合最大长度为len,则Redis会将集合排序后,形成一个从0到
数,可以截取某一段返回。如果输入可选项wirhscores,则连 len-1的下标,然后根据start和stop控制的下标(包含start和stop)返回
内分数返回
zrank key menber 按从小到大有序集合的排行 排名第一的为0,第二的为1......
zrangebylex key min max [limit offset count] 根据值的大小,从小到大排序,min为最小值,max为最大值; 这里范围为key的成员值,Redis借助数学区间的表示方法,"["表示包含该值,
limit选项可选,当Redis求出范围集合后,会生产下标0到n, "("表示不包含该值。
然后根据偏移量offset和限定返回数count,返回对应的成员
zrangebyscore key min max [withscores] 根据分数大小,从小到大求取范围,选项withscores和limit 根据分析求取集合的范围。这里默认包含min和max,如果不想包含,则在参数前
[limit offset coount] 请参考zrange命令和zrangebylex说明 加入"("表示不包含该值。
zremrangebyscore key start stop 根据分数区间进行删除 按照socre进行排序,然后排除0到len-1的下标,然后根据start和stop进行删除。
zremrangebyrank key start stop 按照分数排行从小到大的排序删除,从0开始计算 -----------------
zremrangebylex key min max 按照值的分布进行删除 ------------------
zrevrange key start stop [withscores] 从大到小的按分数排序,参数请参见zrange 与zrange相同,只是排序是从大到小
zrevrangebyscore key max min [withscores] 从大到小的按分数排序,参数请参见zrangebyscore 与zrangebyscore相同,只是排序从大到小
zrevrank key member 按从大到小的顺序,求元素的排行 排名第一位0,第二位1.......
zscore key member 返回成员的分数值 返回成员的分数
zunionstore desKey numKeys key1 [key2 key3 key4...] 求多个有序集合的并集,其中numKeys是有序集合的个数 -------
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
spring-data-redis对有序集合的封装
在Spring中使用Redis的有序集合,需要注意的是Spring对Redis有序集合的元素的值和分数的范围(Range)和限制(Limit)进行了封装,在演示如 何使用Spring操作有序集合前要进一步了解它的封装。
先介绍一个主要的接口----TypedTuple,它不是一个普通的接口,而是一个内部接口它是org.spingframework.data.redis.core.ZSetOperations 接口的内部接口,它定义了两个方法。
public interface ZSetOperations<K, V> {
public interface TypedTuple<V> extends Comparable<ZSetOperations.TypedTuple<V>> { V getValue(); Double getScore(); }
}
这里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操作有序集合
/**
* 通过Spring操作有序集合
*/
@Test
public void testZset() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
//Spring提供接口TypedTuple操作有序集合
Set<TypedTuple> set1 = new HashSet<TypedTuple>();
Set<TypedTuple> set2 = new HashSet<TypedTuple>();
int j = 9;
for (int i = 1; i <= 9; i++) {
//计算分数和值
Double score1 = Double.valueOf(i);
String value1 = "x" + i;
Double score2 = Double.valueOf(j);
String value2 = j % 2 == 1 ? "Y" + j : "X" + j;
//使用Spring提供的默认TypedTuple----DefaultTypedTuple
TypedTuple typedTuple1 = new DefaultTypedTuple(value1, score1);
set1.add(typedTuple1);
TypedTuple typedTuple2 = new DefaultTypedTuple(value2, score2);
set2.add(typedTuple2);
}
//将元素插入有序集合zset1
redisTemplate.opsForZSet().add("zset1", set1);
redisTemplate.opsForZSet().add("zset2", set2);
//统计总数
Long size = null;
size = redisTemplate.opsForZSet().zCard("zset1");
//计分数为score,那么下面的方法就是求3<= score <=6 的元素
size = redisTemplate.opsForZSet().count("zset1", 3, 6);
Set set = null;
//从下标一开始截取5个元素,但是不返回分数,每一个元素是String
set = redisTemplate.opsForZSet().range("zset1", 1, 5);
printSet(set);
//截取集合所有元素,并且对集合按分数排序,并返回分数,每一个元素是TypedTuple
set = redisTemplate.opsForZSet().rangeWithScores("zset1", 0, -1);
printTypedTuple(set);
//将zset1和zset2两个集合的交集放入集合inter_zset
size = redisTemplate.opsForZSet().intersectAndStore("zset1", "zset2", "inter_zset");
//区间
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);
//限制从第五个开始截取
limit.offset(5);
//求区间内的元素,并限制返回4条
set = redisTemplate.opsForZSet().rangeByLex("zset1", range, limit);
printSet(set);
//求排行,排名第1返回0,第2返回1
Long rank = redisTemplate.opsForZSet().rank("zset1", "x4");
System.err.println("rank = " + rank);
//删除元素,返回删除个数
size = redisTemplate.opsForZSet().remove("zset1", "x5", "x6");
System.err.println("delete = " + size);
//按照排行删除从0开始算起,这里将删除排名第2和第3的元素
size = redisTemplate.opsForZSet().removeRange("zset2", 1, 2);
//获取所有集合的元素和分数,以-1代表全部元素
set = redisTemplate.opsForZSet().rangeWithScores("zset2", 0, -1);
printTypedTuple(set);
//删除指定的元素
size = redisTemplate.opsForZSet().remove("zset2", "y5", "y3");
System.err.println(size);
//给集合中的一个元素的分数加上11
Double db1 = redisTemplate.opsForZSet().incrementScore("zset1", "x1", 11);
redisTemplate.opsForZSet().removeRangeByScore("zset1", 1, 2);
set = redisTemplate.opsForZSet().reverseRangeWithScores("zset2", 1, 10);
printTypedTuple(set);
}
/**
* 打印TypedTuple集合
* @param set --Set<TypedTuple>
*/
private static void printTypedTuple(Set<TypedTuple> set) {
if (set != null && set.isEmpty())
return;
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
TypedTuple val = (TypedTuple) iterator.next();
System.err.print("{value = " + val.getValue() + ", score = " + val.getScore() + "}\n");
}
}
/**
* 打印普通集合
* @param set
*/
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.print(val+ "\t");
}
System.out.println();
}