Redis有序集合详解

有序集合和集合类似,只是说它是有序的,和无序集合的主要区别在于每一个元素除了值之外,它还会多一个分数。分数是一个浮点数,在 Java 中是使用双精度表示的,根据分数,Redis 就可以支持对分数从小到大或者从大到小的排序。

这里和无序集合一样,对于每一个元素都是唯一的,但是对于不同元素而言,它的分数可以一样。元素也是 String 数据类型,也是一种基于 hash 的存储结构。

集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是 0(1)。集合中最大的成员数为 2 的 32 次方减 1(40 多亿个成员),有序集合的数据结构如图所示。
在这里插入图片描述

有序集合是依赖 key 标示它是属于哪个集合,依赖分数进行排序,所以值和分数是必须的,而实际上不仅可以对分数进行排序,在满足一定的条件下,也可以对值进行排序。

Redis基础命令

有序集合和无序集合的命令是接近的,只是在这些命令的基础上,会增加对于排序的操作,这些是我们在使用的时候需要注意的细节。

下面讲解这些常用的有序集合的部分命令。有些时候 Redis 借助数据区间的表示方法来表示包含或者不包含,比如在数学的区间表示中,[2,5] 表示包含 2,但是不包含 5 的区间。

Redis有序集合的部分命令
在这里插入图片描述
在这里插入图片描述

在对有序集合、下标、区间的表示方法进行操作的时候,需要十分小心命令,注意它是操作分数还是值,稍有不慎就会出现问题。

这里命令比较多,也有些命令比较难使用,在使用的时候,务必要小心,不过好在我们使用 zset 的频率并不是太高,下面是测试结果——有序集合命令展示。

在这里插入图片描述

spring-data-redis对有序集合的封装

在 Spring 中使用 Redis 的有序集合,需要注意的是 Spring 对 Redis 有序集合的元素的值和分数的范围(Range)和限制(Limit)进行了封装,在演示如何使用 Spring 操作有序集合前要进一步了解它的封装。

先介绍一个主要的接口——TypedTuple,它不是一个普通的接口,而一个内部接口,它是 org.springframework.data.redis.core.ZSetOperations 接口的内部接口,它定义了两个方法,代码如下所示。

public interface ZSetOperations<K,V>{......
public interface TypedTuple<V> extends Comparable<TypedTuple<V>< {V getValue();Double getScore();
}
......
}

这里的 getValue() 是获取值,而 getScore() 是获取分数,但是它只是一个接口,而不是一个实现类。spring-data-redis 提供了一个默认的实现类—— DefaultTypedTuple,同样它会实现 TypedTuple 接口,在默认的情况下 Spring 就会把带有分数的有序集合的值和分数封装到这个类中,这样就可以通过这个类对象读取对应的值和分数了。

Spring 不仅对有序集合元素封装,而且对范围也进行了封装,方便使用。它是使用接口 org.springframework.data.redis.connection.RedisZSetCommands 下的内部类 Range 进行封装的,它有一个静态的 range() 方法,使用它就可以生成一个 Range 对象了,只是要清楚 Range 对象的几个方法才行,为此我们来看看下面的伪代码。

//设置大于等于min
public Range gte(Object min)
//设置大于min
public Range gt(Object min)
//设置小于等于max
public Range lte(Object max)
//设置小于max
public Range lt(Object max)

这 4 个方法就是最常用的范围方法。下面讨论一下限制,它是接口 org.springframework.data.redis.connection.RedisZSetCommands 下的内部类,它是一个简单的 POJO,它存在两个属性,它们的 getter 和 setter 方法,如下面的代码所示。

// ......
public interface RedisZSetCommands {// ......
public class Limit {int offset;int count;
//setter和getter方法
}
//......
}

通过属性的名称很容易知道:offset 代表从第几个开始截取,而 count 代表限制返回的总数量。

通过 Spring 操作有序集合

我们讨论了 spring-data-redis 项目对有序集合的封装。在测试代码前,要把 RedisTemplate 的 keySerializer 和 valueSerializer 属性都修改为字符串序列化器 StringRedisSerializer,测试代码如下所示。

