zoukankan      html  css  js  c++  java
  • Redis学习系列六ZSet(有序列表)及Redis数据结构的过期

     一、简介

    ZSet可以说是Redis中最有趣的数据结构了,因为他兼具了Hash集合和Set的双重特性,也是用的最多的,保证了value值的唯一性的同时,,同时又保证了高性能,最主要的是还可以给每个Value设置Source(权重),那么我们就可以通过权重进行排序,这在业务上是非常常见的,比如很多地方需要,比如我们需要对所有用户的数学成绩进行排序.对英语等等地例子比比皆是,那么通过ZSet,你将会得到一个响应速度非常快的过程.下面会介绍.

    ZSet的内部原理是通过跳跃列表来实现的,这里还是不想说太多关于算法的东西.

    二、ZSet(有序列表)实战

    下面就通过一个列子来讲解,主要是给所有用户的数学成绩进行排序的例子.代码开始在前面的随笔上进行扩展.

    C#控制台:

    给RedisClient.cs扩展如下几个方法:

      /// <summary> 
            /// 异步不带权重的向有序列表批量插入数据
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static async Task<long> SortedSetAddAsync(RedisKey key, SortedSetEntry[] entries)
            {
                var db = GetDatabase();
                return await db.SortedSetAddAsync(key, entries);
            }
    
            /// <summary> 
            /// 异步带权重的向有序列表插入单个元素,不管是否存在已有元素,都执行插入操作
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static async Task<RedisValue> SortedSetAddAsync(RedisKey key, RedisValue value,double source)
            {
                var db = GetDatabase();
                return await db.SortedSetAddAsync(key, value, source);
            }
    
            /// <summary>
            /// 异步按权重(范围为负无穷大到正无穷大排序)得到所有的元素,返回的元素(不包含权重)集合默认的排序时按权重从低到高,可指定权重
            /// </summary>
            /// <param name="key"></param>
            /// <param name="start">权重下限</param>
            /// <param name="stop">权重上限</param>
            /// <returns></returns>
            public static async Task<RedisValue[]> SortedSetRangeByScoreAsync(RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity)
            {
                var db = GetDatabase();
                return await db.SortedSetRangeByScoreAsync(key, start, stop);
            }
    
            /// <summary>
            /// 异步按权重(范围为负无穷大到正无穷大排序)得到所有的元素,返回的元素(包含权重)集合默认的排序时按权重从低到高,可指定权重
            /// </summary>
            /// <param name="key"></param>
            /// <param name="start"></param>
            /// <param name="stop"></param>
            /// <returns></returns>
            public static async Task<SortedSetEntry[]> SortedSetRangeByScoreWithScoresAsync(RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity)
            {
                var db = GetDatabase();
                return await db.SortedSetRangeByScoreWithScoresAsync(key, start,stop);
            }
    
            /// <summary>
            /// 异步按权重(范围为负无穷大到正无穷大排序)得到所有的元素,返回的元素(包含权重)集合默认的排序时按权重从高到低,可指定权重
            /// </summary>
            /// <param name="key"></param>
            /// <param name="start"></param>
            /// <param name="stop"></param>
            /// <returns></returns>
            public static async Task<SortedSetEntry[]> SortedSetRangeByScoreWithScoresDescendingAsync(RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity)
            {
                var db = GetDatabase();
                return await db.SortedSetRangeByScoreWithScoresAsync(key, start, stop,Exclude.None, Order.Descending);
            }
    
            /// <summary>
            /// 异步按权重范围,删除对应键下的所有元素
            /// </summary>
            /// <param name="key"></param>
            /// <param name="start"></param>
            /// <param name="stop"></param>
            /// <returns></returns>
            public static async Task<long> SortedSetRemoveRangeByScoreAsync(RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity)
            {
                var db = GetDatabase();
                return await db.SortedSetRemoveRangeByScoreAsync(key, start, stop);
            }
    
            /// <summary>
            /// 异步删除指定键下的指定值
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            public static async Task<bool> SortedSetRemoveAsync(RedisKey key, RedisValue value)
            {
                var db = GetDatabase();
                return await db.SortedSetRemoveAsync(key, value);
            }

    还可以继续扩展,个人觉得其它方法没什么用,就没有继续扩展了.

    Program.cs代码如下:

        class Program
        {
            static Program()
            {
                //链式配置Redis
                AppConfiguration.Current.ConfigureRedis<RedisConfig>();
            }
    
            static void Main(string[] args)
            {
                StringSetGetAsync();
                Console.ReadKey();
            }
    
            static async void StringSetGetAsync()
            {
                var key = "math";
                var computer = new KeyValuePair<RedisValue, double>("小超的用户Id", 9.0);
                var english = new KeyValuePair<RedisValue, double>("大超的用户Id", 8.0);
                var math = new KeyValuePair<RedisValue, double>("中超的用户Id", 7.0);
                var chinese = new KeyValuePair<RedisValue, double>("大大超的用户Id", 10.0);
                try
                {
                    await RedisClient.SortedSetAddAsync(key, new SortedSetEntry[] { computer, math, english, chinese });
    
                    //模拟重复插入,不会发现插入没有效果,因为Zset自带去重功能是Set和Hash的组合体
                    await RedisClient.SortedSetAddAsync(key, new SortedSetEntry[] { computer, math, english });
    
                    Console.WriteLine("输出指定键的所有元素(不包含权重),默认按权重从小到大排序");
                    //输出指定键的所有元素(不包含权重),默认按权重从小到大排序
                    var values =await RedisClient.SortedSetRangeByScoreAsync(key);
                    foreach (var val in values)
                    {
                        Console.WriteLine("值为:{0}",val);
                    }
                    Console.WriteLine("输出指定键的所有元素(包含权重),默认按权重从小到大排序");
                    //输出指定键的所有元素(包含权重),默认按权重从小到大排序
                    var oValues= await RedisClient.SortedSetRangeByScoreWithScoresAsync(key);
                    foreach (var oVal in oValues)
                    {
                        Console.WriteLine("值为:{0},权重为:{1}",oVal.Element,oVal.Score);
                    }
    
                    Console.WriteLine("输出指定键的所有元素(包含权重),按权重从大到小排序");
                    //输出指定键的所有元素(包含权重),按权重从大到小排序,权重范围为7~8
                    var lValues = await RedisClient.SortedSetRangeByScoreWithScoresDescendingAsync(key,7,8);
                    foreach (var lVal in lValues)
                    {
                        Console.WriteLine("值为:{0},权重为:{1}", lVal.Element, lVal.Score);
                    }
                    try
                    {
                        await RedisClient.SortedSetRemoveRangeByScoreAsync(key, 7, 8);
                        Console.WriteLine("删除key为:{0}下权重为7~8之间的所有元素成功!", key);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("删除元素发生了异常,信息为{0}", ex.Message);
                    }
                    var extraValues = await RedisClient.SortedSetRangeByScoreWithScoresAsync(key);
                    foreach (var eVal in extraValues)
                    {
                        Console.WriteLine("值为:{0},权重为:{1}", eVal.Element, eVal.Score);
                    }
    
                    //输出一个指定键下的指定值
                    try
                    {
                        var value = "大大超的用户Id";
                        await RedisClient.SortedSetRemoveAsync(key, value);
                        Console.WriteLine("删除key为:{0}下值为:{1}的元素成功!", key, value);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("删除元素发生了异常,信息为{0}", ex.Message);
                    }
    
                    var exValues = await RedisClient.SortedSetRangeByScoreWithScoresAsync(key);
                    foreach (var exVal in exValues)
                    {
                        Console.WriteLine("值为:{0},权重为:{1}", exVal.Element, exVal.Score);
                    }
    
                }
                catch (Exception ex)
                {
                    //记录日志
                    Console.WriteLine(ex.Message);
                }
            }
        }

    上面的权重就是实际的分数,ok,是不是很强大!

    三、给Redis数据结构设置过期时间

    到这里Redis的5大基本数据结构算介绍完了,该讲讲过期的知识,Redis的所有数据结构都可以设置过期时间,时间一到,Redis会自动删除相应的对象,注意:Redis的5大基本数据结构基本都是键值对的关系,最外部有个键来指定整个对象,所以Redis的删除是争对该键对应的对象的.但是Hash结构中,除了指定外部的键还可以指定内部的键.向下面这样:

    但是Redis的过期是争对最外部的键的.就是整个数据结构.

    注:关于String结构也有点特殊,因为它本身也可以设置过期时间,如果你已经给一个字符串设置了过期时间,然后调用了过期Api修改它,它原先的过期时间会消失.

    给RedisClient.cs扩展如下方法:

            /// <summary>
            /// 异步给指定的键的对象设置过期时间
            /// </summary>
            /// <param name="key"></param>
            /// <param name="timeSpan"></param>
            /// <returns></returns>
            public static async Task<bool> KeyExpireAsync(RedisKey key,TimeSpan timeSpan)
            {
                var db = GetDatabase();
                return await db.KeyExpireAsync(key, timeSpan);
            }

    Program.cs代码如下:

        class Program
        {
            static Program()
            {
                //链式配置Redis
                AppConfiguration.Current.ConfigureRedis<RedisConfig>();
            }
    
            static void Main(string[] args)
            {
                StringSetGetAsync();
                Console.ReadKey();
            }
    
            static async void StringSetGetAsync()
            {
                var key = "math";
                try
                {
                    await RedisClient.KeyExpireAsync(key, TimeSpan.FromMilliseconds(1000));
                    Console.WriteLine("给指定的键设置过期时间异常成功.");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("给指定的键设置过期时间异常,信息为:{0}.", ex.Message);
                }
                
            }
        }

    对应键为math的ZSet结构对象消失了.其余数据结构自行测试.最好在设置前判断对应的对象存不存在,虽然我试过了,消失了还可以继续设置

  • 相关阅读:
    形象理解ERP(转)
    禁用windows server 2008 域密码复杂性要求策略
    How to adding find,filter,remove filter on display method Form
    Windows Server 2008 R2激活工具
    How to using bat command running VS development SSRS report
    Creating Your First Mac AppGetting Started
    Creating Your First Mac AppAdding a Track Object 添加一个 Track 对象
    Creating Your First Mac AppImplementing Action Methods 实现动作方法
    Creating Your First Mac AppReviewing the Code 审查代码
    Creating Your First Mac AppConfiguring the window 设置窗口
  • 原文地址:https://www.cnblogs.com/GreenLeaves/p/10182723.html
Copyright © 2011-2022 走看看