從跳表到Redis有序集合

2021-09-18 04:52:20 字數 2532 閱讀 2154

spark原始碼閱讀系列停更了好久,因為一直沒能達到想要的效果。寫了一篇spark物理計畫生成,讀下來味同嚼蠟,暫時不打算放出來了。最近偶然遇到《如何閱讀乙份源**》,文中說「寫**是表達自己,讀**是在理解別人」,我想既然沒有理解別人,為什麼要寫一篇水文欺騙自己呢?

最近開始看kafka的書,書裡面提到kafka的檔案offset查詢用到了「跳表」這種資料結構。跳表是一種隨機化資料結構,查詢、新增、刪除操作都可以在對數期望時間下完成;當你設計一種儲存結構,嫌陣列o(n)的插入慢,又嫌鍊錶的o(n)查詢慢,可以嘗試下跳表,既可以o(log n)的插入,又可以o(log n)的查詢,唯一的代價是多出小於一倍的鍊錶儲存空間。

首先看乙個redis有序集合(sorted set)的例子, 向有序集合sc中插入三個元素x,y,z,排序評分為6, 10, 15;

localhost:~ renq$ redis-cli

127.0.0.1:6379> zadd sc 6 x 10 y 15 z

(integer) 3

127.0.0.1:6379> zrange sc 0 -1

1) "x"

2) "y"

3) "z"

127.0.0.1:6379> zrange sc 0 -1 withscores

1) "x"

2) "6"

3) "y"

4) "10"

5) "z"

6) "15"

127.0.0.1:6379>

一般地,跳表的結構如下圖;每一層的節點隨機向上形成索引,直到最上層只有乙個索引節點。查詢時從最上層索引開始,索引的存在加速了查詢過程。

redis內部採用了改進的跳表結構儲存上述資訊,簡化成下圖所示;

具體redis的實現,有序集合叫做zset, 由乙個字典dict和乙個跳表zsl組成。

typedef struct zset  zset;
字典用來在o(1)的時間檢查集合中指定元素是否存在,在o(1)時間內根據鍵取出給定的值;跳表用來在o(log n)的時間內查詢指定鍵值對,進行範圍查詢。

redis完整的zset結構如下所示。

做乙個當天nba球員得分表score, 使用zadd插入球員的得分,注意先插入value(得分),後插入key(球員名)。使用zrange獲取得分排行榜;

127.0.0.1:6379> zadd score 54 harden

(integer) 1

127.0.0.1:6379> zadd score 38 curry

(integer) 1

127.0.0.1:6379> zadd score 20 klay

(integer) 1

127.0.0.1:6379> zadd score 0 lowery

(integer) 1

127.0.0.1:6379> zcard score

(integer) 4

127.0.0.1:6379> zrange score 0 -1

1) "lowery"

2) "klay"

3) "curry"

4) "harden"

127.0.0.1:6379> zrange score 0 -1 withscores

1) "lowery"

2) "0"

3) "klay"

4) "20"

5) "curry"

6) "38"

7) "harden"

8) "54"

注意上面查詢得到的是分數從低到高。想要倒序求分數最高的前幾個,只需先-n, 再-1即可。例如查詢得分前3和前5:

127.0.0.1:6379> zrange score -3 -1

1) "klay"

2) "curry"

3) "harden"

127.0.0.1:6379> zrange score -5 -1

1) "lowery"

2) "klay"

3) "curry"

4) "harden"

選擇第2、第3高分:

127.0.0.1:6379> zrange score -3 -2

1) "klay"

2) "curry"

統計得分在某個區間的球員數量:

127.0.0.1:6379> zcount score 0 30

(integer) 2

127.0.0.1:6379> zcount score 0 60

(integer) 4

127.0.0.1:6379> zcount score 0 10

(integer) 1

如何閱讀乙份源**

跳表**

redis設計與實現 有序集

漫畫科普跳表

Redis 有序集合

redis 有序集合和集合一樣也是string型別元素的集合,且不允許重複的成員。不同的是每個元素都會關聯乙個double型別的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。有序集合的成員是唯一的,但分數 score 卻可以重複。集合是通過雜湊表實現的,所以新增,刪除,查詢的複雜度...

Redis有序集合

redis 有序集合和集合一樣也是string型別元素的集合,且不允許重複的成員。不同的是每個元素都會關聯乙個double型別的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。有序集合的成員是唯一的,但分數 score 卻可以重複。集合是通過雜湊表實現的,所以新增,刪除,查詢的複雜度...

redis 有序集合

import redis pool redis.connectionpool host 127.0.0.1 實現乙個連線池 r redis.redis connection pool pool for i in range 100 r.zadd 1 i,i 表名稱為1,新增內容為 1到100,對應分...