Redis 数据类型之集合(Set)类型

 2016年08月20日    133     声明


  1. 集合(Set)类型
  2. 集合类型中的命令及使用

1. 集合(Set)类型

Redis中的集合(Set)类型类似于List类型,Set类型可以认为是没有排序的字符串集合。和List类型一样,我们可以对集合类型进行元素的添加、删除或判断元素是否存在等操作。

Set类型操作的时间复杂度为O(1),其最大元素数量为232-1(40亿)。和List类型不同的是,Set集合中不允许出现重复的元素,如果多次添加相同元素,Set中将仅保留该元素的一份拷贝。

List类型相比,Set类型还有一个非常重要的特性,可以在服务器端完成多个集合之间的聚合计算操作,如:SUNIONSUNIONSTORESDIFFSTORE。由于这些操作均在服务端完成,因此效率极高,而且也节省了大量的网络I/O开销。


2. 集合类型中的命令及使用

2.1 元素添加、成员判断

操作集合最基本的操作是向集合中添加元素,添加元素使用SADD命令。还可以使用SMEMBERSSISMEMBER查询集合中的成员。

2.1.1 SADD - 添加元素

SADD key member [member ...]

将一个或多个元素member添加到集合key中,如果要添加的元素在集合中已存在,那么该元素将被忽略。如果集合key不存在,那么包含元素member的集合会被创建。

复杂度、返回值:

  • 时间复杂度:O(N)N为被添加的元素数量
  • 返回值:被添加到集合中的新元素的数量,不包括被忽略的元素;如果key不是集合类型,将返回一个错误。

使用示例

# 添加单个元素
redis> SADD blog "segmentfault.com"
(integer) 1

# 添加重复元素
redis> SADD blog "segmentfault.com"
(integer) 0

# 添加多个元素
redis> SADD blog "csdn.net" "itbilu.com"
(integer) 2

redis> SMEMBERS blog
1) "segmentfault.com"
2) "csdn.net"
3) "itbilu.com"


2.1.2 SCARD - 集合元素数

SCARD key

返回集合key中元素的数量。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:集合中的元素数;集合不存在时,返回0

使用示例

redis> SADD tool pc printer phone
(integer) 3

redis> SCARD tool   # 非空集合
(integer) 3

redis> DEL tool
(integer) 1

redis> SCARD tool   # 空集合
(integer) 0


2.1.3 SMEMBERS - 返回集合中成员

SMEMBERS key

返回集合key中所有的成员。如果key不存在,会被当做空集合。

复杂度、返回值:

  • 时间复杂度:O(N)N为集合的基数
  • 返回值:集合中所有的成员

使用示例

# key 不存在或集合为空
redis> EXISTS not_exists_key
(integer) 0
redis> SMEMBERS not_exists_key
(empty list or set)

# 非空集合
redis> SADD language Ruby Python Clojure
(integer) 3

redis> SMEMBERS language
1) "Python"
2) "Ruby"
3) "Clojure"


2.1.4 SISMEMBER - 判断元素是否是集合成员

SISMEMBER key member

判断元素member是否是集合key的成员。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:如果member是集合成员,返回1;如果不是集合成员或集合不存在,返回0

使用示例

redis> SMEMBERS joe's_movies
1) "hi, lady"
2) "Fast Five"
3) "2012"

redis> SISMEMBER joe's_movies "bet man"
(integer) 0

redis> SISMEMBER joe's_movies "Fast Five"
(integer) 1


2.2 获取集合元素、元素移除

集合类型中并不能明确返回指定的成员,但可以通过SPOPSRANDMEMBER随机返回一个或多个元素成员。SREM命令可以移除集合中指定的元素,SMOVE可以将元素从一个元素移至另一个元素。

2.2.1 SPOP - 随机返回并移除一个元素

SPOP key

随机移除并返回集合key中的一个元素。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:被移除的元素;如果key不存在或集合为空,则返回nil

使用示例

redis> SMEMBERS db
1) "MySQL"
2) "MongoDB"
3) "Redis"

