Redis —— 基本数据类型 Set Zset (三)

4. Set

一个集合中最多放 2^31-1 个元素,元素之间无序且不允许重复。

除针对集合内部元素的 增删查改等命令,redis中还有集合间的并,交,差运算。

4.1 集合元素内操作

4.1.1 SADD

bash 复制代码
SADD key member [member ...]

将 一/多元素放入 set 中,重复的无法放入。

返:成功添加的元素个数

时间复杂度:O(1)

bash 复制代码
127.0.0.1:6379> SADD myset 1 2 3 4 5 6 7 8 9
9
127.0.0.1:6379> SMEMBERS myset
1
2
3
4
5
6
7
8
9

4.1.2 SMEMBERS

bash 复制代码
SMEMBERS key

获取 set 中全部元素,元素间是无序的

返:所有元素列表

时间复杂度:O(1)

bash 复制代码
127.0.0.1:6379> SADD myset 1 2 3 4 5 6 7 8 9
9
127.0.0.1:6379> SMEMBERS myset
1
2
3
4
5
6
7
8
9

4.1.3 SISMEMBER

bash 复制代码
SISMEMBER key member

判断某一元素是否在 set 中

返:1:在;0:不在或key不存在

时间复杂度:O(1)

bash 复制代码
127.0.0.1:6379> SMEMBERS myset
1
4
 !!!
hello
6
9
8
2
5
7
3
world
127.0.0.1:6379> SISMEMBER myset "hello"
1
127.0.0.1:6379> SISMEMBER myset "helo"
0

4.1.4 SCARD

bash 复制代码
SCARD key

获取 set 的基数(cardinality),即 set 中的元素个数

返:set 中的元素个数

时间复杂度:O(1)

bash 复制代码
127.0.0.1:6379> SMEMBERS myset
1
4
 !!!
hello
6
9
8
2
5
7
3
world
127.0.0.1:6379> SCARD myset
12

4.1.5 SPOP

bash 复制代码
SPOP key [count]

从 set 中删除 一/多 个元素,由于 set 中的元素是无序的,取的元素是随机 的。

返:取出的元素

时间复杂度:O(n), n 是 元素个数

bash 复制代码
127.0.0.1:6379> SPOP myset
5
127.0.0.1:6379> spop myset 3
7
3
world

4.1.6 SMOVE

bash 复制代码
SMOVE source destination membe

将指定的某一元素从 setA 取出放入 setB 中

返: 1:成功;0:失败

时间复杂度:O(1)

bash 复制代码
127.0.0.1:6379> smove myset myset1 "hello"
1
127.0.0.1:6379> SMEMBERS myset1
hello

4.1.7 SREM

bash 复制代码
SREM key member [member ...]

将指定元素从 set 中删除

返:删除的元素个数

时间复杂度:O(n), n 是 元素个数

bash 复制代码
127.0.0.1:6379> SREM myset 1 2 3
2
127.0.0.1:6379> SMEMBERS myset
4
 !!!
6
9
8

4.2 集合间元素操作

4.2.1 SINTER

bash 复制代码
SINTER key [key ...]

获取给定 set 的交集元素

返:交集元素

时间复杂度:O(n*m), n :最小集合元素个数, M 最大集合元素个数

bash 复制代码
127.0.0.1:6379> SMEMBERS myset
4
 !!!
6
9
8

127.0.0.1:6379> SMEMBERS myset2
9
 !!!
4
hello
6
8
127.0.0.1:6379> SINTER myset myset2
4
 !!!
6
9
8

4.1.2 SINTERSTORE

bash 复制代码
SINTERSTORE destination key [key ...]

将交集元素存入指定 set 中

返:交集元素个数

时间复杂度:O(n*m), n :最小集合元素个数, M 最大集合元素个数

bash 复制代码
127.0.0.1:6379> SINTERSTORE myset3 myset myset2
5
127.0.0.1:6379> SMEMBERS myset3
6
4
9
 !!!
8

4.1.3 SUNION

bash 复制代码
SUNION key [key ...]

取集合的并集元素

返:并集元素

时间复杂度:O(n),n:所有集合元素个数之和

bash 复制代码
127.0.0.1:6379> SMEMBERS myset
4
 !!!
