NoSQL数据库(二)04-Redis数据类型——集合类型之介绍、命令-增加和删除元素、获得集合中的所有元素、判断元素是否在集合中、集合间运算

本文介绍了Redis中的集合类型,包括SADD、SREM、SMEMBERS、SISMEMBER等命令,用于增删元素、检查成员及集合运算。集合类型适用于存储不重复的数据,如文章标签,并能进行高效的交集、并集和差集操作。示例展示了如何使用集合类型存储和操作文章标签。
摘要由CSDN通过智能技术生成

NoSQL数据库(二)04-Redis数据类型——集合类型之介绍、命令-增加和删除元素、获得集合中的所有元素、判断元素是否在集合中、集合间运算

集合类型

Redis 有一种数据类型很适合存储文章的标签,它就是集合类型。

介绍

集合的概念高中的数学课就学习过。在集合中的每个元素都是不同的,且没有顺序。一个集合类型(set)键可以存储至多2的32次方 −1个(相信这个数字对大家来说已经很熟悉了)字符串。 集合类型和列表类型有相似之处,但很容易将它们区分开来,

在这里插入图片描述

集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在等,由于集合类型在Redis内部是使用值为空的散列表(hash table)实现的,所以这些操作的时间复杂度都是O(1)。最方便的是多个集合类型键之间还可以进行并集、交集和差集运算,稍后就会看到灵活运用这一特性带来的便利。

命令
  1. 增加/删除元素

    SADD key member [member …]

    SREM key member [member …]

    SADD 命令用来向集合中增加一个或多个元素,如果键不存在则会自动创建。因为在一个集合中不能有相同的元素,所以如果要加入的元素已经存在于集合中就会忽略这个元素。本命令的返回值是成功加入的元素数量(忽略的元素不计算在内)。例如:

     redis> SADD letters a 
     (integer) 1 
     redis> SADD letters a b c 
     (integer) 2 
    

    第二条SADD命令的返回值为2是因为元素“a”已经存在,所以实际上只加入了两个元素。

    SREM命令用来从集合中删除一个或多个元素,并返回删除成功的个数,例如:

     redis> SREM letters c d 
     (integer) 1 
    

    由于元素“d”在集合中不存在,所以只删除了一个元素,返回值为1。

2.获得集合中的所有元素

SMEMBERS key

SMEMBERS命令会返回集合中的所有元素,例如:

redis> SMEMBERS letters 
1) "b" 
2) "a"
  1. 判断元素是否在集合中

    SISMEMBER key member

    判断一个元素是否在集合中是一个时间复杂度为O(1)的操作,无论集合中有多少个元素,SISMEMBER命令始终可以极快地返回结果。当值存在时判断一个元素是否在集合中是一个时间复杂度为O(1)的操作,无论集合中有多少个元素,SISMEMBER命令始终可以极快地返回结果。当值存在时 SISMEMBER命令返回1,当值不存在或键不存在时返回0,例如:

    redis> SISMEMBER letters a 
    (integer) 1 
    redis> SISMEMBER letters d 
    (integer) 0
    

4.集合间运算

SDIFF key [key „]

SINTER key [key „]

SUNION key [key „]

接下来要介绍的3个命令都是用来进行多个集合间运算的。

1)SDIFF命令用来对多个集合执行差集运算。集合A与集合B的差集表示为A−B,代表所有属于A且不属于B的元素构成的集合(如图3-13所示),即A−B ={x | x∈A且x∈B}。例如:

在这里插入图片描述

{1, 2, 3} - {2, 3, 4} = {1} {2, 3, 4} - {1, 2, 3} = {4} SDIFF命令的使用方法如下:

redis> SADD setA 1 2 3 
(integer) 3 
redis> SADD setB 2 3 4 
(integer) 3 
redis> SDIFF setA setB 
1) "1" 
redis> SDIFF setB setA 
1) "4"

SDIFF命令支持同时传入多个键,例如:

redis> SADD setC 2 3 
(integer) 2 
redis> SDIFF setA setB setC 
1) "1"

(2)SINTER命令用来对多个集合执行交集运算。集合A与集合B的交集表示为A ∩ B,代表所有属于A 且属于B的元素构成的集合(如图3-14所示),即A ∩ B ={x | x ∈ A 且x ∈B}。

例如: {1, 2, 3} ∩ {2, 3, 4} = {2, 3} SINTER命令的使用方法如下:

redis> SINTER setA setB 
1) "2" 
2) "3"

SINTER命令同样支持同时传入多个键,如:

redis> SINTER setA setB setC 
1) "2" 
2) "3"

(3)SUNION命令用来对多个集合执行并集运算。集合A与集合B的并集表示为A∪B,代表所有属于A 或属于B的元素构成的集合(如图3-15所示)即A∪B ={x | x∈A或x ∈B}。

例如: {1, 2, 3} ∪{2, 3, 4} = {1, 2, 3, 4}

在这里插入图片描述

redis> SUNION setA setB 
1) "1" 
2) "2" 
3) "3" 
4) "4"

SUNION命令同样支持同时传入多个键,例如:

redis> SUNION setA setB setC 
1) "1" 
2) "2"
3) "3" 
4) "4"
ex: 存储文章标签

