redis-----05-----redis-set结构以及应用

1 set

Redis的set(集合)内部的键值对是无序的、唯一的。它的内部实现了一个所有value为null的特殊字典。就相当于上面的哈希,只不过value值为null。例如哈希是cmd key key value,那么set就是cmd key key,所以末尾的key当成value了。

如果set集合存储的都是整数类型,那么会使用一个数组存储,此时集合会是一个有序的集合,这样让我们能快速进行交并差运算。(老师讲的)

set(集合)由于其特殊去重复的功能,我们可以用来存储活动中中奖的用户的ID,这样可以保证一个用户不会中奖两次。

2 基础命令

2.1 SADD、SCARD、SMEMBERS、SISMEMBER

# 添加一个或多个指定的member元素到集合的 key中。
# 1)如果已经在集合key中存在member则忽略。
# 2)如果 集合key 不存在,则新建集合key,并添加member元素到集合key中。
# 3)如果key 的类型不是集合则返回错误。
# 返回值integer-reply:返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素。
SADD key member [member ...] 
# 计算集合元素个数。
# 返回值integer-reply: 返回集合的基数(元素的数量),如果key不存在,则返回 0。
SCARD key 

# 返回key集合所有的元素。该命令的作用与使用一个参数的SINTER 命令作用相同。
# 返回值array-reply:返回集合中的所有元素。
SMEMBERS key 
# 返回成员 member 是否是存储的 集合key 的成员。
# 返回值integer-reply,详细说明:
# 1)如果member元素是集合key的成员,则返回1。
# 2)如果member元素不是key的成员,或者集合key不存在,则返回0。
SISMEMBER key member
  • 演示SADD、SCARD(主要按照上面的描述执行):
    在这里插入图片描述
  • 演示SMEMBERS、SISMEMBER(主要按照上面的描述执行):
    在这里插入图片描述

2.2 SRANDMEMBER、SPOP

# 随机返回key集合中的一个或者多个元素,不删除这些元素。
# 注意:
# 1)仅提供key参数,那么随机返回key集合中的一个元素,但不删除。
# 2)Redis 2.6开始,可以接受 count 参数.
# 3)如果count是整数且小于元素的个数,返回含有 count 个不同的元素的数组。
# 4)如果count是个整数且大于集合中元素的个数时,仅返回整个集合的所有元素。
# 5)当count是负数且小于元素的个数,则会返回一个包含count的绝对值的个数元素的数组。
# 6)如果count的绝对值大于元素的个数,则返回的结果集里会出现一个元素出现多次的情况。
# 7)仅提供key参数时,该命令作用类似于SPOP命令,不同的是SPOP命令会将被选择的随机元素从集合中移除,而SRANDMEMBER仅仅是返回该随记元素,而不做任何操作。该条和1)的意思是一样的。
SRANDMEMBER key [count] 

# 从存储在key的集合中移除并返回一个或多个随机元素。count参数将在更高版本中提供,但是在2.6、2.8、3.0中不可用。
# 注意:
# 1)仅提供key参数,那么随机返回key集合中的一个元素,并删除该元素。
# 2)如果count是整数且小于元素的个数,返回含有 count 个不同的元素的数组,并删除返回的元素。
# 3)如果count是个整数且大于集合中元素的个数时,仅返回整个集合的所有元素,并删除集合所有元素。
# 4)如果count只要是个负数,那么会报越界错误。
# 返回值bulk-string-reply:返回被删除的元素,或者当key不存在时返回nil。
# 下面测试发现,当key不存在时,注意:不带count参数返回nil,带count参数返回空数组。
SPOP key [count]
  • 1)演示SRANDMEMBER(主要按照上面的描述执行):由于比较长,所以截取文本。
# tyy这个set集合中的元素。
192.168.1.9:6379> SMEMBERS tyy
1) "f"
2) "a"
3) "g"
4) "c"
5) "x"
6) "z"
7) "b"
8) "y"

# 1)仅提供key参数,那么随机返回key集合中的一个元素,但不删除。
192.168.1.9:6379> SRANDMEMBER tyy
"x"
192.168.1.9:6379> SRANDMEMBER tyy
"f"
192.168.1.9:6379> SRANDMEMBER tyy
"g"
192.168.1.9:6379> SMEMBERS tyy
1) "f"
2) "a"
3) "g"
4) "c"
5) "x"
6) "z"
7) "b"
8) "y"

# 3)如果count是整数且小于元素的个数,返回含有 count 个不同的元素的数组。
192.168.1.9:6379> SRANDMEMBER tyy 3
1) "x"
2) "c"
3) "y"
192.168.1.9:6379> SRANDMEMBER tyy 3
1) "f"
2) "z"
3) "y"

