如何存储文章中的tag(tag不同,也无序)


一、介绍

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

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

二、命令

1.增加/删除元素
SADD key member [member …] 
SREM key member [member …]
  • SADD 命令用来向集合中增加一个或多个元素,如果键不存在则会自动创建。因为在一 个集合中不能有相同的元素,所以如果要加入的元素已经存在于集合中就会忽略这个元素。 本命令的返回值是成功加入的元素数量(忽略的元素不计算在内);
  • SREM命令用来从集合中删除一个或多个元素,并返回删除成功的个数,
2.获得集合中的所有元素
SMEMBERS key

SMEMBERS命令会返回集合中的所有元素

3.判断元素是否在集合中
SISMEMBER key member

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

redis MATCH pattern 详细用法 redis tag_redis

4.集合间运算
SDIFF key [key „] 
SINTER key [key „] 
SUNION key [key „]

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

  1. SDIFF命令用来对多个集合执行差集运算。集合A与集合B的差集表示为A−B,代 表所有属于A且不属于B的元素构成的集合,即A−B ={x | x∈A且x∈B}。 例如:
  2. redis MATCH pattern 详细用法 redis tag_redis_02


  3. redis MATCH pattern 详细用法 redis tag_集合类型_03

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


  6. redis MATCH pattern 详细用法 redis tag_redis_05

  7. SUNION命令用来对多个集合执行并集运算。集合A与集合B的并集表示为A∪B, 代表所有属于A或属于B的元素构成的集合(如图3-15所示)即A∪B ={x | x∈A或x ∈B}。
  8. redis MATCH pattern 详细用法 redis tag_集合类型_06

redis MATCH pattern 详细用法 redis tag_Redis_07


三、实践

1.存储文章标签

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

对每篇文章使用键名为post:文章ID:tags的键存储该篇文章的标签

//给 ID 为 42 的文章增加标签: 
SADD post:42:tags  闲言碎语  技术文章  Java 
//删除标签: 
SREM post:42:tags  闲言碎语 
//显示所有的标签: 
$tags = SMEMBERS post:42:tags
2.通过标签搜索文章

有时我们还需要列出某个标签下的所有文章,甚至需要获得同时属于某几个标签的文章 列表

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

redis MATCH pattern 详细用法 redis tag_Redis_08


四、命令拾遗

1.获得集合中元素个数 SCARD key

SCARD命令用来获得集合中的元素个数,例如:

redis> SMEMBERS letters 
1) "b" 
2) "a" 
redis> SCARD letters 
(integer) 2
2.进行集合运算并将结果存储
SDIFFSTORE destination key [key …] 
SINTERSTORE destination key [key …] 
SUNIONSTORE destination key [key …]

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

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

SRANDMEMBER key [count]
SRANDMEMBER命令用来随机从集合中获取一个元素,如:

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

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

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

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

redis MATCH pattern 详细用法 redis tag_redis_09


SRANDMEMBER 命令返回的数据似乎并不是非常的随机,因为集合类型采用的存储结构(散列表)造成的。散列表使用散 列函数将元素映射到不同的存储位置(桶)上以实现O(1)时间复杂度的元素查找,举个例 子,当使用散列表存储元素b时,使用散列函数计算出b的散列值是0,所以将b存入编号为0 的桶(bucket)中,下次要查找b时就可以用同样的散列函数再次计算b的散列值并直接到相 应的桶中找到 b。当两个不同的元素的散列值相同时会出现冲突,Redis 使用拉链法来解决冲 突,即将散列值冲突的元素以链表的形式存入同一桶中,查找元素时先找到元素对应的桶, 然后再从桶中的链表中找到对应的元素。使用SRANDMEMBER命令从集合中获得一个随机 元素时,Redis首先会从所有桶中随机选择一个桶,然后再从桶中的所有元素中随机选择一个 元素,所以元素所在的桶中的元素数量越少,其被随机选中的可能性就越大。

redis MATCH pattern 详细用法 redis tag_集合类型_10


Redis 会先从3 个桶中随机挑一个非空的桶,然后再从桶中随机选择一个元素,所 以选中元素b的概率会大一些;

有点类型java中的hashMap,put的时候先hash到数组某个位置,如果出现hash冲突,则在该位置向下延伸,储存成红黑树。

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

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

redis> SPOP letters 
"b" 
redis> SMEMBERS letters 
1) "a" 
2) "c" 
3) "d"