Redis数据结构-------有序集合

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();
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值