# 4)如果count是个整数且大于集合中元素的个数时,仅返回整个集合的所有元素。
192.168.1.9:6379> SRANDMEMBER tyy 10
1) "f"
2) "a"
3) "g"
4) "c"
5) "x"
6) "z"
7) "b"
8) "y"
192.168.1.9:6379> SRANDMEMBER tyy 10
1) "f"
2) "a"
3) "g"
4) "c"
5) "x"
6) "z"
7) "b"
8) "y"

# 5)当count是负数且小于元素的个数,则会返回一个包含count的绝对值的个数元素的数组。
192.168.1.9:6379> SRANDMEMBER tyy -3
1) "f"
2) "x"
3) "c"
192.168.1.9:6379> SRANDMEMBER tyy -3
1) "z"
2) "x"
3) "y"

# 6)如果count的绝对值大于元素的个数,则返回的结果集里会出现一个元素出现多次的情况。
# 下面可以看到返回的集合有重复的元素。
192.168.1.9:6379> SRANDMEMBER tyy -10
 1) "b"
 2) "f"
 3) "z"
 4) "x"
 5) "b"
 6) "z"
 7) "g"
 8) "b"
 9) "b"
10) "x"
192.168.1.9:6379> SRANDMEMBER tyy -10
 1) "g"
 2) "b"
 3) "f"
 4) "y"
 5) "y"
 6) "c"
 7) "x"
 8) "f"
 9) "x"
10) "f"
192.168.1.9:6379> 
  • 2)演示SPOP(主要按照上面的描述执行):同样由于比较长,所以截取文本。
# tyy这个set集合中的元素。
192.168.1.9:6379> SMEMBERS tyy
1) "f"
2) "a"
3) "g"
4) "c"
5) "x"
6) "z"
7) "b"
8) "y"

# 1)仅提供key参数,那么随机返回key集合中的一个元素,并删除该元素。
192.168.1.9:6379> SPOP tyy 
"b"
192.168.1.9:6379> SMEMBERS tyy
1) "f"
2) "a"
3) "g"
4) "c"
5) "x"
6) "z"
7) "y"

# 2)如果count是整数且小于元素的个数,返回含有 count 个不同的元素的数组,并删除返回的元素。
192.168.1.9:6379> SPOP tyy 2
1) "y"
2) "x"
192.168.1.9:6379> SMEMBERS tyy
1) "f"
2) "a"
3) "g"
4) "c"
5) "z"

# 3)如果count是个整数且大于集合中元素的个数时,仅返回整个集合的所有元素,并删除集合所有元素。
192.168.1.9:6379> SPOP tyy 10
1) "a"
2) "f"
3) "c"
4) "g"
5) "z"
192.168.1.9:6379> SMEMBERS tyy
(empty array)

# 由于此时tyy这个set集合没有元素了,需要增加元素才能继续往后演示。
192.168.1.9:6379> SADD tyy a b c d e
(integer) 5

# 4)如果count只要是个负数,那么会报越界错误。
192.168.1.9:6379> SPOP tyy -2
(error) ERR value is out of range, must be positive
192.168.1.9:6379> SMEMBERS tyy
1) "a"
2) "c"
3) "b"
4) "d"
5) "e"
192.168.1.9:6379> SPOP tyy -10
(error) ERR value is out of range, must be positive
192.168.1.9:6379> 
192.168.1.9:6379> 

# 返回值bulk-string-reply:返回被删除的元素,或者当key不存在时返回nil。
# 下面测试发现,当key不存在时,注意:不带count参数返回nil,带count参数返回空数组。
192.168.1.9:6379> EXISTS tyy111
(integer) 0
192.168.1.9:6379> SPOP tyy111
(nil)
192.168.1.9:6379> SPOP tyy111 2
(empty array)
192.168.1.9:6379>

2.3 SDIFF、SINTER、SUNION

# 返回一个集合与给定集合的差集的元素。不存在的key认为是空集。
# 返回值array-reply:返回一个集合与给定集合的差集的元素。
SDIFF key [key ...] 

# 返回指定所有的集合的成员的交集。
# 如果key不存在则被认为是一个空的集合,当给定的集合为空的时候,结果也为空。(一个集合为空,结果一直为空)
# 返回值array-reply: 指定所有的集合的成员的交集。
SINTER key [key ...] 

# 返回给定的多个集合的并集中的所有成员。
# 不存在的key可以认为是空的集合。
# 返回值array-reply:返回给定的多个集合的并集中的所有成员。
SUNION key [key ...]
  • 1)演示SDIFF。
