目录
1.Set类型
1.1 Set集合
1.2 普通命令
1.3 集合操作
1.4 内部编码
1.5 使用场景
2.Zset类型
2.1 Zset有序集合
2.2 普通命令
2.3 集合间操作
2.4 内部编码
2.5 使用场景
1.Set类型
1.1 Set集合
集合类型也是保存多个字符串类型的元素,但是和列表类型不同的是,集合中的元素是无序的,并且不允许重复,Redis除了支持集合内的增删改查操作,同时还支持多个集合取交集、并集、差集
集合类型
1.2 普通命令
SADD
将一个或者多个元素添加到set中,重复的元素无法添加到set中
语法:
SADD key member [member ...]
时间复杂度:O(1)
返回值:添加成功的元素个数
SMEMBERS
获取一个 set 中的所有元素,元素之间的顺序是无序的
语法:
SMEMBERS key
时间复杂度:O(N)
返回值:所有元素的列表
SISMEMBER
判断一个元素在不在 set 中
语法:
SISMEMBER key member
时间复杂度:O(1)
返回值:1表示元素在 set 中,0表示不在 set 中或者 key 不存在
SCARD
获取 set 中元素的个数
语法:
SCARD key
时间复杂度:O(1)
返回值:set 内元素的个数
SPOP
从 set 中删除并返回一个或者多个元素,由于 set 中元素是无序的,所以取出的元素是随机的
语法:
SPOP key [count]
count代表个数,不写表示随机删除一个,写的时候,写几个就删除几个
时间复杂度:O(N),N为count
返回值:取出的元素
SMOVE
将一个元素从源 set 取出并放入目标 set 中
语法:
SMOVE source destination member
时间复杂度:O(1)
返回值:1表示成功,0表示失败
如果继续给key1里面添加一个1,然后再把这个1移动到key2,smove也会按照删除插入执行
SREM
将指定的元素从 set 中删除
语法:
SREM key member [member ...]
时间复杂度:O(N),N为要删除元素的个数
返回值:删除元素的个数
1.3 集合操作
交集(inter)、并集(union)、差集(diff)
SINTER
获取给定 set 的交集中的元素
语法:
SINTER key [key ...]
时间复杂度:O(N * M),N是最小的集合元素个数,M是最大的集合元素个数
返回值:交集的元素
SINTERSTORE
获取给定 set 的交集中的元素并保存到目标 set 中
语法:
SINTERSTORE destination key [key ...]
时间复杂度:O(N * M),N是最小的集合元素个数,M是最大的集合元素个数
返回值:交集的元素个数
SUNION
获取给定 set 的并集中的元素
语法:
SUNION key [key ...]
时间复杂度:O(N),N为给定所有集合的总的元素个数
返回值:并集的元素
SUNIONSTORE
获取给定 set 的并集中的元素并保存到目标 set 中
语法:
SUNIONSTORE destination key [key ...]
时间复杂度:O(N),N为给定所有集合的总的元素个数
返回值:并集的元素个数
SDIFF
获取给定 set 的差集中的元素
语法:
SDIFF key [key ...]
时间复杂度:O(N),N为给定的所有集合的总的元素个数
返回值:差集的元素
SDIFFSTORE
获取给定 set 的差集中的元素并保存到目标 set 中
语法:
SDIFFSTORE destination key [key ...]
时间复杂度:O(N),N为给定的所有集合的总的元素个数
返回值:差集的元素个数
1.4 内部编码
集合类型的内部编码有两种:
1)intset(整数集合):当集合中的元素都是整数并且元素格式小于 set-max-intset-entries 配置(默认512个)时,Redis会选用 intset 来作为集合的内部实现,从而减少内存的使用
2)hashtable(哈希表):当集合类型无法满足 intset 的条件时,Redis会使用hashtable作为集合的内部实现
当元素个数较少并且都为整数时,内部编码为 intset:
当元素不是整数时,内部编码为 hashtable:
1.5 使用场景
1)标签
集合类型比较典型的使用场景是标签,例如A用户对娱乐、体育感兴趣,B用户对游戏、综艺感兴趣,这些兴趣点可以被抽象成标签
给用户添加标签
sadd user:1:tags tag1 tag2 tag5
sadd user:2:tags tag2 tag3 tag5
...
sadd user:k:tags tag1 tag2 tag4
给标签添加用户
sadd tag1:users user:1 user:3
sadd tag2:users user:1 user:2 user:3
...
sadd tagk:users user:1 user:4 user:9 user:28
删除用户下的标签
srem user:1:tags tag1 tag5
...
删除标签下的用户
srem tag1:users user:1
srem tag5:users user:1
...
计算用户的共同兴趣标签
sinter user:1:tags user:2:tags
2)使用 set 计算用户之间的共同好友
对两个用户的好友总数取交集
3)使用 set 统计 UV
PV:表示用户每次访问服务器,都会产生一个PV
UV:表示每个用户访问服务器,都会产生一个UV,但是同一个用户多次访问,不会增加UV
2.Zset类型
2.1 Zset有序集合
有序集合中可以存在重复的元素,与集合不同的是,有序集合中的每个元素都有一个唯一的浮点类型的分数(score)与之关联,使得有序集合中的元素是可以维护有序性的,在进行排序的时候就是根据分数(score)的大小来说进行升序/降序排序
列表、集合、有序集合三者的异同点
2.2 普通命令
ZADD
添加或者更新指定元素以及关联的分数到zset中,分数应该符合double类型
NX:用于添加新元素,不会更新已经存在的元素
XX: 用于更新已经存在的元素,不会添加新元素
CH:默认情况下,ZADD返回的是本次添加元素的个数,指定这个选项之后,就会包含本次更新元素的个数
INCR:将元素的分数加上指定的分数,此时只能指定一个元素和分数
语法:
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member
...]
时间复杂度:O(logN)
返回值:本次添加成功的元素个数
注意:hash、set、list很多时候添加一个元素的时间复杂度都是O(1),由于zset是有序结构,它要为新添加的元素取寻找合适的位置,之所以是logN不是N,是因为zset内部的数据结构是跳表
实际上zset内部就是按照升序的方式来排序的,如果两个元素的分数相同,就按照字符串的字典序来进行排序
如果修改了分数,影响了之前的顺序,就会自动移动元素位置,保持升序的顺序不变,此处只修改没有添加返回值就是0
添加新的元素,此处的返回值就是1
加上ch这个选项,更新元素之后,返回值就是更新元素的个数
给元素加上指定的分数,返回值就是最终的分数,只能指定一个元素和分数
ZCARD
获取一个zset中元素的个数
语法:
ZCARD key
时间复杂度:O(1)
返回值:zset内的元素个数
ZCOUNT
返回分数在 min 和 max 之间的元素个数,默认情况下,min 和 max 都是包含,可以通过 ( 排除
语法:
ZCOUNT key min max
时间复杂度:O(logN)
zcount先根据 min 找到对应的元素, 再根据 max 找到对应的元素,zset 会记录每个元素当前的次序,查询到元素,就知道了元素的次序,然后直接把 max 对应的元素和 min 对应的元素次序做减法
返回值:满足条件的元素列表个数
包含 50 和 77
排除 50 和 77
ZRANGE
返回指定区间的元素,分数按照升序,加上 WITHSCORES 可以把分数也返回
语法:
ZRANGE key start stop [WITHSCORES]
时间复杂度:O(logN + M)
此处要根据次序(下标)找到边界值,时间复杂度就是zcount的时间复杂度O(logN),而 M 是 start 和 stop之间的元素个数
返回值:区间内的元素列表
ZREVRANGE
返回指定区间的元素,分数按照降序
语法:
ZREVRANGE key start stop [WITHSCORES]
时间复杂度:O(logN)
返回值:区间内的元素列表
ZRANGEBYSCORE
返回分数在 min 和 max 之间的元素,默认情况 min 和 max 都是包含的,可以通过 ( 排除
语法:
ZRANGEBYSCORE key min max [WITHSCORES]
时间复杂度:O(logN + M)
返回值:区间内的元素列表
ZPOPMAX
删除并返回分数最高的 count 个元素
语法:
ZPOPMAX key [count]
时间复杂度:O(logN * M)
N 是有序集合的元素个数,M 是要删除元素的个数,count 不写表示删除一个,写几就删除几个
返回值:分数和元素列表
BZPOPMAX
ZPOPMAX 的阻塞版本
语法:
BZPOPMAX key [key ...] timeout
时间复杂度:O(logN)
时间复杂度是 logN,是因为从 key 上面只删除了一次元素
返回值:元素列表
ZPOPMIN
删除并返回分数最低的 count 个元素
语法:
ZPOPMIN key [count]
时间复杂度:O(logN * M)
返回值:分数和元素列表
BZPOPMIN
ZPOPMIN的阻塞版本
语法:
BZPOPMIN key [key ...] timeout
时间复杂度:O(logN)
返回值:元素列表
ZRANK
返回指定元素的排名,升序
语法:
ZRANK key member
时间复杂度:O(logN)
返回值:排名
ZREVRANK
返回指定元素的排名,降序
语法:
ZREVRANK key member
时间复杂度:O(logN)
返回值:排名
ZSCORE
返回指定元素的分数
语法:
ZSCORE key member
时间复杂度:O(1)
返回值:分数
ZREM
删除指定的元素
语法:
ZREM key member [member ...]
时间复杂度:O(logN * M)
N 是整个有序集合中元素个数,M 是 member 的个数
返回值:删除元素的个数
ZREMRANGEBYRANK
按照排序,升序删除指定范围的元素,左闭右闭
语法:
ZREMRANGEBYRANK key start stop
时间复杂度:O(logN + M)
N 是整个有序几个的元素个数,M 是 start - stop 区间中元素的个数,此处只需要进行一次查找
返回值:删除元素的个数
ZREMRANGEBYSCORE
按照分数删除指定范围的元素,左闭右闭
语法:
ZREMRANGEBYSCORE key min max
时间复杂度:O(logN + M)
返回值:删除元素的个数
ZINCRBY
为指定的元素加上指定的分数
语法:
ZINCRBY key increment member
时间复杂度:O(logN)
由于增加后的元素可能会改变原有的位置,此时需要保证有序集合中的元素仍然是升序的,因此时间复杂度为 logN
返回值:增加后元素的分数
2.3 集合间操作
ZINTERSTORE
求出给定有序集合中元素并保存到目标集合中,在合并过程中以元素为单位进行合格,元素对应的分数按照不同的聚合方式和权重重新得到新的分数
语法:
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight
[weight ...]] [AGGREGATE <SUM | MIN | MAX>]
destination:要把结果存储到哪个 key 对应的 zset 中
numkeys:整数,表示有几个 key 参与交集运算 ,前面的命令中不涉及到 numkeys,此处涉及到numkeys是为了明确知道后面的选项从哪开始了(类似面向字节流的粘包问题),如果没有这个整数,就无法知道有几个 key 参与
weight:权重
sum: 求和 min:取最小 max:取最大
时间复杂度:O(N * K) + O(logN * M)
N是输入的有序集合中最小的有序集合的元素个数,K表示几个有序集合,M是最终结果的有序集合的元素个数
返回值:目标集合中的元素个数
对 key1 * 2,key2 * 3之后,再将他们相加,得到最终结果
对 key1 和 key2 求交集,取最小值
对 key1 和 key2 求交集,取最大值
在有序集合中,member 才是元素的本体,而 score 只是辅助的,因此,在进行求交集时,只要 member相同就行
ZUNIONSTORE
求出给定有序集合中元素的并集并保存到目标有序集合中,在合并的过程中以元素为单位进行合并,元素对应的分数按照不同的聚合方式和权重得到新的分数
语法:
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight
[weight ...]] [AGGREGATE <SUM | MIN | MAX>]
时间复杂度:O(N) + O(logN * M)
N是输入的有序集合总的元素个数,M是最终结果的有序集合的元素个数
返回值:目标集合中的元素个数
2.4 内部编码
1)当元素个数较少且每个元素较小时,内部编码为 ziplist:
2)当元素个数超过128个,内部编码为 skiplist:
127.0.0.1:6379> ZADD key2 10 kkkkkk......
2.5 使用场景
1)添加用户赞数
例如 A 用户发布了一篇文章,获得了 3 个赞,此时就可以使用有序集合中的 ZADD 和 ZINCRBY
zadd user:ranking 3 A
后续再获得赞数,可以使用 ZINCRBY 了
zincrby user:ranking 1 A
2)取消用户赞数
如果用户注销,此时就可以把用户从榜单上删除,可以使用 ZREM
zrem user:ranking A
3) 展示用户信息以及用户分数
例如将用户的信息(姓名、年龄)保存再哈希类型中,先获取用户的 name ,再根据 name 去查用户的分数和排名
存储用户的信息
HSET user:info name A age 19
获取用户的信息
HGETALL user:info
此时就获取到了用户的 name 和 age,再根据 name 去查询用户的分数和排名
ZSCORE user:ranking A
ZRANK user:ranking A