6
9
8
127.0.0.1:6379> SMEMBERS myset1
hello
127.0.0.1:6379> sunion myset myset1
9
 !!!
4
hello
6
8

4.2.4 SUNIONSTORE

bash 复制代码
SUNIONSTORE destination key [key ...]

将并集元素存入指定 set 中

返:并集元素个数加粗样式

时间复杂度:O(n),n:所有集合元素个数之和

bash 复制代码
127.0.0.1:6379> SUNIONSTORE myset2 myset myset1
6
127.0.0.1:6379> SMEMBERS myset2
9
 !!!
4
hello
6
8

4.2.5 SDIFF

bash 复制代码
SDIFF key [key ...]

获取给定 set 的差集

返:差集元素

时间复杂度:O(n),n:所有集合元素个数之和

bash 复制代码
127.0.0.1:6379> SMEMBERS myset
4
 !!!
6
9
8
127.0.0.1:6379> SMEMBERS myset2
9
 !!!
4
hello
6
8
127.0.0.1:6379> SDIFF myset2 myset
hello

4.2.6 SDIFFSTORE

bash 复制代码
SDIFFSTORE destination key [key...]

将差集存入指定 set 中

返:差集元素个数

时间复杂度:O(n),n:所有集合元素个数之和

bash 复制代码
127.0.0.1:6379> SMEMBERS myset
4
 !!!
6
9
8
127.0.0.1:6379> SMEMBERS myset2
9
 !!!
4
hello
6
8
127.0.0.1:6379> SDIFFSTORE myset4 myset2 myset
1
127.0.0.1:6379> SMEMBERS myset4
hello

4.3 内部编码

  • intset (整数集合):集合中都是整数,且元素个数小于 set-max-intset-entrier 配置(默认 512 个)时,作 set 的内部实现,减小内存使用
  • hashtable(哈希表):不满足 intset 条件时,用 hashtable 作 set 内部实现。

4.4 使用场景

  • 给用户添加标签,eg:喜欢音乐,喜欢体育......
    伪代码:
  1. 给用户加标签:
bash 复制代码
sadd user:1:tags tag1 tag2 tag5
sadd user:2:tags tag2 tag3 tag5
...
  1. 给标签添加用户
bash 复制代码
sadd tag1:users user:1 user:3
sadd tag2:users user:1 user:2 user:3
...
  1. 删除用户标签
bash 复制代码
srem user:1:tags tag1 tag5
...
  1. 删除标签下的用户
bash 复制代码
srem tag1:users user:1
srem tag5:users user:1
...
  1. 计算用户的共同标签
bash 复制代码
sinter user:1:tags user:2:tags

5. Zset

有序集合,就是给集合中的每个元素装备了一个对应的浮点型的分数(score),有序就是依据这种分数的。

有序集中元素不能重复,但是元素的分数可以重复。

5.1 集合内元素操作

5.1.1 ZADD

bash 复制代码
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member
...]
  • XX:仅用于更新存在的元素,不会添新元素
  • NX:仅用于添新元素,不会更新已有元素
  • CH:ZADD 默认返回添加的元素个数,加上该选项后,还会包含更新的元素个数
  • INCR:与 ZINCRBY 效果类似,将元素分数加上指定分数。此时只能指定一个元素和分数

添加或更新 指定元素及其关联分数到 zset 中,分数应为 double型, +inf/-inf 作为正负极限也是合法

时间复杂度:O(log(N))

返:添加成功的元素个数(不算更新的)

bash 复制代码
127.0.0.1:6379> ZADD zset 111 "1" 222 "2" 333 "3"
3

5.1.2 ZCARD

bash 复制代码
ZCARD key

获取一个 zset 的基数,即 zset 中的元素个数

返:zset 内元素个数

时间复杂度:O(1)

bash 复制代码
127.0.0.1:6379> ZCARD zset
3

5.1.3 ZCOUNT

bash 复制代码
ZCOUNT key min max

返回分数在 min 和 max 间的元素个数,默认包含 min 和 max,可以通过 排除。

返:满足条件的元素列表个数

时间复杂度:O(log(N))

bash 复制代码
127.0.0.1:6379> ZCOUNT zset 100 360
3

5.1.4 ZRANGE

bash 复制代码
ZRANGE key start stop [WITHSCORES]

返回指定区间的元素,分数按照升序,加上 WITHSCORE 可以带分数返回

