Skip to content

集合

集合(set)类型也是用来保存多个字符串元素,但和列表类型不一样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素。

Redis 除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集,合理地用好集合类型,能在实际开发中解决很多实际问题。

命令

集合内操作

添加元素

sadd key element [element...]

返回结果为添加成功的元素个数:

1
2
3
4
5
6
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...]

返回结果为成功删除元素个数,例如:

1
2
3
4
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 内部的变量,例如:

1
2
127.0.0.1:6379> scard myset
(integer) 1

判断元素是否在集合中

sismember key element

如果给定元素 element 在集合内返回 1,反之返回 0:

1
2
127.0.0.1:6379> sismember myset c
(integer) 1

随机从集合返回指定个数元素

srandmember key [count]

[count] 是可选参数,如果不写默认为 1,例如:

1
2
3
4
5
127.0.0.1:6379> srandmember myset 2
1) "b"
2) "d"
127.0.0.1:6379> srandmember myset
"a"

从集合随机弹出元素

spop key

spop 操作可以从集合中随机弹出一个元素

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
127.0.0.1:6379> smembers myset
1) "a"
2) "c"
3) "b"
4) "g"
5) "d"
6) "f"
7) "e"
127.0.0.1:6379> spop myset
"g"
127.0.0.1:6379> smembers myset
1) "a"
2) "c"
3) "b"
4) "d"
5) "f"
6) "e"

Redis 3.2 版本开始,spop 也支持 [count] 参数

1
2
3
4
5
6
7
8
127.0.0.1:6379> spop myset 2
1) "f"
2) "a"
127.0.0.1:6379> smembers myset
1) "c"
2) "b"
3) "d"
4) "e"

获取所有元素

smembers key

下面获取集合 myset 所有元素,并且返回结果是无序的:

1
2
3
4
5
127.0.0.1:6379> smembers myset
1) "c"
2) "b"
3) "d"
4) "e"

smembers 和 lrange、hgetall 都属于比较重的命令,如果元素过多存在阻塞 Redis 的可能性,这时候可以使用 sscan 来完成

集合间操作

现在有两个集合,它们分别是 user:1:followuser:2:follow:

1
2
3
4
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:followuser:2:follow 两个集合的交集,返回结果是 sports、it:

1
2
3
127.0.0.1:6379> sinter user:1:follow user:2:follow
1) "sports"
2) "it"

求多个集合的并集

sunion key [key ...]

1
2
3
4
5
6
7
127.0.0.1:6379> sunion user:1:follow user:2:follow
1) "ent"
2) "sports"
3) "news"
4) "music"
5) "it"
6) "his"

求多个集合的差集

sdiff key [key ...]

1
2
3
4
5
6
7
127.0.0.1:6379> sdiff user:1:follow user:2:follow
1) "music"
2) "his"

127.0.0.1:6379> sdiff user:2:follow user:1:follow
1) "ent"
2) "news"

将交集、并集、差集的结果保存

1
2
3
sinterstore destination key [key ...]
sunionstore destination key [key ...]
sdiffstore destination key [key ...]
1
2
3
4
5
6
7
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) "sports"
2) "it"

内部编码

集合类型的内部编码有两种:

intset(整数集合)

当集合中的元素都是整数且元素个数小于 set-max-intset-entries 配置(默认 512 个)时,Redis 会选用 intset 来作为集合的内部实现,从而减少内存的使用

hashtable(哈希表)

当集合类型无法满足 intset 的条件时,Redis 会使用 hashtable 作为集合的内部实现

使用场景

集合类型比较典型的使用场景是标签(tag)。
例如一个用户可能对娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。
有了这些数据就可以得到喜欢同一个标签的人,以及用户的共同喜好的标签,这些数据对于用户体验以及增强用户粘度比较重要。
例如一个电子商务的网站会对不同标签的用户做不同类型的推荐,比如对数码产品比较感兴趣的人,在各个页面通过邮件的形式给他们推荐最新的数据产品,通常会为网站带来更多的利益。

开发提示

用户和标签的关系维护应该在一个事务内执行,防止部分命令失败造成的数据不一致

python使用

方法 作用 示例 示例结果