Redis中的zset類(lèi)型詳解
什么是zset
有序集合zset保留了set集合不能有重復(fù)成員的特點(diǎn),但與set集合不同的是,zset的每個(gè)member都有一個(gè)唯一的浮點(diǎn)數(shù)類(lèi)型的分?jǐn)?shù)score與之關(guān)聯(lián)。依據(jù)每個(gè)member的score進(jìn)行排序。結(jié)構(gòu)如下圖所示:
有序集合中的元素是不能重復(fù)的,但分?jǐn)?shù)允許重復(fù)
常用命令
zadd
添加或更新指定元素以及關(guān)聯(lián)的分?jǐn)?shù)到zset中,分?jǐn)?shù)是double類(lèi)型語(yǔ)法: zadd key [nx|xx] [gt|lt] [ch] [incr] score member [score member...]
- nx:僅用于添加新元素,不能更新已經(jīng)存在的元素
- xx:僅用于更新已經(jīng)存在的元素,不能添加新元素
- gt:greater than 只能更新已經(jīng)存在并且分?jǐn)?shù)比現(xiàn)在的分?jǐn)?shù)高的元素,能正常添加元素
- lt:less than 只能更新已經(jīng)存在并且分?jǐn)?shù)比現(xiàn)在分?jǐn)?shù)低的元素,能正常添加元素
- ch:默認(rèn)情況,zadd返回的是本次添加元素的個(gè)數(shù),但指定這個(gè)選項(xiàng)后,還會(huì)包含本次更新的元素的個(gè)數(shù)
- incr:將元素的分?jǐn)?shù)加上指定的分?jǐn)?shù),并且只能指定一個(gè)元素和分?jǐn)?shù)
我使用的版本是redis5,在redis5中不支持 gt/lt操作
時(shí)間復(fù)雜度:O(logN)
由于zset是有序結(jié)構(gòu),要求新增的元素,要放到合適的位置上即找位置的過(guò)程,zset內(nèi)部使用跳表的數(shù)據(jù)結(jié)構(gòu),可以達(dá)到O(logN)
:::dangerzset中的member和score不是鍵值對(duì)的關(guān)系,而是“pair”的關(guān)系,可以通過(guò)member找到score,也可以通過(guò)score找到member:::
zrange
查看zset中元素詳情語(yǔ)法: zrange key start stop
時(shí)間復(fù)雜度:O(logN+M)
首先根據(jù)下標(biāo)找到邊界值,找元素O(logN),從start位置開(kāi)始遍歷到stop位置,O(m)
redis內(nèi)部存儲(chǔ)數(shù)據(jù)是按照二進(jìn)制存儲(chǔ),所以redis服務(wù)器不負(fù)責(zé)“字符編碼”,因此需要redis客服端支持
添加 withscores
能查看每個(gè)元素對(duì)應(yīng)分?jǐn)?shù)
zset內(nèi)部默認(rèn)是按照升序的方式來(lái)排列的
zrevrange
返回指定區(qū)間元素,分?jǐn)?shù)按降序排列,帶上 withscores
可以將分?jǐn)?shù)加上語(yǔ)法: zrevrange key start stop [withscores]
時(shí)間復(fù)雜度:O(logN+M)
zcard
查看一共有幾個(gè)元素語(yǔ)法: zcard key
時(shí)間復(fù)雜度:O(1)
zcount
根據(jù)給定分?jǐn)?shù)區(qū)間查找有幾個(gè)元素語(yǔ)法: zcount key min max
閉區(qū)間時(shí)間復(fù)雜度:O(logN)
先根據(jù)min找到對(duì)應(yīng)元素,再根據(jù)max找到對(duì)應(yīng)元素,而查找元素的時(shí)間復(fù)雜度是O(logN),由于zset內(nèi)部記錄每個(gè)元素的“次序”,可以直接把max對(duì)應(yīng)元素的次序減去min對(duì)應(yīng)元素的次序即可,不需要進(jìn)行遍歷。
使用 (
表示開(kāi)區(qū)間
min和max可以寫(xiě)成浮點(diǎn)數(shù),浮點(diǎn)數(shù)中inf表示無(wú)窮大,-inf表示負(fù)無(wú)窮大
zrangebyscore
返回分?jǐn)?shù)在min和max之間的元素語(yǔ)法: zrangebyscore key min max [withscores]
時(shí)間復(fù)雜度:O(logN+M)
在redis6以后該命令被廢棄,將功能合并到zrange中
zpopmax
刪除并返回分?jǐn)?shù)最高的count個(gè)元素,類(lèi)似topk問(wèn)題語(yǔ)法: zpopmax key [count]
時(shí)間復(fù)雜度:O(logN*M)
刪除M個(gè)元素,查找一個(gè)元素時(shí)間復(fù)雜度為O(logN)
返回值:返回分?jǐn)?shù)和元素列表
bzpopmax
zpopmax的阻塞版本語(yǔ)法: bzpopmax key [key...] timeout
時(shí)間復(fù)雜度:O(logN)返回值:返回元素列表
zpopmin
刪除并返回分?jǐn)?shù)最低的count個(gè)元素語(yǔ)法: zpopmin key [count]
時(shí)間復(fù)雜度:O(logN*M)返回值:返回分?jǐn)?shù)和元素列表
bzpopmin
zpopmin的阻塞版本語(yǔ)法: bzpopmin key [key...] timeout
時(shí)間復(fù)雜度:O(logN)返回值:返回元素列表
zrank
返回指定元素的次序,按升序排語(yǔ)法: zrank key member
時(shí)間復(fù)雜度:O(logN)返回值:返回對(duì)應(yīng)次序/下標(biāo)
zrevrank
zrank的降序版本語(yǔ)法: zrevrank key member
時(shí)間復(fù)雜度:O(logN)返回值:返回對(duì)應(yīng)元素次序/下標(biāo)
zscore
返回指定元素的分?jǐn)?shù)語(yǔ)法: zscore key member
時(shí)間復(fù)雜度:O(1)
在前面的命令中根據(jù)member找元素的時(shí)間復(fù)雜度都是O(logN),但是這里redis犧牲空間,換取時(shí)間做了特定的優(yōu)化
zrem
刪除指定元素語(yǔ)法: zrem key member [member...]
返回值:分?jǐn)?shù)
zremrangebyrank
根據(jù)下標(biāo)表示的范圍進(jìn)行刪除,閉區(qū)間語(yǔ)法: zremrangebyrank key start stop
時(shí)間復(fù)雜度:O(logN+M)
查找位置只需一次即可,然后刪除M個(gè)元素
返回值:返回刪除的個(gè)數(shù)
zremrangebyscore
刪除對(duì)應(yīng)的分?jǐn)?shù)范圍內(nèi)的元素語(yǔ)法: zremrangebyscore key min max
時(shí)間復(fù)雜度:O(logN+M)返回值:返回刪除個(gè)數(shù)
zincrby
修改元素的分?jǐn)?shù),并保持整個(gè)有序集合仍然是升序的語(yǔ)法: zincrby key increment member
時(shí)間復(fù)雜度:O(logN)返回值:增加后元素的分?jǐn)?shù)
zinterstore
將給定有序集合中元素的交集并保持到目標(biāo)有序集合中語(yǔ)法: zinterstore destination numkeys key [key...] [weights weight [weight ...]] [aggregate <sum|min|max>]
- destination:把結(jié)果存儲(chǔ)到這個(gè)key
- numkeys:整數(shù),描述后續(xù)有幾個(gè)key參與交集運(yùn)行
- weights: 權(quán)重,有序集合帶有分?jǐn)?shù),此處指定的權(quán)重,相當(dāng)于一個(gè)系數(shù),會(huì)乘于當(dāng)前的分?jǐn)?shù)
- aggregate:求并集時(shí)相同的元素的分?jǐn)?shù)是相加/取最小/取最大,默認(rèn)是相加
時(shí)間復(fù)雜度:O(NK)+O(Mlog(M)) -> O(M*logM)
N:輸入若干個(gè)有序集合中,元素最少的個(gè)數(shù)
K:有幾個(gè)有序集合
M:最終有序集合的元素個(gè)數(shù)
k一般不會(huì)太大,可以看作1,N和M接近,同一個(gè)數(shù)量級(jí)。
所以O(shè)(NK)+O(Mlog(M))->O(M)+O(Mlog(M))-> O(MlogM)
c:300.5+102=35
a:100.5+202=45
zunionstore
將給定有序集合中元素的并集并保存進(jìn)目標(biāo)有序集合中語(yǔ)法: zunionstore destination numkeys key [key...] [weights weight [weight...]][aggregate <sum|min|max>]
用法和 zinterstore
一致
內(nèi)部編碼
如果有序集合中的元素個(gè)數(shù)較少,或者各個(gè)元素體積較小使用 ziplist
來(lái)存儲(chǔ),如果當(dāng)前元素個(gè)數(shù)比較多,或者各個(gè)元素體積非常大使用 skiplist
存儲(chǔ)
應(yīng)用場(chǎng)景
最關(guān)鍵的應(yīng)用場(chǎng)景就是排行榜系統(tǒng),例如微博熱搜,游戲天梯排行,成績(jī)排行
1.游戲天梯排汗
使用zset將玩家信息和對(duì)應(yīng)分?jǐn)?shù)存入即可,就會(huì)自動(dòng)生成一個(gè)排行榜,可以使用
zrevrange
取出前幾名玩家。當(dāng)分?jǐn)?shù)發(fā)生改變,可以使用zincrby
修改分?jǐn)?shù),排行順序能自動(dòng)調(diào)整。
2.微博熱搜
微博熱搜需要考慮到瀏覽量,點(diǎn)贊量,轉(zhuǎn)發(fā)量,評(píng)論量等,需要使用權(quán)重
weights
,此時(shí)可以使用zinterstore/zunionstore
按照加權(quán)的方式處理??梢詫⒚總€(gè)維度的數(shù)值放到有序集合中,member
就是微博id,score
就是各個(gè)維度的數(shù)值。通過(guò)zinterstore/zunionstore
把上述有序集合按照約定的權(quán)重,進(jìn)行集合間運(yùn)算即可。
到此這篇關(guān)于Redis的zset類(lèi)型的文章就介紹到這了,更多相關(guān)Redis zset類(lèi)型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 基于Redis?zSet實(shí)現(xiàn)滑動(dòng)窗口對(duì)短信進(jìn)行防刷限流的問(wèn)題
- Redis基本數(shù)據(jù)類(lèi)型Zset有序集合常用操作
- Redis中ZSet的具體使用
- Redis使用ZSET實(shí)現(xiàn)消息隊(duì)列使用小結(jié)
- redis使用zset實(shí)現(xiàn)延時(shí)隊(duì)列的示例代碼
- Redis使用ZSET實(shí)現(xiàn)消息隊(duì)列的項(xiàng)目實(shí)踐
- redis中跳表zset的具體使用
- redis延時(shí)隊(duì)列zset實(shí)現(xiàn)的示例
- Redis中Zset類(lèi)型常用命令的實(shí)現(xiàn)
相關(guān)文章
詳解Redis在SpringBoot工程中的綜合應(yīng)用
這篇文章主要介紹了Redis在SpringBoot工程中的綜合應(yīng)用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-10-10Redis fork進(jìn)程分配不到內(nèi)存解決方案
這篇文章主要介紹了Redis fork進(jìn)程分配不到內(nèi)存解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11Redis超詳細(xì)講解高可用主從復(fù)制基礎(chǔ)與哨兵模式方案
Redis因?yàn)槠涓咝阅芎鸵子眯栽谖覀兒蠖说姆?wù)中發(fā)揮了巨大的作用,并且很多重要功能的實(shí)現(xiàn)都會(huì)依賴(lài)redis,本篇我們來(lái)了解Redis高可用主從復(fù)制與哨兵模式2022-04-04關(guān)于Redis?bigkeys命令會(huì)阻塞問(wèn)題的解決
這篇文章主要介紹了關(guān)于Redis?bigkeys命令會(huì)阻塞問(wèn)題的解決,今天分享一次Redis引發(fā)的線上事故,避免再次踩雷,實(shí)現(xiàn)快速入門(mén),需要的朋友可以參考下2023-03-03SpringBoot整合Redis實(shí)現(xiàn)序列化存儲(chǔ)Java對(duì)象的操作方法
這篇文章主要介紹了SpringBoot整合Redis實(shí)現(xiàn)序列化存儲(chǔ)Java對(duì)象,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03Redis隊(duì)列和阻塞隊(duì)列的實(shí)現(xiàn)
本文主要介紹了Redis隊(duì)列和阻塞隊(duì)列的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11