返:区间内的元素列表

时间复杂度:O(log(N)+M)

bash 复制代码
127.0.0.1:6379> ZRANGE zset 0 -1
1
2
3
127.0.0.1:6379> ZRANGE zset 0 -1 withscores
1
111
2
222
3
333

5.1.5 ZREVRANGE

bash 复制代码
REVRANGE key start stop [WITHSCORES]

ZRANGE ,但分数按照降序,也可加WITHSCORES

返:区域内元素列表

时间复杂度:O(log(N)+M)

bash 复制代码
127.0.0.1:6379> ZREVRANGE zset 0 -1 
3
2
1
127.0.0.1:6379> ZREVRANGE zset 0 -1 withscores
3
333
2
222
1
111

5.1.6 ZRANGEBYSCORE

bash 复制代码
ZRANGEBYSCORE key min max [WITHSCORES]

返回分数在 min 和 max 间的元素,默认包含 min 和 max,可以通过 排除。

返:区域内元素列表

时间复杂度:O(log(N)+M)

bash 复制代码
127.0.0.1:6379> ZRANGEBYSCORE zset (111 333 
2
3
127.0.0.1:6379> ZRANGEBYSCORE zset (111 333 withscores
2
222
3
333

5.1.7 ZPOPMAX

bash 复制代码
ZPOPMAX key [count]

删除并返回分数最高的 count 个元素。

返:分数和元素列表

时间复杂度:O(log(N) * M)

bash 复制代码
127.0.0.1:6379> ZPOPMAX zset 
3
333

5.1.8 BZPOPMAX

bash 复制代码
BZPOPMAX key [key ...] timeout

ZPOPMAX 阻塞版

返:元素列表

时间复杂度:O(log(N))

bash 复制代码
127.0.0.1:6379> BZPOPMAX zset 10
zset
2
222

5.1.9 ZPOPMIN

bash 复制代码
ZPOPMIN key [count]

删除并返回分数最低的 count 个元素。

返:分数和元素列表

时间复杂度:O(log(N) * M)

和 ZPOPMAX 类似不再展示

5.1.10 BZPOPMIN

bash 复制代码
BZPOPMIN key [key ...] timeout

ZPOPMIN 阻塞版

返:元素列表

时间复杂度:O(log(N))

和 BZPOPMAX 类似不再展示

5.1.11 ZRANK / ZREVRANK

bash 复制代码
ZRANK key member

返回指定元素的排名,按升/降序

返:排名

时间复杂度:O(log(N))

bash 复制代码
127.0.0.1:6379> ZRANGE zset 0 -1 
1
3
4
5
6
127.0.0.1:6379> ZRANK zset 3
1

5.1.12 ZSCORE

bash 复制代码
 ZSCORE key member

返:指定元素的分数

时间复杂度:O(1)

bash 复制代码
127.0.0.1:6379> ZADD zset 333 "3" 444 "4" 555 "5" 666 "6"
4
127.0.0.1:6379> ZSCORE zset 6
666

5.1.13 ZREM

bash 复制代码
ZREM key member [member ...]

删除指定 一/多 个元素

返:删除的元素个数

时间复杂度:O(M*log(N))

bash 复制代码
127.0.0.1:6379> ZRANGE zset 0 -1 
1
3
4
5
6
127.0.0.1:6379> ZREM zset 4
1
127.0.0.1:6379> ZRANGE zset 0 -1 
1
3
5
6

5.1.14 ZREMRANGEBYRANK

bash 复制代码
ZREMRANGEBYRANK key start stop

按升序删除指定范围元素,左闭右闭

返:删除的元素个数

时间复杂度:O(log(N)+M)

bash 复制代码
127.0.0.1:6379> ZRANGE zset 0 -1 
1
3
5
6
127.0.0.1:6379> ZREMRANGEBYRANK zset 2 3
2
127.0.0.1:6379> ZRANGE zset 0 -1 
1
3

5.1.15 ZREMRANGEBYSCORE

bash 复制代码
ZREMRANGEBYSCORE key min max

按分数删除指定范围元素,左闭右闭

返:删除的元素个数

时间复杂度:O(log(N)+M)

bash 复制代码
127.0.0.1:6379> ZADD zset 222 "2" 444 "4" 555 "5" 666 "6"
4
127.0.0.1:6379> ZRANGE zset 0 -1 
1
2
3
4
5
6
127.0.0.1:6379> ZREMRANGEBYSCORE zset 400 666
3
127.0.0.1:6379> ZRANGE zset 0 -1 
1
2
3

5.1.16 ZINCRBY

bash 复制代码
ZINCRBY key increment member

给指定元素的分数加指定分数

返:加后元素的分数

时间复杂度:O(log(N))

bash 复制代码
127.0.0.1:6379> ZINCRBY zset 1 1
112

5. 2 集合间元素操作

5.2.1 ZINTERSTORE

bash 复制代码
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight
[weight ...]] [AGGREGATE <SUM | MIN | MAX>]

取出有序集中元素的交集并存入目标有序集中,合并时以元素为单位进行,元素分数按聚合方式和权重获取新值。

返:目标集中元素个数

时间复杂度:O(NK)+O(Mlog(M))

N :有序集合中最小的有序集合的元素个数;

K :几个有序集合;

M :结果有序集合的元素个数。

bash 复制代码
127.0.0.1:6379> ZRANGE zset1 0 -1
1
7
8
9
127.0.0.1:6379> ZRANGE zset 0 -1
1
2
3
127.0.0.1:6379> ZINTERSTORE zset2 2 zset zset1
1
127.0.0.1:6379> ZRANGE zset2 0 -1 
1

5.2.2 ZUNIONSTORE

bash 复制代码
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight
[weight ...]] [AGGREGATE <SUM | MIN | MAX>]

