set类型是string类型的集合,其特点是集合元素无序且不重复,每个集合最多可以存储 232 – 1 个元素(40多亿)

127.0.0.1:6379> sadd myset hello //往指定集合中添加元素
 (integer) 1
 127.0.0.1:6379> sadd myset hello //集合中的元素值不能重复
 (integer) 0
 127.0.0.1:6379> sadd myset chris 
 (integer) 1
 127.0.0.1:6379> sadd myset tony
 (integer) 1
 127.0.0.1:6379> SMEMBERS myset //查看指定集合的元素
 1) "chris"
 2) "tony"
 3) "hello"
 127.0.0.1:6379> SISMEMBER myset chris //检查指定集合的元素是否存在
 (integer) 1
 127.0.0.1:6379> SISMEMBER myset php
 (integer) 0
======================================
 127.0.0.1:6379> scard myset //获取集合中元素的个数
 (integer) 4
 127.0.0.1:6379> srem myset tony //移除指定集合中的元素
 (integer) 1
 127.0.0.1:6379> scard myset //查看集合总元素的个数
 (integer) 3
 127.0.0.1:6379> SMEMBERS myset
 1) "may"
 2) "chris"
 3) "hello"
======================================
 127.0.0.1:6379> SRANDMEMBER myset //随机抽取一个元素
 "chris"
 127.0.0.1:6379> SRANDMEMBER myset
 "hello"
 127.0.0.1:6379> SRANDMEMBER myset
 "may"
 127.0.0.1:6379> SRANDMEMBER myset 2//随机抽取指定个数元素
 1) "chris"
 2) "may"
 127.0.0.1:6379> SRANDMEMBER myset 2
 1) "chris"
 2) "hello"
======================================
 127.0.0.1:6379> SPOP myset //随机移除一个元素
 "may"
 127.0.0.1:6379> SPOP myset 2 //随机移除指定个数元素
 1) "chris"
 2) "hello"
 127.0.0.1:6379> SMEMBERS myset
 (empty array)
======================================
 127.0.0.1:6379> SMEMBERS myset
 1) "may"
 2) "chris"
 3) "tony"
 4) "hello"
 127.0.0.1:6379> SMEMBERS myset2
 1) "may"
 2) "chris"
 3) "hello"
 127.0.0.1:6379> SMOVE myset myset2 tony //将指定集合的值移动到另一个集合
 (integer) 1
 127.0.0.1:6379> SMEMBERS myset
 1) "may"
 2) "chris"
 3) "hello"
 127.0.0.1:6379> SMEMBERS myset2
 1) "may"
 2) "chris"
 3) "tony"
 4) "hello"
======================================
 交集SINTER 、差集SDIFF 、并集SUNION 
 127.0.0.1:6379> SMEMBERS myset
 1) "may"
 2) "chris"
 3) "hello"
 127.0.0.1:6379> SMEMBERS myset2
 1) "may"
 2) "chris"
 3) "tony"
 4) "hello"
 127.0.0.1:6379> SDIFF myset myset2 //差集,左对比右
 (empty array)
 127.0.0.1:6379> SDIFF myset2 myset 
 1) "tony"
 127.0.0.1:6379> SINTER myset myset2 //交集,共同的(共同好友实现)
 1) "may"
 2) "chris"
 3) "hello"
 127.0.0.1:6379> SUNION myset myset2 //并集(去重合并)
 1) "chris"
 2) "may"
 3) "tony"
 4) "hello"

总结

set类型是无序不重复的,可以存储40多亿元素

应用场景

1、数据去重

将需要对比的数据放入集合中进行去重 SUNION myset myset2

2、兴趣热点

每位用户首次使用今日头条时会设置3项爱好的内容,但是后期为了增加用户的活跃度、兴趣点,必须让用户对其他信息类别逐渐产生兴趣,增加客户留存度,如何实现?

系统分析出各个分类的最新或最热点信息条目并组织成set集合,随机挑选其中部分信息,配合用户关注信息分类中的热点信息组织成展示的全信息集合
解决方案 : srandmember key [count] , spop key [count]


3、随机推荐类信息检索

例如热点歌单推荐,热点新闻推荐,热卖旅游线路,应用APP推荐,大V推荐等

4、共同好友,关注

将A用户所有关注的人放在一个set集合中,将它的粉丝也放在一个集合中(实现:共同关注、共同爱好)

需要注意的是,如果你用的是Redis Cluster集群,对于sinter、smove这种操作多个key的命令,要求这两个key必须存储在同一个slot(槽位)中,否则会报出 (error) CROSSSLOT Keys in request don’t hash to the same slot 错误。

Redis Cluster一共有16384个slot,每个key都是通过哈希算法CRC16(key)获取数值哈希,再模16384来定位slot的。要使得两个key处于同一slot,除了两个key一模一样,还有没有别的方法呢?答案是肯定的,Redis提供了一种Hash Tag的功能,在key中使用{}括起key中的一部分,在进行 CRC16(key) mod 16384 的过程中,只会对{}内的字符串计算,例如friend_set:{123456}和fans_set:{123456},分别表示用户123456的好友集合和粉丝集合,在定位slot时,只对{}内的123456进行计算,所以这两个集合肯定是在同一个slot内的,当用户123456关注某个粉丝时,就可以通过smove命令将这个粉丝从用户123456的粉丝集合移动到好友集合。

相比于通过srem命令先将这个粉丝从粉丝集合中删除,再通过sadd命令将这个粉丝加到好友集合,smove命令的优势是它是原子性的,不会出现这个粉丝从粉丝集合中被删除,却没有加到好友集合的情况。

然而,对于通过sinter获取共同好友而言,Hash Tag则无能为力,例如,要用sinter去获取用户123456和456789两个用户的共同好友,除非我们将key定义为{friend_set}:123456和{friend_set}:456789,否则不能保证两个key会处于同一个slot,但是如果真这样做的话,所有用户的好友集合都会堆积在同一个slot中,数据分布会严重不均匀,不可取,所以,在实战中使用Redis Cluster时,sinter这个命令其实是不适合作用于两个不同用户对应的集合的(同理其它操作多个key的命令)。

5、黑名单/白名单

  经常有业务出于安全性方面的考虑,需要设置用户黑名单、ip黑名单、设备黑名单等,set类型适合存储这些黑名单数据,sismember命令可用于判断用户、ip、设备是否处于黑名单之中。

6、权限集合

集团公司共具有12000名员工,内部OA系统中具有700多个角色,3000多个业务操作,23000多种数据,每位员工具有一个或多个角色,如何快速进行业务操作的权限校验?