public static 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++) {j--;// 计算分数和值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--DefaultTypedTupleTypedTuple typedTuple1 = new DefaultTypedTuple(value1, score1);set1.add(typedTuple1);TypedTuple typedTuple2 = new DefaultTypedTuple(value2, score2);set2.add(typedTuple2);}// 将元素插入有序集合zset1redisTemplate.opsForZSet().add("zset1", set1);redisTemplate.opsForZSet().add("zset2", set2);// 统计总数Long size = null;size = redisTemplate.opsForZSet().zCard("set1");// 计分数为score,那么下面的方法就是求 3<=score<=6的元素size = redisTemplate.opsForZSet().count("zset1", 3, 6);Set set = null;// 从下标一开始截取5个元素,但是不返回分数,每一个元索是Stringset = redisTemplate.opsForZSet().range("zset1", 1, 5);printSet(set);// 截取集合所有元素,并且对集合按分数排序,并返回分数,每一个元素是TypedTupleset = redisTemplate.opsForZSet().rangeWithScores("zset1", 0, -1);printTypedTuple(set);// 将zset1和zset2两个集合的交集放入集合inter_zsetsize = 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("xl"); // 大于等于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返回1Long 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);// 给集合中的一个元素的分数加上11Double dbl = 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>
*/
public 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();
}

上面的代码演示了大部分 Spring 对有序集合的操作,并给出了比较清晰的注释,大家认真思考之后就能熟悉如何通过 Spring 操作有序集合了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/564093.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何为你的网站启用HTTPS

步骤一&#xff1a;获取SSL/TLS证书 选择SSL证书提供商&#xff1a; 选择一家可信赖的SSL证书提供商。对于小型网站&#xff0c;JoySSL提供的免费证书是一个不错的选择。购买或申请证书&#xff1a; 根据你的网站需求&#xff0c;购买相应类型的SSL证书。证书的类型包括单域、…

Redis HyperLogLog常用命令

基数并不是存储元素&#xff0c;存储元素消耗内存空间比较大&#xff0c;而是给某一个有重复元素的数据集合&#xff08;一般是很大的数据集合&#xff09;评估需要的空间单元数&#xff0c;所以它没有办法进行存储&#xff0c;加上在工作中用得不多&#xff0c;我们要介绍一下…

Redis的基础事务

Redis 存在事务&#xff0c;尽管它没有数据库那么强大&#xff0c;但是它还是很有用的&#xff0c;尤其是在那些需要高并发的网站当中。 使用 Redis 读/写数据要比数据库快得多&#xff0c;如果使用 Redis 事务在某种场合下去替代数据库事务&#xff0c;则可以在保证数据一致性…

Redis事务回滚深入

对于 Redis 而言&#xff0c;不单单需要注意其事务处理的过程&#xff0c;其回滚的能力也和数据库不太一样&#xff0c;这也是需要特别注意的一个问题——Redis 事务遇到的命令格式正确而数据类型不符合&#xff0c;如图所示。 从图中可知&#xff0c;我们将 key1 设置为字符串…

计算机辅助设计的发展及应用,计算机辅助设计的发展与应用

计算机维普资讯 http://doc.xuehai.net第 1卷第 34 2、期19 98年 9月株洲工学院学报V 11 o34 o 2N .、 .J OURNAL OF HUZ Z HOU NS TUTE OF TEC I TI HNOL OGY S p 1 9 e .98⑦计算机辅助设计的发展与应用7摘要廖建勇(洲工学院株株洲 420) 1 0 87讨论计算机辅助设计( AD) c技术…

Java 画圆

Java控制台画圆 画空心圆 完整代码&#xff1a; //空心圆 import java.util.Scanner; class circle2 { public static void main(String[] args) { new circle2().print();} //画圆函数void print() {System.out.println("输入半径&#xff1a;"); Sca…

智能控制和计算机控制的区别,解析智能控制技术是什么及与传统控制的区别

描述智能控制是什么智能控制(intelligent controls)在无人干预的情况下能自主地驱动智能机器实现控制目标的自动控制技术。对许多复杂的系统&#xff0c;难以建立有效的数学模型和用常规的控制理论去进行定量计算和分析&#xff0c;而必须采用定量方法与定性方法相结合的控制方…

C++ 画直线

使用C画直线 完整代码 #include "graphics.h" int main() {int driver,mode,i;float x0,y0,y1,x1;float j12,k;driverVGA;modeVGAHI;initgraph(&driver,&mode,"");setbkcolor(GREEN);x0263;y0263;y1275;x1275;for(i0;i<18;i){setcolor(5);lin…

