更多精彩文章,關注公衆號【ToBeTopJavaer】,更有數萬元精品vip資源免費等你來拿!!!
本文咱們要剖析的基本類型是ZSet,下面咱們將深刻源碼剖析Redis中ZSet的實現。php
一、sorted set,有序的 set,每一個元素有個 score。java
二、score 相同時,按照 key 的 ASCII 碼排序。python
數據結構對比
添加元素redis
zadd myzset 10 java 20 php 30 ruby 40 cpp 50 python
獲取所有元素算法
zrange myzset 0 -1 withscoreszrevrange myzset 0 -1 withscores
根據分值區間獲取元素數組
zrangebyscore myzset 20 30
移除元素,也能夠根據 score rank 刪除ruby
zrem myzset php cpp
統計元素個數數據結構
zcard myzset
分值遞增dom
zincrby myzset 5 python
根據分值統計個數函數
zcount myzset 20 60
獲取元素 rank
zrank myzset java
獲取元素 score
zsocre myzset java
也有倒序的 rev 操做(reverse)
同時知足如下條件時使用 ziplist 編碼:
一、元素數量小於 128 個
二、全部 member 的長度都小於 64 字節
在 ziplist 的內部,按照 score 排序遞增來存儲。插入的時候要移動以後的數據。
對應 redis.conf 參數:
超過閾值以後,使用 skiplist+dict 存儲。
咱們先來看一下有序鏈表:
在這樣一個鏈表中,若是咱們要查找某個數據,那麼須要從頭開始逐個進行比較,直到找到包含數據的那個節點,或者找到第一個比給定數據大的節點爲止(沒找到)。
也就是說,時間複雜度爲 O(n)。一樣,當咱們要插入新數據的時候,也要經歷一樣的查找過程,從而肯定插入位置。
而二分查找法只適用於有序數組,不適用於鏈表。
假如咱們每相鄰兩個節點增長一個指針(或者理解爲有三個元素進入了第二層),讓指針指向下下個節點。
這樣全部新增長的指針連成了一個新的鏈表,但它包含的節點個數只有原來的一半(上圖中是 7, 19, 26)。在插入一個數據的時候,決定要放到那一層,取決於一個算法(在 redis 中 t_zset.c 有一個 zslRandomLevel 這個方法)。
如今當咱們想查找數據的時候,能夠先沿着這個新鏈表進行查找。當碰到比待查數據大的節點時,再回到原來的鏈表中的下一層進行查找。好比,咱們想查找 23,查找的路徑是沿着下圖中標紅的指針所指向的方向進行的:
1. 23 首先和 7 比較,再和 19 比較,比它們都大,繼續向後比較。
2. 但 23 和 26 比較的時候,比 26 要小,所以回到下面的鏈表(原鏈表),與 22比較。
3. 23 比 22 要大,沿下面的指針繼續向後和 26 比較。23 比 26 小,說明待查數據 23 在原鏈表中不存在。
在這個查找過程當中,因爲新增長的指針,咱們再也不須要與鏈表中每一個節點逐個進行比較了。須要比較的節點數大概只有原來的一半。這就是跳躍表。
typedef struct zskiplistNode { sds ele; /* zset 的元素 */ double score; /* 分值 */ struct zskiplistNode *backward; /* 後退指針 */ struct zskiplistLevel { struct zskiplistNode *forward; /* 前進指針, 對應 level 的下一個節點 */ unsigned long span; /* 從當前節點到下一個節點的跨度(跨越的節點數) */ } level[]; /* 層 */ } zskiplistNode; typedef struct zskiplist { struct zskiplistNode *header, *tail; /* 指向跳躍表的頭結點和尾節點 */ unsigned long length; /* 跳躍表的節點數 */ int level; /* 最大的層數 */ } zskiplist; typedef struct zset { dict *dict; zskiplist *zsl; } zset; 複製代碼
隨機獲取層數的函數(源碼):
int zslRandomLevel(void) { int level = 1; while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF)) level += 1; return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL; }複製代碼
id 爲 6001 的新聞點擊數加 **1:zincrby hotNews:20190926 1 n6001
獲取今天點擊最多的 15 條:zrevrange hotNews:20190926 0 15 withscores**
更多精彩文章,關注公衆號【ToBeTopJavaer】,更有數萬元精品vip資源免費等你來拿!!!
``