# 差集就是我有,你没有的。所以它会返回我有,你没有的结果集。注意SDIFF的key的前后顺序,因为前面属于我,后面的key属于你。多个key时会先计算前面的差集,然后再与下一个集合进行差集运算。
# 1)两个key的差集运算。比较简单。
# 解释:因为s1、s2都有c,所以会被去掉。然后因为SDIFF时,s1排在前面,所以会返回s1有s2没有的结果集,这就是差集运算。
192.168.1.9:6379> SADD s1 a b c
(integer) 3
192.168.1.9:6379> SADD s2 c d e
(integer) 3
192.168.1.9:6379> SDIFF s1 s2
1) "a"
2) "b"

# 2)多个key的差集运算。
# 下面给出两个关于多个key的差集运算例子。
# 例子1:
# 解释:因为SDIFF时,set1、set2排在前面,所以先计算两者的差集。得出:a b d。
# 然后再与set3运算:即a b d 与 a c e作差集,因为a b d这个中间集合排在前面,所以得出:b d。
192.168.1.9:6379> SADD set1 a b c d
(integer) 4
192.168.1.9:6379> SADD set2 c
(integer) 1
192.168.1.9:6379> SADD set3 a c e
(integer) 3
192.168.1.9:6379> SDIFF set1 set2 set3
1) "b"
2) "d"
192.168.1.9:6379> 

# 例子2:
# 与例子1同理,SDIFF先算set11、set22的结果集,得出:b d这个中间结果集。
# 然后b d 与 o p q作差集运算,因为b d排在前面,所以返回b d。
192.168.1.9:6379> SADD set11 a b c d 
(integer) 4
192.168.1.9:6379> SADD set22 a c f 
(integer) 3
192.168.1.9:6379> SADD set33 o p q 
(integer) 3
192.168.1.9:6379> SDIFF set11 set22 set33
1) "b"
2) "d"

# 3)不存在的key认为是空集。
192.168.1.9:6379> 
192.168.1.9:6379> EXISTS tyy111
(integer) 0
192.168.1.9:6379> EXISTS s111
(integer) 0
192.168.1.9:6379> EXISTS s1
(integer) 1
192.168.1.9:6379> SDIFF s111 s1
(empty array)

# 注意,如果上面的s1和不存在的s111换个位置,那么会返回s1的元素,因为在我的redis-cli它是存在的。
192.168.1.9:6379> SMEMBERS s1
1) "a"
2) "c"
3) "b"
192.168.1.9:6379> SDIFF s1 s111
1) "a"
2) "b"
3) "c"
  • 2)演示SINTER。多个key的和差集一样,先运算前面的key,得出中间结果集后再和后面的key运算。
    两个key的。
    在这里插入图片描述
    多个key的。
    在这里插入图片描述

  • 3)演示SUNION。多个key的和差集一样,先运算前面的key,得出中间结果集后再和后面的key运算。
    两个key的。
    在这里插入图片描述
    多个key的。
    在这里插入图片描述

3 存储结构

如果set集合存储的都是整数类型,那么会使用一个数组存储,此时集合会是一个有序的集合(可以认为是内部有序,方便理解),这样让我们能快速进行交并差运算。否则使用字典存储。

4 应用

4.1 抽奖

# 添加抽奖用户。Award:1中:Award代表抽奖这个功能,1代表第一次抽奖,即抽奖id。
SADD Award:1 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010
# 查看所有抽奖用户 
SMEMBERS Award:1

# 下面开始抽奖: 
# 1)抽取3名幸运用户,这三名可以重复抽奖。
# 下面看到,随机抽出来的用户可能是重复的。
SRANDMEMBER Award:1 3
SRANDMEMBER Award:1 3

# 2)如果抽取一等奖1名,二等奖2名,三等奖3名,且抽奖后的人不能再抽取,该如何操作?
# 分析,实际场景一般三等奖的都是最先抽的,所以下面会先抽三等奖。然后因为抽奖之后不能再抽取,那么不能使用SRANDMEMBER,而是使用SPOP。
SMEMBERS Award:1
# 抽三等奖
SPOP Award:1 3
# 抽二等奖
SPOP Award:1 2
# 抽一等奖
SPOP Award:1 1

注意:因为下面我的redis版本不支持SPOP的count参数,我的版本是windows redis-cli 3.0.504版本。
不支持SPOP的count参数的结果:
在这里插入图片描述
支持SPOP的count参数的结果:
在这里插入图片描述

4.2 共同关注

抖音、微博这些APP都有共同关注的功能,那么他们是如何实现的呢?
实际不难,共同关注的功能我们可以使用交集去处理。例如A关注了一些人,B也关注了一些人,那么对A和B进行取交集,即可得到共同关注的人。
例如:
在这里插入图片描述

4.3 推荐好友

推荐好友的功能也不难,例如A关注了一些好友,B也关注了一些好友,那么对A和B进行取差集,即可得到我有而你没有的好友。这样就达到了推荐好友的功能,即可能认识的人。
例如:经过下面的差集运算,就得到B可能认识的人。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值