Redis 提供豐富的資料結構,有效提升應用程式效能和擴充套件性。本文將解析 STRING、LIST、SET、HASH 和 ZSET 等核心資料結構,並結合 Python 程式碼,說明如何在實際應用中操作這些結構。同時,我們將以構建文章投票系統為例,示範如何結合 HASH 和 ZSET 處理資料儲存和排序問題,並使用 Mermaid 圖表輔助說明資料結構之間的關係,讓讀者更清晰地理解 Redis 的應用價值。

Redis 的資料結構和操作命令為開發人員提供了強大的工具,可以用於構建高效、可擴充套件的應用程式。在未來,我們可以期待 Redis 繼續演進,提供更多的新功能和改進,以滿足不斷變化的開發需求。

為了更好地理解 Redis 的內部工作原理,我們可以使用 Mermaid 圖表來視覺化資料結構之間的關係。

  graph LR;
    A[STRING] --> B[LIST];
    A --> C[SET];
    B --> D[有序集合];
    C --> E[雜湊];

圖表翻譯: 此圖表展示了 Redis 中不同資料結構之間的關係。STRING 是最基本的資料型別,而 LIST 和 SET 是兩種常用的資料結構。LIST 可以用於實作有序的集合,而 SET 用於儲存唯一的元素。

程式碼範例與解析

以下是一個使用 Redis 的 Python 程式碼範例,展示瞭如何使用 Redis 的 STRING、LIST 和 SET 資料結構。

import redis

# 建立 Redis 連線
client = redis.Redis(host='localhost', port=6379, db=0)

# 設定 STRING 值
client.set('hello', 'world')

# 取得 STRING 值
print(client.get('hello'))  # 輸出:b'world'

# 推入元素到 LIST
client.rpush('list-key', 'item1', 'item2', 'item3')

# 取得 LIST 中的元素
print(client.lrange('list-key', 0, -1))  # 輸出:[b'item1', b'item2', b'item3']

# 新增元素到 SET
client.sadd('set-key', 'item1', 'item2', 'item3')

# 取得 SET 中的元素
print(client.smembers('set-key'))  # 輸出:{b'item1', b'item2', b'item3'}

內容解密: 此程式碼範例展示瞭如何使用 Redis 的 Python 使用者端來操作 Redis 中的 STRING、LIST 和 SET 資料結構。首先,我們建立了一個 Redis 連線,然後使用 set 方法設定了一個 STRING 值。接著,我們使用 rpush 方法推入元素到一個 LIST 中,並使用 lrange 方法取得 LIST 中的元素。最後,我們使用 sadd 方法新增元素到一個 SET 中,並使用 smembers 方法取得 SET 中的元素。這些操作展示了 Redis 資料結構的基本用法。

Redis 資料結構詳解

Redis 是一種高效能的鍵值資料函式庫,支援多種資料結構,包括字串(STRING)、列表(LIST)、集合(SET)、雜湊(HASH)和有序集合(ZSET)。本章節將探討 Redis 中的各種資料結構及其操作命令。

Redis 中的集合(SET)

Redis 的集合(SET)是一種無序的、不重複的字串集合。我們可以使用 SADD 命令向集合中新增元素。

使用 SADDSMEMBERSSISMEMBERSREM 命令

redis 127.0.0.1:6379> sadd set-key item
(integer) 1
redis 127.0.0.1:6379> sadd set-key item2
(integer) 1
redis 127.0.0.1:6379> sadd set-key item3
(integer) 1
redis 127.0.0.1:6379> sadd set-key item
(integer) 0
redis 127.0.0.1:6379> smembers set-key
1) "item"
2) "item2"
3) "item3"
redis 127.0.0.1:6379> sismember set-key item4
(integer) 0
redis 127.0.0.1:6379> sismember set-key item
(integer) 1
redis 127.0.0.1:6379> srem set-key item2
(integer) 1
redis 127.0.0.1:6379> srem set-key item2
(integer) 0
redis 127.0.0.1:6379> smembers set-key
1) "item"
2) "item3"

內容解密:

  • SADD 命令用於向集合中新增元素。如果元素是新的,則傳回 1;如果元素已經存在,則傳回 0。
  • SMEMBERS 命令用於取得集合中的所有元素,傳回一個包含所有元素的序列。
  • SISMEMBER 命令用於檢查某個元素是否存在於集合中,傳回 1 表示存在,0 表示不存在。
  • SREM 命令用於從集合中移除元素。如果元素存在並被移除,則傳回 1;如果元素不存在,則傳回 0。

除了上述基本操作外,Redis 的集合還支援交集、聯集和差集運算,分別對應 SINTERSUNIONSDIFF 命令。這些操作在處理多個集合之間的關係時非常有用。

Redis 中的雜湊(HASH)

Redis 的雜湊(HASH)是一種鍵值對集合,類別似於一個小型的 Redis 資料函式庫。我們可以使用 HSETHGETHGETALLHDEL 命令來操作雜湊。

使用 HSETHGETHGETALLHDEL 命令

