Redis数据类型之zset
上篇文章:
Redis数据类型之sethttps://blog.csdn.net/sniper_fandc/article/details/149139848?fromshare=blogdetail&sharetype=blogdetail&sharerId=149139848&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link
目录
1 zadd和zrange
2 zcard和zcount
3 zrevrange和zrangebyscore
4 zpopmax和bzpopmax
5 zpopmin和bzpopmin
6 zrank和zrevrank
7 zscore
8 zrem、zremrangebyrank和zremrangebyscore
9 zincrby
10 zinterstore
11 zunionstore
12 zset的使用场景
zset是有序集合,集合中元素不能重复,但是引入分数(score,float类型),每一个元素member对应一个score,集合中元素按score升序排序(自动进行)。如果多个member的score相同,则相同score的member按字典顺序排序。
注意:score支持-inf(负无穷大)和inf(无穷大)两种值。
1 zadd和zrange
命令:zadd key [NX | XX] [GT | LT] [CH] [INCR] score1 member1 score2 member2 ...
向key的有序集合中添加(score,member)对(pair)。时间复杂度O(logN)(因为元素有序,所以通常有序序列在对应位置插入的时间复杂度为O(logN),比如二分查找(注意这里只是举例,zset底层没有用二分,而是跳表)),N表示有序集合中元素的个数。返回值添加成功元素的个数。
默认key不存在则创建key并添加,key存在则直接添加。而如果member已经存在,就更新score。常用的选项如下:
[NX | XX]:这对选项在key存在时对于member是否存在有不同的做法。NX表示member不存在才添加,存在member则不修改。XX表示存在member就修改score,不存在member则不添加。
[GT | LT]:这对选项只有在必须更新score时才生效,如果member不存在则要添加member。GT表示更新后的score必须大于更新前的score才会更新;LT表示更新后的score必须小于更新前的score才会更新。
[CH]:对返回值的描述。添加该选项,zadd的默认返回值就会变为修改成功元素的数量+添加成功元素的数量。
[INCR]:zadd+incr==zincrby命令,可以针对score进行加减运算。注意,该选项只能针对一对pair,因此如果使用该选项,zadd命令就只能写一对(score,member)。比如zadd key incr 10 member,对member的分数+10。
命令:zrange key start end [withscores]
查询key的有序集合下标范围[start,end]的元素(因为有序,所以可以用下标表示范围)。withscores选项表示同时查询member和score。这里的顺序即是有序集合的排序顺序—升序。时间复杂度O(logN + M),N表示有序集合元素的个数,M表示区间内元素的个数。
2 zcard和zcount
命令:zcard key
查询key的有序集合中元素的个数。时间复杂度O(1)。返回值为元素的个数。
命令:zcount key min max
查询key的有序集合中满足score在[min,max]范围内元素的个数,如果要写开区间,需要在min或max前加上(表示开区间。时间复杂度O(logN),N表示有序集合中元素的个数。返回值为满足范围的元素的个数。
注意:zcount的时间复杂度为什么不是O(logN + M)?表示先查找max和min,需要O(logN),在遍历[min,max]内的元素得到个数,需要O(M)表示区间内元素的个数。实际上zset内部对于每个元素还会记录排名/次序,查找到max和min后直接把各自次序做减法就可以得到区间内元素的个数,因此时间复杂度是O(logN)而不是O(logN + M)。
3 zrevrange和zrangebyscore
注意:这一组命令在低于redis 6.2的版本都可以使用,redis 6.2版本后弃用这组命令,这组命令被合并到zrange中使用参数表示:zrevrange使用rev参数代替、zrangebyscore使用byscore参数代替。
命令:zrevrange key start end [withscores]
按降序方式查询[start,end]下标范围内的元素。时间复杂度O(logN+M)。
命令:zrangebyscore key min max [withscores]
查询score在范围[min,max]下标范围内的元素(可以使用开区间(的表示形式)。时间复杂度O(logN+M)。
4 zpopmax和bzpopmax
命令:zpopmax key [count]
删除score最大的count个元素,不带count参数默认删除一个。时间复杂度O(logN*M),N表示有序集合元素的个数,M表示要删除的元素个数。返回值是被删除的元素和score。
注意:实际该命令的作用就是尾删,那可以通过保留一个尾部标记,尾删的复杂度就可以从O(logN)变为O(1)。Redis源码中也确实有尾部标记,但是该命令的实现没有用到尾部标记,而是直接调用通用的删除命令,即时间复杂度O(logN),删除M个就是O(logN*M)。
命令:bzpopmax key1 key2 ... timeout
阻塞版本的zpopmax(可以把有序集合看做优先级队列),同时监听多个key,只要有一个key不空就删除最大的元素同时返回对应的key、member和score。timeout是超时时间,单位为秒,double类型。时间复杂度O(logN),N表示有序集合元素的个数,即使有多个key,但是也只删一个就返回,因此不用乘M。
5 zpopmin和bzpopmin
这对命令和zpopmax和bzpopmax对应,因此用法也一样,只不过是删除score最小的元素。这里不在演示。
命令:zpopmin key [count]
命令:bzpopmin key1 key2 ... timeout
6 zrank和zrevrank
命令:zrank key member
查询member的排名,实际上就是下标。时间复杂度O(logN),N表示有序集合中元素的个数。返回值就是对应的下标。
命令:zrevrank key member
查询member的排名,下标是从右往左查(比如最大score在zset的尾部,对应的排名就是0,次大的排名就是1等等)。时间复杂度O(logN),N表示有序集合中元素的个数。返回值就是对应的下标。
7 zscore
命令:zscore key member
查询member的score。时间复杂度O(1),该命令底层进行了优化,用空间换时间,因此时间复杂度不再是O(logN),而是O(1)。返回值就是对应的score。
8 zrem、zremrangebyrank和zremrangebyscore
命令:zrem key member1 member2 ...
删除多个member。时间复杂度O(logN*M),N是有序集合元素的个数,M是要删除元素的个数。返回值是成功删除的个数。
命令:zremrangebyrank key start end
根据rank排名/下标范围[start,end]删除多个member。时间复杂度O(logN+M),N是有序集合元素的个数,M是要删除元素的个数,注意这里因为只需要查找start对应的元素,其后的元素连续删除即可(无需再查找),因此时间复杂度不是O(logN*M)。返回值是成功删除的个数。
命令:zremrangebyscore key min max
根据score范围[min,max]删除多个member。时间复杂度O(logN+M),N是有序集合元素的个数,M是要删除元素的个数,注意这里因为只需要查找start对应的元素,其后的元素连续删除即可(每次删除只需判断分数是否超过max,无需再查找),因此时间复杂度也不是O(logN*M)。返回值是成功删除的个数。
9 zincrby
命令:zincrby key number member
对member的score增加number。时间复杂度O(logN)。返回值增加后的score。该命令较简单,作用同zadd的incr参数,故不再演示。
10 zinterstore
命令:zinterstore destination numkeys key1 key2 ... [weights weight1 weight2 ...] [aggregate <sum | min | max>]
把输入的key求交集并存储在destination键中。numkeys表示本次交集运算有多少个key参与(因为key后面还可能跟参数选项,因此需要用该参数来识别输入的key的结束位置,类似http协议的content-length的作用—防止因为TCP协议的面向字节流导致的粘包问题)。weights表示为不同的key赋予不同的权重,计算交集后的score前首先需要各key中交集元素*权重。aggregate表示最终交集元素的score合并方式:sum求和、min取最小、max取最大。
时间复杂度O(K*logN)+O(M*logM),其中K表示输入的有序集合的个数,N表示输入的有序集合中最小集合的元素的个数,M是交集中元素的个数。
返回值:交集中元素的个数。
11 zunionstore
命令:zunionstore destination numkeys key1 key2 ... [weights weight1 weight2 ...] [aggregate <sum | min | max>]
把输入的key求并集并存储在destination键中。参数含义类似zinterstore,不再介绍。
时间复杂度O(logN)+O(M*logM),其中K表示输入的有序集合的个数,N表示输入的有序集合中最小集合的元素的个数,M是并集中元素的个数。
返回值:并集中元素的个数。
注意:redis 5中没有类似set中的zinter、zunion和zdiff等命令,该系列命令在redis 6.2以后才引入。
12 zset的使用场景
zset最常用于排行榜系统,排行榜系统要求分数可能实时变化,并且对于角色的排名以升序或降序排名,还支持随时查找角色在排行榜中的位置和按范围查找排行榜排名信息。zset天然支持,对于排名分数就是score,角色就是member,同时支持按范围查找zrange、按分数查找zrange、查找角色排名zrank等等,基于内存+查询元素时间复杂度O(logN),查找速度很快,适应实时性的要求。
并且由于集合的特性还支持排行榜的合并,因为有些排行榜会进行综合指数排序,这就设计到集合的并集或交集+weight。因此zset就很适合排行榜系统。
下篇文章: