目录
添加元素:sadd key element [element ...]
删除元素:srem key element [element ...]
判断元素是否在集合中:sismember key element
随机从集合返回指定个数元素:srandmember key [count]
集合
基本概念
- 集合(set)类型也是用来保存多个的字符串元素,但和列表类型不一样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素。
- 如图下图,集合user:1:follow包含着"it"、"music"、"his"、"sports"四个元素,一个集合最多可以存储2^(32-1)个元素。
- Redis除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集,合理地使用好集合类型,能在实际开发中解决很多实际问题。
命令
集合内操作
添加元素:sadd key element [element ...]
- 返回结果为添加成功的元素个数,例如:
127.0.0.1:6379> exists myset (integer) 0 127.0.0.1:6379> sadd myset a b c (integer) 3 127.0.0.1:6379> sadd myset a b (integer) 0删除元素:srem key element [element ...]
- 返回结果为成功删除元素个数,例如:
127.0.0.1:6379> srem myset a b (integer) 2 127.0.0.1:6379> srem myset hello (integer) 0计算元素个数:scard key
- scard的时间复杂度为O(1),它不会遍历集合所有元素,而是直接用Redis内部的变量,例如:
127.0.0.1:6379> scard myset (integer) 1判断元素是否在集合中:sismember key element
- 如果给定元素element在集合内返回1,反之返回0,例如:
127.0.0.1:6379> sismember myset c (integer) 1随机从集合返回指定个数元素:srandmember key [count]
- [count]是可选参数,如果不写默认为1,例如:
127.0.0.1:6379> srandmember myset 2 1) "a" 2) "c" 127.0.0.1:6379> srandmember myset "d"从集合随机弹出元素:spop key
- spop操作可以从集合中随机弹出一个元素,例如下面代码是一次spop后,集合元素变为"d b a":
127.0.0.1:6379> spop myset "c" 127.0.0.1:6379> smembers myset 1) "d" 2) "b" 3) "a"
- 需要注意的是Redis从3.2版本开始,spop也支持[count]参数。
- srandmember和spop都是随机从集合选出元素,两者不同的是spop命令执行后,元素会从集合中删除,而srandmember不会。
获取所有元素:smembers key
- 下面代码获取集合myset所有元素,并且返回结果是无序的:
127.0.0.1:6379> smembers myset 1) "d" 2) "b" 3) "a"
- smembers和lrange、hgetall都属于比较重的命令,如果元素过多存在阻塞Redis的可能性,这时候可以使用sscan来完成
集合间操作
- 现在有两个集合,它们分别是user:1:follow和user:2:follow:
127.0.0.1:6379> sadd user:1:follow it music his sports (integer) 4 127.0.0.1:6379> sadd user:2:follow it news ent sports (integer) 4求多个集合的交集:sinter key [key ...]
- 例如下面代码是求user:1:follow和user:2:follow两个集合的交集,返回结果是sports、it:
127.0.0.1:6379> sinter user:1:follow user:2:follow 1) "sports" 2) "it"求多个集合的并集:suinon key [key ...]
- 例如下面代码是求user:1:follow和user:2:follow两个集合的并集,返回结果是sports、it、his、news、music、ent:
127.0.0.1:6379> sunion user:1:follow user:2:follow 1) "sports" 2) "it" 3) "his" 4) "news" 5) "music" 6) "ent"求多个集合的差集:sdiff key [key ...]
- 例如下面代码是求user:1:follow和user:2:follow两个集合的差集,返回结果是music和his:
127.0.0.1:6379> sdiff user:1:follow user:2:follow 1) "music" 2) "his"
将交集、并集、差集的结果保存
sinterstore destination key [key ...] suionstore destination key [key ...] sdiffstore destination key [key ...]
- 集合间的运算在元素较多的情况下会比较耗时,所以提供了上面三个命令(原命令+store)将集合间交集、并集、差集的结果保存在destination key中
- 例如下面操作将user:1:follow和user:2:follow两个集合的交集结果保存在user:1_2:inter中,user:1_2:inter本身也是集合类型:
127.0.0.1:6379> sinterstore user:1_2:inter user:1:follow user:2:follow (integer) 2 127.0.0.1:6379> type user:1_2:inter set 127.0.0.1:6379> smembers user:1_2:inter 1) "it" 2) "sports"集合常用命令时间复杂度
内部编码
intset(整数集合)
- 当集合中的元素都是整数且元素个数小于set-max-intset-entries配置(默认512个)时,Redis会选用intset来作为集合的内部实现,从而减少内存的使用。
hashtable(哈希表)
- 当集合类型无法满足intset的条件时,Redis会使用hashtable作为集合的内部实现。
当元素个数较少且都为整数时,内部编码为intset
127.0.0.1:6379> sadd setkey 1 2 3 4 (integer) 4 127.0.0.1:6379> object encoding setkey "intset"当元素个数超过512个,内部编码变为hashtable
127.0.0.1:6379> sadd setkey 1 2 3 4 5 6 ... 512 513 (integer) 509 127.0.0.1:6379> scard setkey (integer) 513 127.0.0.1:6379> object encoding listkey "hashtable"当某个元素不为整数时,内部编码也会变为hashtable
127.0.0.1:6379> sadd setkey a (integer) 1 127.0.0.1:6379> object encoding setkey "hashtable"应用场景
- 集合类型比较典型的使用场景是标签(tag)。
- 例如一个电子商务的网站会对不同标签的用户做不同类型的推荐,比如对数码产品比较感兴趣的人,在各个页面或者通过邮件的形式给他们推荐最新的数码产品,通常会为网站带来更多的利益。
- 给用户添加标签
sadd user:1:tags tag1 tag2 tag5 sadd user:2:tags tag2 tag3 tag5 ... sadd user:k:tags tag1 tag2 tag4 ...
- 给标签添加用户
sadd tag1:users user:1 user:3 sadd tag2:users user:1 user:2 user:3 ... sadd tagk:users user:1 user:2 ...
- 用户和标签的关系维护应该在一个事务内执行,防止部分命令失败造成的数据不一致
- 删除用户下的标签
srem user:1:tags tag1 tag5 ...
- 删除标签下的用户
srem tag1:users user:1 srem tag5:users user:1 ...
- 计算用户共同感兴趣的标签
- 可以使用sinter命令,来计算用户共同感兴趣的标签,如下代码所示:
sinter user:1:tags user:2:tags
- 前面只是给出了使用Redis集合类型实现标签的基本思路,实际上一个标签系统远比这个要复杂得多,不过集合类型的应用场景通常为以下几种:
sadd=Tagging 标签 spop/srandmember=Random item 生成随机数,比如抽奖 sadd+sinter=Social Graph 社交需求
- 【注】参考《Redis开发与运维》
版权声明:本文为baidu_41388533原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。