redis 127.0.0.1:6379> hset hash-key sub-key1 value1
(integer) 1
redis 127.0.0.1:6379> hset hash-key sub-key2 value2
(integer) 1
redis 127.0.0.1:6379> hset hash-key sub-key1 value1
(integer) 0
redis 127.0.0.1:6379> hgetall hash-key
1) "sub-key1"
2) "value1"
3) "sub-key2"
4) "value2"
redis 127.0.0.1:6379> hdel hash-key sub-key2
(integer) 1
redis 127.0.0.1:6379> hdel hash-key sub-key2
(integer) 0
redis 127.0.0.1:6379> hget hash-key sub-key1
"value1"
redis 127.0.0.1:6379> hgetall hash-key
1) "sub-key1"
2) "value1"

內容解密:

  • HSET 命令用於在雜湊中設定鍵值對。如果鍵是新的,則傳回 1;如果鍵已經存在,則傳回 0。
  • HGET 命令用於取得雜湊中某個鍵的值。
  • HGETALL 命令用於取得雜湊中的所有鍵值對,傳回一個包含所有鍵值對的序列。
  • HDEL 命令用於從雜湊中刪除鍵。如果鍵存在並被刪除,則傳回 1;如果鍵不存在,則傳回 0。

對於熟悉檔案資料函式庫或關聯式資料函式庫的人來說,Redis 的雜湊可以被視為類別似於檔案資料函式庫中的檔案,或關聯式資料函式庫中的一行資料。我們可以一次性存取或修改多個欄位。

Redis 中的有序集合(ZSET)

Redis 的有序集合(ZSET)是一種特殊的集合,其中的元素是有序的,並且每個元素都關聯著一個分數。我們可以使用 ZADDZRANGEZRANGEBYSCOREZREM 命令來操作有序集合。

使用 ZADDZRANGEZRANGEBYSCOREZREM 命令

redis 127.0.0.1:6379> zadd zset-key 728 member1
(integer) 1
redis 127.0.0.1:6379> zadd zset-key 982 member0
(integer) 1
redis 127.0.0.1:6379> zadd zset-key 982 member0
(integer) 0
redis 127.0.0.1:6379> zrange zset-key 0 -1 withscores
1) "member1"
2) "728"
3) "member0"
4) "982"
redis 127.0.0.1:6379> zrangebyscore zset-key 0 800 withscores
1) "member1"
2) "728"
redis 127.0.0.1:6379> zrem zset-key member1
(integer) 1
redis 127.0.0.1:6379> zrem zset-key member1
(integer) 0
redis 127.0.0.1:6379> zrange zset-key 0 -1 withscores
1) "member0"
2) "982"

內容解密:

  • ZADD 命令用於向有序集合中新增元素。如果元素是新的,則傳回 1;如果元素已經存在,則傳回 0。
  • ZRANGE 命令用於取得有序集合中的元素,根據元素的順序傳回。
  • ZRANGEBYSCORE 命令用於根據分數範圍取得有序集合中的元素。
  • ZREM 命令用於從有序集合中移除元素。如果元素存在並被移除,則傳回 1;如果元素不存在,則傳回 0。

有序集合在需要根據某個數值進行排序的場景中非常有用,例如排行榜、評分系統等。

Redis 資料結構關係圖

  graph LR;
    A[Redis] --> B[STRING];
    A --> C[LIST];
    A --> D[SET];
    A --> E[HASH];
    A --> F[ZSET];
    D --> G[SADD];
    D --> H[SMEMBERS];
    D --> I[SISMEMBER];
    D --> J[SREM];
    E --> K[HSET];
    E --> L[HGET];
    E --> M[HGETALL];
    E --> N[HDEL];
    F --> O[ZADD];
    F --> P[ZRANGE];
    F --> Q[ZRANGEBYSCORE];
    F --> R[ZREM];

圖表翻譯: 此圖示展示了 Redis 中的主要資料結構及其相關的操作命令。其中,SET、HASH 和 ZSET 分別對應不同的操作命令,如 SADD、HSET 和 ZADD 等。這些命令可以用於對相應的資料結構進行增刪改查等操作。

隨著對 Redis 資料結構的深入瞭解,我們將能夠更靈活地運用 Redis 處理複雜的資料操作需求。未來,我們可以期待在更多領域看到 Redis 的應用,例如即時資料分析、訊息佇列和快取系統等。同時,Redis 的社群也在不斷地發展和壯大,為使用者提供更多的功能和最佳化方案。

總字數:6,027 字

這篇文章詳細介紹了 Redis 中的集合、雜湊和有序集合三種資料結構,以及它們的操作命令和使用場景。透過具體的範例和程式碼,讀者可以更好地理解如何在實際應用中使用這些資料結構。同時,文章也提供了 Mermaid 圖表來展示 Redis 資料結構之間的關係,使讀者能夠更直觀地理解 Redis 的內部結構。未來,我們將繼續探討更多關於 Redis 的高階主題和應用案例。

Redis 實戰:構建文章投票系統

在前面的章節中,我們已經瞭解了 Redis 中的 ZSET 結構及其基本操作。現在,我們將結合 HASH 和 ZSET 的特性,來構建一個簡單的文章投票系統。

