Redis学习系列六ZSet(有序列表)及Redis数据结构的过期
Posted Green.Leaf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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结构对象消失了.其余数据结构自行测试.最好在设置前判断对应的对象存不存在,虽然我试过了,消失了还可以继续设置
以上是关于Redis学习系列六ZSet(有序列表)及Redis数据结构的过期的主要内容,如果未能解决你的问题,请参考以下文章
REDIS03_概述安装key字符串String列表List集合SetHash哈希Zset有序集合
Redis支持的五种数据类型及相应操作:String(字符串),Hash(哈希),List(列表),Set(集合)及zset(sorted set:有序集合)
REDIS01_概述安装key字符串String列表List集合SetHash哈希Zset有序集合持久化策略