首页

5.4集合的创建和修改

关灯 护眼    字体:

上一章 目录 下一章




集合(Sets)是Redis的基本数据结构之一。

Redis中的集合与列表一样可以存放很多数据,但不同之处在于:集合里面的数据不能重复,也没有顺序。由于没有顺序,所以自然没有方向,不存在“左右侧”之说。

Redis的集合与Python的集合有非常多的相似之处,可以对比学习。集合有15条操作命令,本节将介绍其中常用的9条命令。



5.4.1  使用redis-cli实现


1.插入数据

集合的首字母为“S”,“添加”的英文为“Add”,所以向集合中添加数据的命令为“sadd”,命令格式如下:

sadd  key  value1  value2  value3

key  的命名方式与字符串和列表一样,可以使用数字、字母、下划线和中文,但不建议使用中文。

Value可以有一个或者多个。如果有多个Value,则每一个之间使用空格隔开;如果一个Value内部本身就有空格,则使用引号把它包起来。

以下为使用示例:

命令执行效果如图5-44所示。

图5-44  向Redis的集合中添加数据

向Redis集合中添加数据的过程如图5-45所示。

图5-45  集合插入数据示意图

从图5-45可以看出,由于集合里面的数据是没有顺序的,所以:

●  数据插入命令执行的先后顺序无关紧要。

●  在一条命令中,数据位于“value1”还是“value3”也无关紧要。

由于集合的数据是不重复的,如果在一条命令中同一个数据既是“value1”又是“value2”会怎么样?如果多条命令都插入了同一个数据又会怎么样?下面通过实际执行命令来看效果。

sadd  example_set  python  golang  python  C  Java

sadd  example_set  python

运行效果如图5-46所示。

图5-46  往集合中插入重复数据

从图5-46可以看出,第一次尝试插入“python”“golang”“python”“C”“Java”一共5个值,但实际上,Redis返回的数字“4”表示实际上只插入了4个值。这是因为有两个“python”,集合自动过滤了第2个“python”。

接下来单独插入一个值“python”,Redis  返回0,表示实际上什么数据都没有添加进“example_set”这个集合中。因为原来已经有“python”这个值了,所以,集合不再接收重复的数据。

2.读取数据

集合里面的数据虽然没有顺序也不能重复,但是可以查看集合里面一共有多少个数据。

(1)查询集合里面元素的数量。

查询集合数据量的命令是scard。其中,首字母“s”是“集合(Sets)”的首字母,“card”不是英文单词“卡片(Card)”,而是“基数(Cardinality)”的缩写。

命令格式如下:

scard  key

例如执行以下命令:

scard  example_set

执行效果如图5-47所示,表示集合“example_set”中有11条数据。

图5-47  查看集合内部有多少数据

(2)从集合中获取数据。

从集合中获取数据使用的命令为“spop”。由于集合里面的数据没有顺序,所以spop命令会随机获取集合中的数据,无法预测会获取哪一条数据。

“spop”命令的格式如下:

spop  key  count

其中,如果“count”省略,则表示随机获取1条数据。

●  如果“count”为其他大于1的整数,则会获取多条数据;

●  如果“count”对应的整数超过了集合总数据的条数,则获取集合中的所有数据,例如:

spop  example_set

spop  example_set  3

spop  example_set  1000

运行效果如图5-48所示。获取一条数据后,这一条数据就被会被从集合中删除。

图5-48  从集合中弹出数据

(3)获取集合中的所有数据。

如果要获取所有数据,则可以使用以下命令:

smembers  key

运行效果如图5-49所示。

图5-49  获取集合的所有数据

提示:

smembers命令不会删除数据。但是如果集合里的数据量极大,就应该慎重使用“获取所有数据”,因为这样会导致系统的I/O资源瞬间被耗尽。

(4)判断集合中是否包含某个元素。

sadd命令在遇到数据已经存在时,会返回“0”,如果数据不存则把数据插入再返回“1”。所以,这一条命令可以通过返回的数字来判断数据是否存在。

如果不想把数据插入集合,只是单纯想检查数据是否在集合中,那就要使用“sismember”命令。“sismember”命令的使用格式如下:

sismember  key  value

如果数据存在,则返回“1”;如果数据不存在,则返回“0”。例如:

sismember  example_set  2

sismember  example_set  xxxx

运行效果如图5-50所示,如果看到“2”则表示数据是已经存在的,而如果看到“xxxx”则表示数据是不存在的。

图5-50  检查数据是否在集合中

3.删除数据

如果要从集合中删除特定的数据,可以使用命令“srem”,格式为:

srem  key  value1  value2  value3

例如:

srem  example_set  2

运行效果如图5-51所示。

图5-51  从集合中删除数据

提示:

从效果上看,检查数据是否在集合中且不把数据添加进集合中有两种写法:

(1)直接使用“sismember”命令。

(2)使用“sadd”命令,如果返回“1”,则再使用“srem”命令把添加的这一条数据移除。

它们的区别在于:

●  方式(1)不论集合中有多少数据,检查的时间都相同。

●  方式(2)的时间会随着集合中数据量的增加而增加。

●  方式(2)有两步,假设刚刚执行了第一条命令,还没有来得及删除数据,此时另一台服务器又去检查这个数据是否存在,就会导致结果出错。

4.集合的交集

在数学中,“集合”包括“交集”“并集”“差集”的概念。在  Redis  的集合中也存在这样的概念。

有两个集合A和B。交集是指,既属于A,又属于B的数据构成的集合。

假设:A集合中的内容为{1,  'C',  'three',  'python',  2,’三’},  B集合中的内容为{9,8.0,'VI',’七’,'python',2}。