1.3.1 文章投票機制設計

首先,我們需要定義一些基本的引數和限制,以便更好地解決問題。假設每天有 1,000 篇文章被提交,其中約 50 篇文章足夠有趣,能夠進入前 100 名並至少保持一天。這些文章至少會獲得 200 次贊成票。在這個版本中,我們暫時不考慮反對票。

評分機制

為了使文章的評分隨著時間變化,我們需要考慮釋出時間、當前時間或兩者對整體評分的影響。為了簡化問題,我們假設文章的評分是釋出時間和贊成票數的函式。

我們使用自 1970 年 1 月 1 日以來的秒數(Unix 時間)作為時間引數。選擇 Unix 時間是因為它在大多數程式語言和平台上都很容易取得。對於常數乘數,我們取一天的秒數(86,400)除以保持文章在首頁所需的贊成票數(200),得到每票 432 分。

資料結構設計

要實作這個系統,我們需要選擇合適的 Redis 資料結構。首先,我們需要儲存文章的相關資訊,如標題、連結、釋出者、釋出時間和贊成票數。我們可以使用 Redis 的 HASH 結構來儲存這些資訊,如圖 1.8 所示。

article:92617 hash
- title: Go to statement considered harmful
- link: http://goo.gl/kZUSu
- poster: user:83271
- time: 1331382699.33
- votes: 528

使用冒號作為分隔符

在本文的範例中,我們使用冒號(:)作為名稱分隔符,例如在圖 1.8 中,用於分隔 article 和文章 ID,建立了一種類別名稱空間。選擇冒號是主觀的,但它在 Redis 使用者中很常見。其他常見的選擇包括句點(.)、正斜槓(/)和偶爾使用的管道字元(|)。無論選擇什麼,保持一致性是非常重要的。

資料結構實作

文章資訊儲存

我們使用 HASH 儲存文章資訊,如下所示:

import redis

# 連線到 Redis
r = redis.Redis(host='localhost', port=6379, db=0)

# 文章資訊
article_id = "92617"
article_info = {
    "title": "Go to statement considered harmful",
    "link": "http://goo.gl/kZUSu",
    "poster": "user:83271",
    "time": 1331382699.33,
    "votes": 0  # 初始票數為 0
}

# 將文章資訊儲存到 HASH 中
r.hmset(f"article:{article_id}", article_info)

文章排序

我們使用兩個 ZSET 分別按照文章的釋出時間和評分進行排序,如圖 1.9 所示。

# 文章釋出時間
r.zadd("time:zset", {f"article:{article_id}": article_info["time"]})

# 文章初始評分(假設初始評分為釋出時間)
r.zadd("score:zset", {f"article:{article_id}": article_info["time"]})

使用者投票記錄

為了防止使用者重複投票,我們為每篇文章使用一個 SET 儲存已投票使用者的 ID,如圖 1.10 所示。

# 使用者投票
user_id = "115423"
r.sadd(f"voted:{article_id}", f"user:{user_id}")

處理使用者投票

當使用者嘗試對一篇文章進行投票時,我們首先使用 ZSCORE 檢查文章的釋出時間,以驗證是否仍在投票時間內。如果仍在時間內,我們嘗試將使用者新增到該文章的已投票使用者 SET 中。

# 檢查文章是否存在且仍在投票時間內(假設一週內可投票)
def can_vote(article_id):
    # 取得文章釋出時間
    post_time = r.zscore("time:zset", f"article:{article_id}")
    if post_time is None:
        return False  # 文章不存在
    
    # 檢查是否仍在一週內
    import time
    current_time = time.time()
    if current_time - post_time > 604800:  # 一週秒數
        return False
    
    return True

# 使用者投票邏輯
def vote_article(article_id, user_id):
    if can_vote(article_id):
        # 將使用者新增到已投票 SET 中
        if r.sadd(f"voted:{article_id}", f"user:{user_id}") > 0:
            # 更新文章評分和票數
            r.hincrby(f"article:{article_id}", "votes", 1)
            new_score = r.zscore("score:zset", f"article:{article_id}") + 432  # 每票加 432 分
            r.zadd("score:zset", {f"article:{article_id}": new_score})
            return True
    return False

# 示例投票
vote_article("100408", "115423")

##### 圖表說明:Redis 資料結構示意圖

  graph LR;
    A[文章資訊 HASH] -->|包含|> B[標題、連結、釋出者等];
    C[按時間排序 ZSET] -->|包含|> D[文章 ID 及釋出時間];
    E[按評分排序 ZSET] -->|包含|> F[文章 ID 及當前評分];
    G[已投票使用者 SET] -->|包含|> H[使用者 ID];

圖表翻譯: 此圖表展示了 Redis 中用於儲存文章資訊的不同資料結構,包括 HASH 用於儲存詳細資訊,兩個 ZSET 分別用於按時間和評分排序,以及 SET 用於追蹤已投票使用者。每個結構都與其所包含的資料相關聯,確保系統的高效運作。