一、基本了解
集合类型也是保存多个字符串类型的元素的,但和列表类型不同的是,集合中1)元素之间是⽆序 的2)元素不允许重复,如图2-24所⽰。⼀个集合中最多可以存储 32 2 − 1 个元素。Redis除了⽀持 集合内的增删查改操作,同时还⽀持多个集合取交集、并集、差集,合理地使⽤好集合类型,能在实 际开发中解决很多问题。
图2-24集合类型
二、普通命令
2.1、SADD
将⼀个或者多个元素添加到set中。注意,重复的元素⽆法添加到set中。
语法:
SADD key member [member ...]
命令有效版本:1.0.0之后
时间复杂度:O(1)
返回值:本次添加成功的元素个数。
⽰例:
redis> SADD myset "Hello"(integer) 1redis> SADD myset "World"(integer) 1redis> SADD myset "World"(integer) 0redis> SMEMBERS myset1) "Hello"2) "World"
2.1、SMEMBERS
获取⼀个set中的所有元素,注意,元素间的顺序是⽆序的。
语法:
SMEMBERS key
命令有效版本:1.0.0之后
时间复杂度:O(N)
返回值:所有元素的列表。
⽰例:
redis> SADD myset "Hello"(integer) 1redis> SADD myset "World"(integer) 1redis> SMEMBERS myset1) "Hello"2) "World"
2.2、SISMEMBER
判断⼀个元素在不在set中。
语法:
SISMEMBER key member
命令有效版本:1.0.0之后
时间复杂度:O(1)
返回值:1表⽰元素在set中。0表⽰元素不在set中或者key不存在。
⽰例:
redis> SADD myset "one"(integer) 1redis> SISMEMBER myset "one"(integer) 1redis> SISMEMBER myset "two"(integer) 0
2.3、SCARD
获取⼀个set的基数(cardinality),即set中的元素个数。
语法:
SCARD key
命令有效版本:1.0.0之后
时间复杂度:O(1)
返回值:set内的元素个数。
⽰例:
redis> SADD myset "Hello"(integer) 1redis> SADD myset "World"(integer) 1redis> SCARD myset(integer) 2
2.4、SPOP
从set中删除并返回⼀个或者多个元素。注意,由于set内的元素是⽆序的,所以取出哪个元素实际是 未定义⾏为,即可以看作随机的。
语法:
SPOP key [count]
命令有效版本:1.0.0之后
时间复杂度:O(N),n是count
返回值:取出的元素。
⽰例:
redis> SADD myset "one"(integer) 1redis> SADD myset "two"(integer) 1redis> SADD myset "three"(integer) 1redis> SPOP myset"one"redis> SMEMBERS myset1) "three"2) "two"redis> SADD myset "four"(integer) 1redis> SADD myset "five"(integer) 1redis> SPOP myset 31) "three"2) "four"3) "two"redis> SMEMBERS myset1) "five"
2.4、SMOVE
将⼀个元素从源set取出并放⼊⽬标set中。
语法:
SMOVE source destination member
命令有效版本:1.0.0之后
时间复杂度:O(1)
返回值:1表⽰移动成功,0表⽰失败。
⽰例:
redis> SADD myset "one"(integer) 1redis> SADD myset "two"(integer) 1redis> SADD myotherset "three"(integer) 1redis> SMOVE myset myotherset "two"(integer) 1redis> SMEMBERS myset1) "one"redis> SMEMBERS myotherset1) "three"2) "two"
2.5、SREM
将指定的元素从set中删除。
语法:
SREM key member [member ...]
时间复杂度:O(N),N是要删除的元素个数
返回值:本次操作删除的元素个数。
⽰例:
redis> SADD myset "one"(integer) 1redis> SADD myset "two"(integer) 1redis> SADD myset "three"(integer) 1redis> SREM myset "one"(integer) 1redis> SREM myset "four"(integer) 0redis> SMEMBERS myset1) "three"2) "two"
三、集合间操作
交集(inter)、并集(union)、差集(diff)的概念如图2-25所⽰。
图2-25集合求交集、并集、差集
3.1、SINTER
获取给定set的交集中的元素。
语法:
SINTER key [key ...]
命令有效版本:1.0.0之后
时间复杂度:O(N*M),N是最⼩的集合元素个数.M是最⼤的集合元素个数
返回值:交集的元素。
⽰例:
redis> SADD key1 "a"(integer) 1redis> SADD key1 "b"(integer) 1redis> SADD key1 "c"(integer) 1redis> SADD key2 "c"(integer) 1redis> SADD key2 "d"(integer) 1redis> SADD key2 "e"(integer) 1redis> SINTER key1 key21) "c"
3.2、SINTERSTORE
获取给定set的交集中的元素并保存到⽬标set中。
语法:
SINTERSTORE destination key [key ...]
命令有效版本:1.0.0之后
时间复杂度:O(N*M),N是最⼩的集合元素个数.M是最⼤的集合元素个数
返回值:交集的元素个数。
⽰例:
redis> SADD key1 "a"(integer) 1redis> SADD key1 "b"(integer) 1redis> SADD key1 "c"(integer) 1redis> SADD key2 "c"(integer) 1redis> SADD key2 "d"(integer) 1redis> SADD key2 "e"(integer) 1redis> SINTERSTORE key key1 key2(integer) 1redis> SMEMBERS key1) "c"
3.3、SUNION
获取给定set的并集中的元素。
语法:
SUNION key [key ...]
命令有效版本:1.0.0之后
时间复杂度:O(N),N给定的所有集合的总的元素个数.
返回值:并集的元素。
⽰例:
redis> SADD key1 "a"(integer) 1redis> SADD key1 "b"(integer) 1redis> SADD key1 "c"(integer) 1redis> SADD key2 "c"(integer) 1redis> SADD key2 "d"(integer) 1redis> SADD key2 "e"(integer) 1redis> SUNION key1 key21) "a"2) "c"3) "e"4) "b"5) "d"
3.4、SUNIONSTORE
获取给定set的并集中的元素并保存到⽬标set中。
语法:
SUNIONSTORE destination key [key ...]
命令有效版本:1.0.0之后
时间复杂度:O(N),N给定的所有集合的总的元素个数.
返回值:并集的元素个数。
⽰例:
redis> SADD key1 "a"(integer) 1redis> SADD key1 "b"(integer) 1redis> SADD key1 "c"(integer) 1redis> SADD key2 "c"(integer) 1redis> SADD key2 "d"(integer) 1redis> SADD key2 "e"(integer) 1redis> SUNIONSTORE key key1 key2(integer) 5redis> SMEMBERS key1) "a"2) "c"3) "e"4) "b"5) "d"
3.5、SDIFF
获取给定set的差集中的元素。
语法:
SDIFF key [key ...]
命令有效版本:1.0.0之后
时间复杂度:O(N),N给定的所有集合的总的元素个数
返回值:差集的元素
⽰例:
redis> SADD key1 "a"(integer) 1redis> SADD key1 "b"(integer) 1redis> SADD key1 "c"(integer) 1redis> SADD key2 "c"(integer) 1redis> SADD key2 "d"(integer) 1redis> SADD key2 "e"(integer) 1redis> SDIFF key1 key21) "a"2) "b"
3.6、SDIFFSTORE
获取给定set的差集中的元素并保存到⽬标set中。
SDIFFSTORE destination key [key ...]
命令有效版本:1.0.0之后
时间复杂度:O(N),N给定的所有集合的总的元素个数
返回值:差集的元素个数
⽰例:
redis> SADD key1 "a"(integer) 1redis> SADD key1 "b"(integer) 1redis> SADD key1 "c"(integer) 1redis> SADD key2 "c"(integer) 1redis> SADD key2 "d"(integer) 1redis> SADD key2 "e"(integer) 1redis> SDIFFSTORE key key1 key2(integer) 2redis> SMEMBERS key1) "a"2) "b"
3.7、命令⼩结
表2-6集合类型命令
命令 | 时间复杂度 |
---|---|
sadd key element[element...] | O(k),k是元素个数 |
srem key element[element...] | O(k),k是元素个数 |
scard key | O(1) |
sismember key element | O(1) |
srandmember key[count] | O(n),n是count |
spop key[count] | O(n),n是count |
smembers key | O(k),k是元素个数 |
sinter key[key...] sitnerstore | O(m*k),k是⼏个集合中元素最⼩的个数,m是键个 数 |
sunion key[key...] sunionstore | O(k),k是多个集合的元素个数总和 |
sdiff key[key...] sdiffstore | O(k),k是多个集合的元素个数总和 |
四、内部编码
集合类型的内部编码有两种:
- intset(整数集合):当集合中的元素都是整数并且元素的个数⼩于set-max-intset-entries配置 (默认512个)时,Redis会选⽤intset来作为集合的内部实现,从⽽减少内存的使⽤。
- hashtable(哈希表):当集合类型⽆法满⾜intset的条件时,Redis会使⽤hashtable作为集合 的内部实现。
1)当元素个数较少并且都为整数时,内部编码为intset:
127.0.0.1:6379> sadd setkey 1 2 3 4(integer) 4127.0.0.1:6379> object encoding setkey"intset"
2)当元素个数超过512个,内部编码为hashtable:
127.0.0.1:6379> sadd setkey 1 2 3 4(integer) 513127.0.0.1:6379> object encoding setkey"hashtable"
3)当存在元素不是整数时,内部编码为hashtable:
127.0.0.1:6379> sadd setkey a(integer) 1127.0.0.1:6379> object encoding setkey"hashtable"
五、使⽤场景
集合类型⽐较典型的使⽤场景是标签(tag)。例如A⽤⼾对娱乐、体育板块⽐较感兴趣,B⽤⼾ 对历史、新闻⽐较感兴趣,这些兴趣点可以被抽象为标签。有了这些数据就可以得到喜欢同⼀个标签 的⼈,以及⽤⼾的共同喜好的标签,这些数据对于增强⽤⼾体验和⽤⼾黏度都⾮常有帮助。例如⼀个 电⼦商务⽹站会对不同标签的⽤⼾做不同的产品推荐。
下⾯的演⽰通过集合类型来实现标签的若⼲功能。
1)给⽤⼾添加标签
sadd user:1:tags tag1 tag2 tag5sadd user:2:tags tag2 tag3 tag5...sadd user:k:tags tag1 tag2 tag4
2)给标签添加⽤⼾
sadd tag1:users user:1 user:3sadd tag2:users user:1 user:2 user:3...sadd tagk:users user:1 user:4 user:9 user:28
3)删除⽤⼾下的标签
srem user:1:tags tag1 tag5...
4)删除标签下的⽤⼾
srem tag1:users user:1srem tag5:users user:1...
5)计算⽤⼾的共同兴趣标签
sinter user:1:tags user:2:tags