不积跬步无以至千里,这一篇set继续走起,set底层原理也是并不复杂,还是先来基本操作,再来原理解析。
目录
一、概述及基本操作
set存储String类型的无序集合,最大存储数量(2^32) - 1 个元素(40亿左右)元素不可以重复。
操作命令:
1、Sadd:将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略。
假如集合 key 不存在,则创建一个只包含添加的元素作成员的集合。当集合 key 不是集合类型时,返回一个错误。
a、语法:SADD KEY_NAME VALUE1..VALUEN
b、返回值:被添加到集合中的新元素的数量,不包括被忽略的元素。
c、实例解释:127.0.0.1:6379> SADD set1 "a"
运行上面命令,会将a添加到keyname = set1 的集合中,返回1,可以理解为,添加成功就返回1,添加失败就返回0。
2、Scard:返回集合中元素的数量。
a、语法:SCARD KEY_NAME
b、返回值:集合中元素的数量, 当集合 key 不存在时,返回 0 。
c、实例解释:127.0.0.1:6379> SCARD set1
运行上面命令,将返回set1集合中元素的个数。
3、Sdiff:返回给定集合之间的差集。不存在的集合 key 将视为空集。
差集的结果来自前面的 FIRST_KEY ,而不是后面的 OTHER_KEY1,也不是整个 FIRST_KEY OTHER_KEY1..OTHER_KEYN 的差集。
a、语法:SDIFF FIRST_KEY OTHER_KEY1..OTHER_KEYN
b、返回值:第一个集合中不存在于后面其他集合中的元素组成的列表。
c、实例解释:有集合 k1 = {a,b,c} 、 k2 = {b,c,d,e}
则:127.0.0.1:6379> SDIFF k1 k2
运行上面命令,将返回一个k1相对于k2不同的元素组成的集合,k1中只有"a"不在k2集合中,所以返回集合{a}。
4、Sdiffstore:将给定集合之间的差集存储在指定的集合中。如果指定的集合 key 已存在,则会被覆盖。
a、语法:SDIFFSTORE DESTINATION_KEY KEY1...KEYN
b、返回值:结果集中的元素数量。
c、实例解释:有集合 k1 = {a,b,c} 、 k2 = {b,c,d,e}
则:127.0.0.1:6379> SDIFFSTORE k3 k1 k2
运行上面命令,此时将会把k1相对于k2不同的元素存储在k3中,如果之前k3已经存在,则会覆盖k3的内容,此时k3 = {a},并返回k3的元素个数1。
5、Sinter:返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。 当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。
a、语法:SINTER KEY KEY1..KEYN
b、返回值:交集成员的列表。
c、实例解释:有集合 k1 = {a,b,c} 、 k2 = {b,c,d,e}
则:127.0.0.1:6379> SINTER k1 k2
运行上面命令,将返回k1、k2的交集,即返回:{b,c}
6、Sinterstore:将给定集合之间的交集存储在指定的集合中。如果指定的集合已经存在,则将其覆盖。
a、语法:SINTERSTORE DESTINATION_KEY KEY KEY1..KEYN
b、返回值:返回存储交集的集合的元素数量。
c、实例解释:127.0.0.1:6379> SINTERSTORE k3 k1 k2
运行上面命令,将k1、k2的交集元素存储在k3中,并返回k3集合的元素个数。
7、Sismember:判断成员元素是否是集合的成员。
a、语法:SISMEMBER KEY VALUE
b、返回值:如果成员元素是集合的成员,返回 1 。 如果成员元素不是集合的成员,或 key 不存在,返回 0 。
c、实例解释:127.0.0.1:6379> SISMEMBER k1 "a"
运行上面命令,判定a是否在k1集合中,在集合中返回1,不在集合中返回0。
8、Smembers:返回集合中的所有的成员。 不存在的集合 key 被视为空集合。
a、语法:SMEMBERS key
b、返回值:集合中的所有成员。
c、实例解释:127.0.0.1:6379> SMEMBERS k1
运行上面命令,返回k1中的所有元素。
9、Smove:将指定成员 member 元素从 source 集合移动到 destination 集合。
SMOVE 是原子性操作。
如果 source 集合不存在或不包含指定的 member 元素,则 SMOVE 命令不执行任何操作,仅返回 0 。否则, member 元素从 source 集合中被移除,并添加到 destination 集合中去。
当 destination 集合已经包含 member 元素时, SMOVE 命令只是简单地将 source 集合中的 member 元素删除。
当 source 或 destination 不是集合类型时,返回一个错误。
a、语法:SMOVE SOURCE DESTINATION MEMBER
b、返回值:如果成员元素被成功移除,返回 1 。 如果成员元素不是 source 集合的成员,并且没有任何操作对 destination 集合执行,那么返回 0 。
c、实例解释:127.0.0.1:6379> SMOVE k1 k2 "a"
运行上面命令,将元素a从k1中移动到k2中,即将a元素从k1集合中删除,并在k2集合中添加a元素。
10、Spop:用于移除集合中的指定 key 的一个或多个随机元素,移除后会返回移除的元素。
a、语法:SPOP key [count],其中 count 参数(要移除的个数)在 3.2+ 版本可用。
b、返回值:集合中元素的数量, 当集合 key 不存在时,返回 0 。
c、实例解释:
127.0.0.1:6379> SPOP k1
127.0.0.1:6379> SPOP k1 2
运行上面2条命令,第一条命令将会从k1中随机移除一个元素,并返回该元素。第二条命令将会从k1中随机移除2个元素,并返回这两个元素。
11、Srandmember:用于返回集合中的一个随机元素。
从 Redis 2.6 版本开始, Srandmember 命令接受可选的 count 参数:
- 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。
- 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。
该操作和 SPOP 相似,但 SPOP 将随机元素从集合中移除并返回,而 Srandmember 则仅仅返回随机元素,而不对集合进行任何改动。
a、语法:SRANDMEMBER KEY [count]
b、返回值:只提供集合 key 参数时,返回一个元素;如果集合为空,返回 nil 。 如果提供了 count 参数,那么返回一个数组;如果集合为空,返回空数组。
c、实例解释:
127.0.0.1:6379> SRANDMEMBER k1
127.0.0.1:6379> SRANDMEMBER k1 2
运行上面2条命令,第一条命令将会从k1中随机获取一个元素,并返回该元素。第二条命令将会从k1中随机获取2个元素,并返回这两个元素组成的集合。命令均不会对k1集合本身产生影响。
12、Srem:用于移除集合中的一个或多个成员元素,不存在的成员元素会被忽略。
当 key 不是集合类型,返回一个错误。在 Redis 2.4 版本以前, SREM 只接受单个成员值。
a、语法: SREM KEY MEMBER1..MEMBERN
b、返回值:被成功移除的元素的数量,不包括被忽略的元素。
c、实例解释:127.0.0.1:6379> SREM k1 a b
运行上面命令,会将a,b元素从k1中删除掉,并返回删掉元素的数量。
13、Sunion:返回给定集合的并集。不存在的集合 key 被视为空集。
a、语法:SUNION KEY KEY1..KEYN
b、返回值:并集成员的列表。
c、实例解释:有集合 k1 = {a,b} 、 k2 = {b,c,d}
则:127.0.0.1:6379> SUNION k1 k2
运行上面命令,将返回k1、k2的并集{a,b,c,d}。
14、Sunionstore:将给定集合的并集存储在指定的集合 destination 中。如果 destination 已经存在,则将其覆盖。
a、语法:SUNIONSTORE DESTINATION KEY KEY1..KEYN
b、返回值:结果集中的元素数量。
c、实例解释:127.0.0.1:6379> SUNIONSTORE k3 k1 k2
运行上面命令,将k1、k2的交集存储在k3中,并返回k3的元素数量。
15、Sscan:用于迭代集合中键的元素。
a、语法:SSCAN key cursor [MATCH pattern] [COUNT count]
b、返回值:数组列表。
c、实例解释:sscan 命令以及其相关命令一两句话不是很容易将明白,详细了解可以查看:https://www.cnblogs.com/meowyeon/p/8627779.html
二、存储原理
1、Redis用intset或hashtable存储set。如果元素都是整数类型,就用inset存储。如果不是整数类型,就用hashtable(数组+链表的存来储结构)。
对于redis这种存储KV数据形式的而言,它是怎么存储set的元素的呢?set在存储元素时,key就是元素的值,value为null。
另外对于intset和hashtable存在编码转换,使用intset存储必须满足下面两个条件,否则使用hashtable,条件如下:
a、集合保存的所有元素都是整数值
b、集合保存的元素数量不超过512个
2、intset数据结构
intset内部是一个数组(int8_t coentents[]数组),而且存储数据的时候是有序的,因为在查找数据的时候是通过二分查找来实现的。
typedef struct intset {
// 编码方式
uint32_t encoding;
// 集合包含的元素数量
uint32_t length;
// 保存元素的数组
int8_t contents[];
} intset;
三、应用场景
1、抽奖:利用 spop 命令可以实现抽奖功能。
2、点赞、签到、打卡功能:
例如,微博的ID是t1001,用户ID是u3001。用like:t1001来维护t1001这条微博的所有点赞用户。
点赞了这条微博:sadd like:t1001 u3001
取消点赞:srem like:t1001 u3001
是否点赞:sismember like:t1001 u3001
点赞的所有用户:smembers like:t1001
点赞数:scard like:t1001
3、还有其他功能,例如相互关注、商品筛选、商品标签等都可以利用set来完成。