redis> SPOP db
"Redis"

redis> SMEMBERS db
1) "MySQL"
2) "MongoDB"

redis> SPOP db
"MySQL"

redis> SMEMBERS db
1) "MongoDB"


2.2.2 SRANDMEMBER - 随机返回一个或多个元素

SRANDMEMBER key [count]

如果可选参数count未提供,则随机集合key中的一个元素。count元素提供时,则按以下规则返回:

  • count小于集合元素总数,则随机返回数量为count的元素。如果大于总数,则返回全部元素。
  • 如果count为负数,则返回一个数量为其绝对值的的元素。

复杂度、返回值:

  • 时间复杂度:未提供countO(1);提供是为O(N)N为返回数组的元素个数
  • 返回值:一个元素或数量为count的数组;集合为空则返回nil或空数组。

使用示例

# 添加元素
redis> SADD fruit apple banana cherry
(integer) 3

# 只给定 key 参数,返回一个随机元素
redis> SRANDMEMBER fruit
"cherry"
redis> SRANDMEMBER fruit
"apple"

# 给定 3 为 count 参数,返回 3 个随机元素
# 每个随机元素都不相同
redis> SRANDMEMBER fruit 3
1) "apple"
2) "banana"
3) "cherry"

# 给定 -3 为 count 参数,返回 3 个随机元素
# 元素可能会重复出现多次
redis> SRANDMEMBER fruit -3
1) "banana"
2) "cherry"
3) "apple"

redis> SRANDMEMBER fruit -3
1) "apple"
2) "apple"
3) "cherry"

# 如果 count 是整数,且大于等于集合基数,那么返回整个集合
redis> SRANDMEMBER fruit 10
1) "apple"
2) "banana"
3) "cherry"

# 如果 count 是负数,且 count 的绝对值大于集合的基数
# 那么返回的数组的长度为 count 的绝对值
redis> SRANDMEMBER fruit -10
1) "banana"
2) "apple"
3) "banana"
4) "cherry"
5) "apple"
6) "apple"
7) "cherry"
8) "apple"
9) "apple"
10) "banana"

# SRANDMEMBER 并不会修改集合内容
redis> SMEMBERS fruit
1) "apple"
2) "cherry"
3) "banana"

# 集合为空时返回 nil 或者空数组
redis> SRANDMEMBER not-exists
(nil)
redis> SRANDMEMBER not-eixsts 10
(empty list or set)


2.2.3 SREM - 移除指定的元素

SREM key member [member ...]

移除集合key中指定的一个或多个元素member,如果member不存在会被忽略。

复杂度、返回值:

  • 时间复杂度:O(N)N为指定的member数量
  • 返回值:被移除的元素数量;如果key不是集合类型,会返回一个错误。

使用示例

# 测试数据
redis> SMEMBERS languages
1) "c"
2) "lisp"
3) "python"
4) "ruby"

# 移除单个元素
redis> SREM languages ruby
(integer) 1

# 移除不存在元素
redis> SREM languages non-exists-language
(integer) 0

# 移除多个元素
redis> SREM languages lisp python c
(integer) 3
redis> SMEMBERS languages
(empty list or set)


2.2.4 SMOVE - 将元素从集合移至另一个集合

SMOVE source destination member

将元素member从集合source移动至集合destination

如果元素在集合source中不存在,则不进行任何操作;如果destination中已存在该元素,则仅从source中删除该元素。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:元素移动成功返回1;其它情况返回0

使用示例

redis> SMEMBERS songs
1) "Billie Jean"
2) "Believe Me"

redis> SMEMBERS my_songs
(empty list or set)

redis> SMOVE songs my_songs "Believe Me"
(integer) 1

redis> SMEMBERS songs
1) "Billie Jean"

redis> SMEMBERS my_songs
1) "Believe Me"


2.3 集合间的操作

集合类型中还提供了集合间操作的命令,这些命令在服务器端操作,执行效率非常高。集间的操作有:差集、交集、并集,命令有返回指定的集合元素,或将操作结果存储至一个新集合。

