集合的内部编码
集合类型的内部编码有两种:
- intset(整数集合):当集合中的元素都是整数且元素个数小于set-max-intset-entries配置(默认512个)时,Redis会选用intset来作为集合内部实现,从而减少内存的使用。
- hashtable(哈希表):当集合类型无法满足intset的条件时,Redis会使用hashtable作为集合的内部实现。
下面用示例来说明:
当元素个数较少且都为整数时,内部编码为intset:
127.0.0.1:6379> sadd setkey 2 3 4 5
(integer) 4
127.0.0.1:6379> object encoding setkey
"intset"
当元素个数超过512个,内部编码变为hashtable:
127.0.0.1:6379>sadd setkey2 1 2 3 4 5 6 7... 511 512 513
OK
127.0.0.1:6379> object encoding setkey2
"hashtable"
当某个元素不为整数时,内部编码也会变为hashtable:
127.0.0.1:6379> sadd setkey3 a b c
(integer) 3
127.0.0.1:6379> object encoding setkey2
"hashtable"
集合结构
结构依然还是key-value的结构,key还是字符串类型,value是一个集合,可以将若干字符串进行一个组合。
- 可以使用sadd向集合增加数据。
- 集合中不能存在重复数据,向集合中插入重复数据将会失败。
- 可是使用srem key music,删除集合中的数据。
- redis中还支持集合间的API操作,sinter实现集合间相同的元素(交集),sdiff实现集合间不同的元素(差集),sunion实现集合间所有的元素(并集)。
特点
- 无序
- 无重复
- 支持集合间操作
集合类型的相关命令
sadd、srem
- sadd key element:向聚合key添加element(如果element已经存在,添加失败),时间复杂度O(N),N 是被添加的元素的数量。
# 添加单个元素
redis> sadd bbs "discuz.net"
(integer) 1
# 添加重复元素
redis> sadd bbs "discuz.net"
(integer) 0
# 添加多个元素
redis> sadd bbs "tianya.cn" "groups.google.com"
(integer) 2
redis> smembers bbs
1) "discuz.net"
2) "groups.google.com"
3) "tianya.cn"
- srem key element:将集合key中的element移除掉,时间复杂度O(N),N 为给定 member 元素的数量。
# 测试数据
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)
scard、sismember、srandmember、smembers、spop
- scard key:返回集合 key 的基数(集合中元素的数量),时间复杂度O(1)。
redis> sadd tool pc printer phone
(integer) 3
redis> scard tool # 非空集合
(integer) 3
redis> del tool
(integer) 1
redis> scard tool # 空集合
(integer) 0
- sismember key member:判断 member 元素是否集合 key 的成员,时间复杂度O(1)。
redis> smembers joe's_movies
1) "hi, lady"
2) "Fast Five"
3) "2012"
# member 元素不是集合的成员,或 key 不存在,返回 0。
redis> sismember joe's_movies "bet man"
(integer) 0
# member 元素是集合的成员,返回 1。
redis> sismember joe's_movies "Fast Five"
(integer) 1
- srandmember key [count]:只提供了 key 参数,那么返回集合中的一个随机元素。时间复杂度只提供 key 参数时为 O(1) 。如果提供了 count 参数,那么为 O(N) , N 为返回数组的元素个数。
# 添加元素
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)
- 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"
- spop key:移除并返回集合中的一个随机元素。如果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用 srandmembers 命令。时间复杂度O(1)。
redis> smembers db
1) "MySQL"
2) "MongoDB"
3) "Redis"
redis> spop db
"Redis"
#当 key 不存在或 key 是空集时,返回 nil 。
redis> spop not_exists_key
(nil)
redis> smembers db
1) "MySQL"
2) "MongoDB"
redis> spop db
"MySQL"
redis> smembers db
1) "MongoDB"
srandmember和spop的区别
- spop从集合弹出,每次只能弹出一个。
- srandmember不会破坏集合。
实战
- 给用户添加标签、给标签添加用户
集合间APi
- sinter user:1:follow user:2:follow = it sports:交集
- sdiff user:1:follow user:2:follow = music his:差集
- sunion user:1:follow user:2:follow = it music sports new ent:并集
- sdiff | sinter | sunion + destkey …:将差集、交集、并集结果保存在destkey中。
TIPS
- sadd = tagging(标签相关场景)。
- spop / srandmember = random item(数据数的相关场景)。
- sadd + sinter = social graph(社交相关场景)。