考虑到一个文章的所有标签都是互不相同的,而且展示时对这些标签的排列顺序并没有要求,我们可以使用集合类型键存储文章标签。

对每篇文章使用键名为post:文章ID:tags的键存储该篇文章的标签。具体操作如伪代码:

var redis = require('redis');
var client = new redis({
    // 配置
});

client.sadd('post:42:tags 杂文 技术文章 java');

client.srem('post:42:tags 杂文');

var tags = client.smembers('post:42:tags');

使用集合类型键存储标签适合需要单独增加或删除标签的场合。如在 WordPress博客程序中无论是添加还是删除标签都是针对单个标签的(如图 3-16 所示),可以直观地使用SADD和SREM命令完成操作。

另一方面,有些地方需要用户直接设置所有标签后一起上传修改,图3-17所示是某网站的个人资料编辑页面,用户编辑自己的爱好后提交,程序直接覆盖原来的标签数据,整个过程没有针对单个标签的操作,并未利用到集合类型的优势,所以此时也可以直接使用字符串类型键存储标签数据。

在这里插入图片描述

之所以特意提到这个在实践中的差别是想说明对于 Redis 存储方式的选择并没有绝对的规则,比如之前介绍过使用列表类型存储访客评论,但是在一些特定的场合下散列类型甚至字符串类型可能更适合。

ex: 通过标签搜索文章

有时我们还需要列出某个标签下的所有文章,甚至需要获得同时属于某几个标签的文章列表,这种需求在传统关系数据库中实现起来比较复杂,下面举一个例子。

现有3张表,即posts、tags和posts_tags,分别存储文章数据、标签、文章与标签的对应关系。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

为了找到同时属于“Java”、“MySQL”和“Redis”这3个标签的文章,需要使用如下的SQL语句:

SELECT p.post_title FROM posts_tags pt, posts p, tags t WHERE pt.tag_id = t.tag_id AND (t.tag_name IN ('Java', 'MySQL', 'Redis')) AND p.post_id = pt.post_id GROUP BY p.post_id HAVING COUNT(p.post_id)=3;

很明显看到这样的 SQL 语句不仅效率相对较低,而且不易阅读和维护。而使用Redis可以很简单直接地实现这一需求。

为每一个标签使用一个名为具体做法是为每个标签使用一个名为tag:标签名称:posts的集合类型键存储标有该标签的文章ID列表。假设现在有3篇文章,ID分别为1、2、3,其中ID为1的文章标签是“Java”,ID 为 2 的文章标签是“Java”、“MySQL”,ID 为 3 的文章标签是“Java”、“MySQL”和“Redis”。

在这里插入图片描述

最简单的,当需要获取标记“MySQL”标签的文章时只需要使用命令 SMEMBER Stag:MySQL:posts即可。如果要实现找到同时属于Java、MySQL和Redis 3 个标签的文章,只需要将tag:Java:posts、tag:MySQL:posts和tag:Redis:posts这3个键取交集,借助SINTER命令即可轻松完成。

命令补充
  1. 获取集合中的元素个数

SCARD key

redis> SMEMBERS letters 
1) "b" 
2) "a" 
redis> SCARD letters 
(integer) 2
  1. 进行集合运算并将结果存储

    SDIFFSTORE destination key [key …]

    SINTERSTORE destination key [key …]

    SUNIONSTORE destination key [key …]

SDIFFSTORE命令和SDIFF命令功能一样,唯一的区别就是前者不会直接返回运算结果,而是将结果存储在destination键中。 SDIFFSTORE命令常用于需要进行多步集合运算的场景中,如需要先计算差集再将结果和其他键计算交集。 SINTERSTORE和SUNIONSTORE命令与之类似,不再赘述。

  1. 随机获得集合中的元素

    SRANDMEMBER key [count]

redis> SRANDMEMBER letters 
"a" 
redis> SRANDMEMBER letters 
"b" 
redis> SRANDMEMBER letters 
"a"

还可以传递count参数来一次随机获得多个元素,根据count的正负不同,具体表现也不同。

(1)当count为正数时,SRANDMEMBER会随机从集合里获得count个不重复的元素。如果count的值大于集合中的元素个数,则SRANDMEMBER会返回集合中的全部元素。

(2)当count为负数时,SRANDMEMBER会随机从集合里获得|count|个的元素,这些元素有可能同。

4.从集合中弹出一个元素

SPOP key

我们学习过LPOP命令,作用是从列表左边弹出一个元素(即返回元素的值并删除它)。SPOP命令的作用与之类似,但由于集合类型的元素是无序的,所以 SPOP命令会从集合中随机选择一个元素弹出

实例

set_demo.js

var redis = require('redis');
var client = new redis({

});

// 存储标签  post:id:comments  post:id:tags

client.sadd('post:42:tags 杂文 技术 java nodejs');  //存储
client.srem('post:42:tags 技术'); 

var tags = client.smember('post:42:tags');

emo.js

var redis = require('redis');
var client = new redis({

});

// 存储标签  post:id:comments  post:id:tags

client.sadd('post:42:tags 杂文 技术 java nodejs');  //存储
client.srem('post:42:tags 技术'); 

var tags = client.smember('post:42:tags');
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值