2.3.1 SDIFF - 返回一或多个集合的差集

SDIFF key [key ...]

返回指定的一个或多个集合的差集。

复杂度、返回值:

  • 时间复杂度:O(N)N为指定集合的成员数量之和。
  • 返回值:差集成员列表。

使用示例

redis> SMEMBERS peter's_movies
1) "bet man"
2) "start war"
3) "2012"

redis> SMEMBERS joe's_movies
1) "hi, lady"
2) "Fast Five"
3) "2012"

redis> SDIFF peter's_movies joe's_movies
1) "bet man"
2) "start war"


2.3.2 SDIFFSTORE - 将一或多个集合的差集保存至另一集合

SDIFFSTORE destination key [key ...]

该命令与SDIFF类型,但它不会直接返回,而是将差集存储到另一集合destination中。如果destination已存在,则将其覆盖。

复杂度、返回值:

  • 时间复杂度:O(N)N为指定集合的成员数量之和。
  • 返回值:结果交集成员数量。

使用示例

redis> SMEMBERS joe's_movies
1) "hi, lady"
2) "Fast Five"
3) "2012"

redis> SMEMBERS peter's_movies
1) "bet man"
2) "start war"
3) "2012"

redis> SDIFFSTORE joe_diff_peter joe's_movies peter's_movies
(integer) 2

redis> SMEMBERS joe_diff_peter
1) "hi, lady"


2.3.3 SINTER - 将一或多个集合的交集保存至另一集合

SINTER key [key ...]

返回一个或多个指定集合的交集。如果指定的key不存在,会被视为空集合,返回的结果集也为空。

复杂度、返回值:

  • 时间复杂度:O(N*M)N为指定集合中基数最小的集合,M为指定集合的数量。
  • 返回值:交集成员列表。

使用示例

redis> SMEMBERS group_1
1) "LI LEI"
2) "TOM"
3) "JACK"

redis> SMEMBERS group_2
1) "HAN MEIMEI"
2) "JACK"

redis> SINTER group_1 group_2
1) "JACK"


2.3.4 SINTERSTORE - 将一或多个集合的交集存储到新集合

SINTERSTORE destination key [key ...]

该命令类似于SINTER,但它不会返回成员列表,而是将结果集存储至一个新的集合destination中。

复杂度、返回值:

  • 时间复杂度:O(N*M)N为指定集合中基数最小的集合,M为指定集合的数量。
  • 返回值:结果集中的成员数量。

使用示例

redis> SMEMBERS songs
1) "good bye joe"
2) "hello,peter"

redis> SMEMBERS my_songs
1) "good bye joe"
2) "falling"

redis> SINTERSTORE song_interset songs my_songs
(integer) 1

redis> SMEMBERS song_interset
1) "good bye joe"


2.3.5 SUNION - 返回集合的并集

SUNION key [key ...]

返回一个或多个集合的并集;如果key不存在,会被视为空集合。

复杂度、返回值:

  • 时间复杂度:O(N)N为所有集合成员之和
  • 返回值:并集成员列表。

使用示例

redis> SMEMBERS songs
1) "Billie Jean"

redis> SMEMBERS my_songs
1) "Believe Me"

redis> SUNION songs my_songs
1) "Billie Jean"
2) "Believe Me"


2.3.6 SUNIONSTORE - 将集合的并集插入新集合

SUNIONSTORE destination key [key ...]

此命令类似于SUNION,但它不会直接返回集合的交集,而是将结果插入一个新的集合destination。如果destination已存在,则将其覆盖。

复杂度、返回值:

  • 时间复杂度:O(N)N为所有集合成员之和
  • 返回值:并集元素数量。

使用示例

redis> SMEMBERS NoSQL
1) "MongoDB"
2) "Redis"

redis> SMEMBERS SQL
1) "sqlite"
2) "MySQL"

redis> SUNIONSTORE db NoSQL SQL
(integer) 4

redis> SMEMBERS db
1) "MySQL"
2) "sqlite"
3) "MongoDB"
4) "Redis"