则:A与B的交集就是{2,  'python'},如图5-52中的阴影部分所示。

图5-52  阴影部分为交集

在Redis中,求集合交集使用的命令为“sinter”,命令格式如下:

sinter  key1  key2  key3

如果有多个key,那么就是求所有key对应的集合的交集。实例代码如下:

运行效果如图5-53所示。

图5-53  求集合的交集

5.集合的并集

集合的“并集”是指,只属于集合A的数据与只属于集合B的数据,以及既属于A又属于B的数据构成的集合,集合A与集合B都有的数据需要去重。

假设:A集合中的内容为{1,  'C',  'three',  'python',  2,’三’},  B集合中的内容为{9,8.0,'VI',’七’,'python',2}。

则:A与B的并集就是{1,  'C',  'three',  'python',  2,’三’,  9,  8.0,  'VI',  ’七’},如图5-54中的阴影部分所示。

图5-54  阴影部分为并集

求集合并集使用的命令为“sunion”,命令格式如下:

sunion  key1  key2  key3

如果有超过两个key,那么就是求所有集合的并集。实例代码如下:

运行效果如图5-55所示。

图5-55  求集合的并集

6.集合的差集

集合的“差集”是指,只属于一个集合,不属于其他集合的数据构成的集合。

假设:A集合中的内容为{1,  'C',  'three',  'python',  2,’三’},  B集合中的内容为{9,8.0,'VI',’七’,'python',2}。

则:A与B的差集就是{1,  'C',  'three',  ’三’},如图5-56中的阴影部分所示。

图5-56  阴影部分为集合A对集合B的差集

求集合差集使用的命令是“sdiff”,命令格式如下:

sdiff  key1  key2  key3

意思是,求所有只在key1对应的集合中有,在key2、key3……集合中没有的数据构成的集合。实例代码如下:

运行效果如图5-57所示。

图5-57  求集合的差集



5.4.2  使用Python实现


使用Python操作Redis集合相关的关键字与redis-cli的命令完全相同,唯一的差别在于参数的传入方式。

1.插入数据

使用Python向Redis集合中添加数据,用到的关键字是“sadd”。实例代码如下:

代码5-12  在Python中向Redis集合插入数据

代码返回的数字表示当前添加了几条数据。运行效果如图5-58所示。

图5-58  使用Python添加数据到集合中

如果数据已经在集合中,则Python是不会把它重复添加进去的,见下方代码:

>>>  client.sadd('example_set_python',  'some_data')

1

>>>  client.sadd('example_set_python',  'some_data')

0

运行效果如图5-59所示。在数据不存在时添加,则返回1;在数据已经存在时添加,则返回0。

图5-59  添加重复数据返回0

2.读取数据

使用关键字“scard”可以查看集合中数据的条数,使用关键字“spop”可以从集合中随机获取一条数据。

代码5-13  在Python中读取Redis集合的数据

运行效果如图5-60所示。获取的数据均为bytes型数据。

图5-60  获取集合数据条数与弹出数据

提示:

在Python中,“spop”关键字没有“count”参数,因此一次只能获取一条数据,不能一次性获取多条数据。如果要一次获取多条数据,则可以使用循环来实现,见代码5-13。

代码5-13  使用循环从Redis集合中获取数据

运行效果如图5-61所示。

图5-61  使用循环来间接获取多条数据

获取集合所有数据的关键字为“smembers”。以下是一个示例:

代码5-14  获取Redis集合中的全部数据

运行效果如图5-62所示。

图5-62  获取集合中的全部数据

从图5-62可以看出,关键字“smembers”返回的数据格式是Python中的“集合(set)”,且里面的每一个数据都是bytes型数据。

3.删除数据

从集合中移除数据使用的关键字为“srem”。以下是一个示例:

代码5-15  从Redis集合中删除数据

运行效果如图5-63所示。

图5-63  从集合中移除数据

4.集合的运算

交集、并集和差集用到的关键字和redis-cli中的命令是一样的,分别是“sinter”“sunion”和“sdiff”。以下是一个实例。

代码5-16  使用Python计算Redis的集合的交集并集和差集

运行效果如图5-64所示。

图5-64  在Python中求交集、并集和差集

提示:

求差集时,参数的顺序是很重要的,最后的结果是用第1个Key对应的集合中的数据扣除后面的Key对应的集合中的数据。



5.4.3  集合的应用


在工程中,Redis的集合一般有两种用途:

(1)根据集合内数据不重复的特性实现去重并记录信息。

(2)利用多个集合计算交集、并集和差集。

假设,要做一个学生选课情况实时监控系统,则需要实时知道以下几个数据:

(1)当前一共有多少学生至少选了一门课。

(2)选了A课没有选B课的学生有多少。

(3)既选了A课又选了B课的学生有多少。

(4)A、B两门课至少选了一门的学生有多少。

使用集合可以轻易实现这样的功能。每一门课作为一个集合,里面的值就是每一个学生的学号,如图5-65所示。

图5-65  模拟课程集合

通过求交集并集和差集就能实现上面的要求了。

主要代码如下:

代码5-17  使用Redis集合运算计算学生选课信息



其中,第31行代码表示:只有在这个程序被直接运行时才运行下面的四行代码;如果是被其他代码作为模块带入,则不运行后面的四行代码。



本章小结


本章主要介绍了  Redis  的安装和三种基本数据结构——字符串、列表和集合的使用。在学习这三种数据结构时,建议读者使用Python来操作,同时设想一些使用场景来帮助自己更好地理解。


上一章 目录 下一章