有序集合類型
上節我們一起學習了集合類型,感受到了redis的強大。現在我們接着學Redis的最后一個類型——有序集合類型。
有序集合類型,大家從名字上應該就可以知道,實際上就是在集合類型上加了個有序而已。Redis中的有序集合類型,實際上是在集合類型上,為每個元素都關聯一個分數,有序實際上說的是分數有序,我們根據分數的范圍獲取集合及其他操作。集合的元素依然是不能夠相同的,但是分數可以相同。
下面列舉有序集合和類型和列表類型的相似處:
①兩者都是有序的(廢話!)
②兩者都可以獲得某一范圍的元素
下面列舉區別:
①列表是鏈表實現的,靠近兩邊的數據讀取極快,而元素過多后獲取中間元素的速度則會很慢;有序集合類型使用的散列表和跳躍表(Skip list)實現的,所以讀取哪部分的數據都差不多(時間復雜度是O(logN))。
②列表中不能簡單的調整元素的位置,但是有序集合可以(通過改變分數)。
③有序集合比列表費內存(要存儲分數、散列、跳躍表)。
下面我們來一起學習命令(這里參數關鍵字都比較多,所以下面開始列舉的命令,關鍵字都使用大寫)。
1、增加元素
ZADD key score member [score member ...]
ZADD命令是向集合中增加元素的命令,往集合中增加分數為score的member,這里也是可以一次增加多個值,返回值是成功增加的元素的個數,如果member存在,則score會覆蓋原有的分數。
127.0.0.1:6379> zadd scoreboard 89 tom (integer) 1 //添加一個 127.0.0.1:6379> zadd scoreboard 70 peter 100 david (integer) 2 //添加多個 127.0.0.1:6379> zrange scoreboard 0 -1 withscores 1) "peter" //帶分數輸出 2) "70" 3) "tom" 4) "89" 5) "david" 6) "100"
我們發現Peter的分數錄入錯了,需要修改為76分,這時候我們接着執行下面的命令。
127.0.0.1:6379> zadd scoreboard 76 peter (integer) 0 //member存在時,score不一致,會修改score 127.0.0.1:6379> zrange scoreboard 0 -1 withscores 1) "peter" 2) "76" //70->76 3) "tom" 4) "89" 5) "david" 6) "100"
這里分數不僅僅支持整數,還支持浮點數。
127.0.0.1:6379> zadd testscore 17e+307 A (integer) 1 127.0.0.1:6379> zadd testscore 3.3 B (integer) 1 127.0.0.1:6379> zadd testscore -inf D (integer) 1 127.0.0.1:6379> zadd testscore +inf C (integer) 1 127.0.0.1:6379> zrange testscore 0 -1 withscores 1) "D" 2) "-inf" 3) "B" 4) "3.2999999999999998" 5) "A" 6) "1.6999999999999999e+308" 7) "C" 8) "inf"
其中+inf和-inf是正負無窮的意思。
2、獲得元素的分數
127.0.0.1:6379> zscore scoreboard peter "76"
3、獲得排名在某個范圍的元素列表
ZRANGE命令會按照元素分數的從小到大順序返回索引從start到stop之間所有的元素(包含兩端)。ZRANGE與LRANGE命令相似,索引從0開始,負數一樣代表從后向前查找(-1是最后一個)。WITHSCORE代表是否加上分數。
127.0.0.1:6379> zrange scoreboard 0 2 1) "peter" 2) "tom" 3) "david" 127.0.0.1:6379> zrange scoreboard 0 -1 withscores 1) "peter" 2) "76" 3) "tom" 4) "89" 5) "david" 6) "100" 127.0.0.1:6379> zrevrange scoreboard 0 -1 withscores 1) "david" 2) "100" 3) "tom" 4) "89" 5) "peter" 6) "76"
ZRANGE命令的時間復雜度為O(longN+m),其中n為有序集合的基數,m為返回的元素個數。如果遇到分數相同的情況,Redis會按照字典順序(即”0″<…<”9″<”A”<…<”Z”<”a”<…<”z”這樣的順序)進行排列。如果是中文,也會按照編碼之后的字典順序排序。
ZREVRANGE命令和ZRANGE命令唯一不同的是ZREVRANGE命令是按照分數從大到小給出順序結果。
4、獲得指定分數范圍的元素
這個命令參數很多,但是都很好理解。這個命令用來獲取指定分數范圍的元素,min是最小值,max是最大值,WITHSCORE還是和上面介紹的一樣,LIMIT是為了指定偏移量及數量的,和sql的有點像。offset是偏移量,count是數量。同時這些min和max都是包含的,如果要想不包含,需要使用“(”符號。
127.0.0.1:6379> zrangebyscore scoreboard 80 100 withscores 1) "tom" 2) "89" 3) "david" 4) "100" 127.0.0.1:6379> zrangebyscore scoreboard (80 100 withscores 1) "tom" 2) "89" 3) "david" 4) "100" 127.0.0.1:6379> zrangebyscore scoreboard 80 (100 withscores 1) "tom" 2) "89" 127.0.0.1:6379> zrangebyscore scoreboard 80 100 withscores limit 1 1 1) "david" 2) "100" 127.0.0.1:6379> zrangebyscore scoreboard 80 100 withscores limit 1 2 1) "david" 2) "100" 127.0.0.1:6379> zrangebyscore scoreboard 60 +inf withscores 1) "peter" 2) "76" 3) "tom" 4) "89" 5) "david" 6) "100"
5、增加某個元素的分數
127.0.0.1:6379> ZINCRBY scoreboard 2 peter "78"
127.0.0.1:6379> ZINCRBY scoreboard -5 peter "73"
這個命令可以增加一個元素的分數,返回值是更改后的分數。這里就不再贅述用法了,和INCRBY命令類似。同樣如果不存在會初始為0在增加,負數即是減小。
6、獲得集合中元素的數量
這個命令和SCARD類似,也就不多說了。
7、獲得指定分數范圍的元素個數
這里就是獲得min和max分數之間的元素數,當然這里也支持“(”符號。
8、刪除一個或多個元素
返回值是成功刪除的元素的個數。
127.0.0.1:6379> zrem scoreboard peter (integer) 1 127.0.0.1:6379> zrange scoreboard 0 -1 1) "tom" 2) "david"
9、按照排名范圍刪除元素
這個命令按照元素分數從小到大順序刪除指定范圍內所有的元素(其實就是先排序,然后按照排好的序列的索引刪除),並返回刪除的元素的數量。
10、按照分數范圍刪除元素
這里就是直接刪除分數范圍的元素了,這里分數同樣支持“(”符號,返回刪除數量。
11、獲得元素的排名
ZRANK命令按照元素分數的從小到大的順序獲得制定元素的排名(第一個從0開始),ZREVRANK則相反。
127.0.0.1:6379> zrank scoreboard tom (integer) 0 127.0.0.1:6379> zrank scoreboard david (integer) 1
最后我們舉個實際應用的例子。
我們把wordpress的文章按點擊率排序,關系數據庫我們是遍歷所有的文章排序點擊數,如果使用Redis,我們需要一個posts:page.view鍵的有序集合類型,然后每個member為文章ID,score為文章的點擊量。這樣我們就可以用ZREVRANGE命令獲取點擊量排行榜。
還有一個實際的例子,我們用有序集合類型保存文章的發布時間(時間用UNIX時間及時間的毫秒數)與文章ID,這樣我們可以很方便的按時間來查看文章列表,我們的文章列表應該是用文章發布時間排序而不應該用文章ID排序的。