计算机系统性错误,《深入理解计算机系统-异常》

现代操作系统通过使控制流发生突变来对某些意外情况(磁盘读写数据准备就绪、硬件定时器产生信号等)做出反应。一般而言&#xff0c;我们把这些突变命名为异常控制流(Exceptional Contral Flow ECF)。异常控制流发生在计算机系统的各个层次。比如&#xff0c;在硬件层&#xff0…

C 画矩形

使用C画矩形 使用C语言的相关知识在控制台输出一个矩形。 完整代码 #include "graphics.h" int main() {int x0,y0,y1,x1,driver,mode,i;driverVGA;modeVGAHI;initgraph(&driver,&mode,"");setbkcolor(YELLOW);x0263;y0263;y1275;x1275;for(i0;…

C++ 画圆

C画圆 使用C技术在控制台输出一个圆形。 完整代码 # define PAI 3.1415926 # define B 0.809 # include "graphics.h" #include "math.h" int main() {int i,j,k,x0,y0,x,y,driver,mode;float a;driverCGA;modeCGAC0;initgraph(&driver,&mode,&…

C 画图

使用C语言画图 使用C语言相关知识画图。 完整代码 #include "graphics.h" #define LEFT 0 #define TOP 0 #define RIGHT 639 #define BOTTOM 479 #define LINES 400 #define MAXCOLOR 15 int main() {int driver,mode,error;int x1,y1;int x2,y2;int dx1,dy1,dx2,…

C 杨辉三角形

使用C语言实现杨辉三角形 C语言使用循坏输出10行的杨辉三角形。 完整代码&#xff1a; #include <stdio.h>int main() {int i,j;int a[10][10];printf("\n");for(i0;i<10;i) {a[i][0]1;a[i][i]1;}for(i2;i<10;i)for(j1;j<i;j)a[i][j]a[i-1][j-1]a[…

计算机项目开发流程,产品开发项目建议流程图怎样画

产品开发项目建议流程图怎样画2019-01-14 10:30:270点赞3收藏0评论每一个新产品即将问世的时候会对其进行一系列的测试&#xff0c;测试的结果以及需要更改的地方我们会用表格将其整理起来&#xff0c;流程图就是一个比较实用的图表&#xff0c;可以清晰的看到整件事情的操作流…

C 画点

C语言画点 使用C语言画点。 完整代码 #include "stdio.h" #include "graphics.h" int main() {int i,j,driverVGA,modeVGAHI;initgraph(&driver,&mode,"");setbkcolor(YELLOW);for(i50;i<230;i20)for(j50;j<230;j)putpixel(i,j…

C 画椭圆

C语言画圆 使用C语言画椭圆。 完整代码 #include "stdio.h" #include "graphics.h" #include "conio.h" int main() {int x360,y160,driverVGA,modeVGAHI;int num20,i;int top,bottom;initgraph(&driver,&mode,"");topy-30…

C++ 画图

使用C画图 C实现画图&#xff0c;采用ellipse and rectangle实现。 完整代码 #include "stdio.h" #include "graphics.h" #include "conio.h" main() {int driverVGA,modeVGAHI;int i,num15,top50;int left20,right50;initgraph(&driver,…

计算机办公价格,公职人员,你的办公电脑最少要用6年,而价格不能超过这个数?...

小王&#xff0c;是个公职人员&#xff0c;每天的工作&#xff0c;都离不开电脑。可是&#xff0c;他的电脑最近似乎不太给力&#xff0c;而且动不动就死机。有一次&#xff0c;领导在开会前&#xff0c;着急要个发言材料&#xff0c;就把这活安排给了小王。还有一个小时&#…

C 画美丽的图案

C语言画图案 使用C语言技术画一个美丽的图案在控制台输出。 完整代码 #include "graphics.h" #include "math.h" #include "dos.h" #include "conio.h" #include "stdlib.h" #include "stdio.h" #include &quo…

flume 写入文件服务器,Flume环境配置以及基本操作

flume的作用是从接受外界的日志信息&#xff0c;然后输出到本地的一个框架。agent是Flume很重要的组成&#xff0c;包括有source&#xff0c;channel&#xff0c;sink。source是从外部接受日志。channel跟内存相似&#xff0c;读满了之后再写到sink中。sink是将数据写到本地&am…