取出有序集中元素的并集并存入指定有序集中,合并时以元素为单位进行,元素分数按聚合方式和权重获取新值。

返:目标集中元素个数

时间复杂度:O(N)+O(M*log(M))

N :集合总元素个数;

M :结果集合的元素个数。

bash 复制代码
127.0.0.1:6379> ZRANGE zset1 0 -1
1
7
8
9
127.0.0.1:6379> ZRANGE zset 0 -1
1
2
3
127.0.0.1:6379> ZUNIONSTORE zset3 2 zset zset1
6
127.0.0.1:6379> ZRANGE zset3 0 -1 
1
2
3
7
8
9

5.3 内部编码

  • ziplist (压缩链表):集合元素个数小于 zset-max-ziplist-entries 配置(默认 128 个),且元素值均小于 zset-max-ziplist-value 配置(默认 64 字节)时,作 zset 的内部实现,ziplist 可以减小内存消耗
  • skiplist(跳表):不满足 ziplist 的条件,则用其作 zset 的内部实现,因为此时 ziplist 的操作效率会下降。

5.4 使用场景

典型场景------排行榜系统

伪代码:

  1. 添加赞数
bash 复制代码
zadd user:ranking:2022-03-15 3 james

之后再有点赞,则用 zincrby

  1. 取消用户赞数
bash 复制代码
zrem user:ranking:2022-03-15 tom
  1. 展示获赞数前十用户
bash 复制代码
zrevrangebyrank user:ranking:2022-03-15 0 9
  1. 展示用户信息以及分数
bash 复制代码
hgetall user:info:tom
zscore user:ranking:2022-03-15 mike
zrank user:ranking:2022-03-15 mike
相关推荐
kkoral2 小时前
单机docker部署的redis sentinel,使用python调用redis,报错
redis·python·docker·sentinel
java1234_小锋4 小时前
Redis6为什么引入了多线程?
java·redis
DemonAvenger5 小时前
Redis与MySQL双剑合璧:缓存更新策略与数据一致性保障
数据库·redis·性能优化
想用offer打牌5 小时前
面试官问Redis主从延迟导致脏数据读怎么解决?
redis·后端·面试
墨白曦煜7 小时前
深入剖析 Redis 客户端:Sentinel 模式下的“寻址”与“感知”艺术
数据库·redis·sentinel
遇见火星7 小时前
Redis高可用-哨兵模式(Sentinel)
redis·sentinel
鸽鸽程序猿8 小时前
【Redis】Java客户端使用Redis
java·redis·github
北城以北88888 小时前
SpringBoot--Redis基础知识
java·spring boot·redis·后端·intellij-idea
橘子138 小时前
Linux线程——一些概念(七)
java·redis·缓存