Core Data Structures II: Sets & Sorted Sets

Redis
Chapter 4 ยท Core Data Structures II: Sets & Sorted Sets

๐ŸŽฏ Core Data Structures II: Sets & Sorted Sets

Chapter 3 covered Strings, Lists, and Hashes. Two more shapes complete Redis's core toolkit: Sets, for unique unordered collections, and Sorted Sets, for unique collections ordered by a numeric score โ€” the structure behind two of Redis's most famous real-world patterns.

Sets: Unique, Unordered Collections

A Redis set holds unique members with no defined order โ€” adding the same value twice has no effect, and duplicates are automatically rejected.

127.0.0.1:6379> SADD post:55:tags "redis" "databases" "redis" (integer) 2 127.0.0.1:6379> SMEMBERS post:55:tags 1) "redis" 2) "databases"

Note the return value: 2, not 3 โ€” the second "redis" was silently ignored as a duplicate, exactly what a set is for.

SINTER computes the intersection of multiple sets โ€” useful for "which members appear in both of these collections":

127.0.0.1:6379> SADD likes:redis alice bob carol (integer) 3 127.0.0.1:6379> SADD likes:databases bob carol dave (integer) 3 127.0.0.1:6379> SINTER likes:redis likes:databases 1) "bob" 2) "carol"

Sorted Sets: Ordered by Score

A sorted set combines a set's uniqueness with an explicit numeric score per member โ€” Redis maintains the members in score order automatically, regardless of insertion order.

127.0.0.1:6379> ZADD scores 42 "alice" (integer) 1 127.0.0.1:6379> ZADD scores 91 "bob" (integer) 1 127.0.0.1:6379> ZRANGE scores 0 -1 WITHSCORES 1) "alice" 2) "42" 3) "bob" 4) "91"

ZRANGE returns members in ascending score order regardless of the order they were added โ€” alice (added first) still comes before bob because 42 < 91, not because of insertion order.

The Leaderboard Pattern

A sorted set is the textbook fit for a game leaderboard: score as the ranking value, ZREVRANGE for highest-first, ZSCORE to look up one player, ZRANK for their position.

127.0.0.1:6379> ZADD leaderboard 1500 "player1" 2200 "player2" 800 "player3" (integer) 3 127.0.0.1:6379> ZREVRANGE leaderboard 0 2 WITHSCORES 1) "player2" 2) "2200" 3) "player1" 4) "1500" 5) "player3" 6) "800" 127.0.0.1:6379> ZSCORE leaderboard "player1" "1500"

The Sliding-Window Counter Pattern

Sorted sets also power a classic real-world Redis pattern: rate limiting via a sliding window. Each request is added with the current timestamp as its score; old entries outside the window are pruned; the remaining count is the request count within that window โ€” the exact mechanism behind Chapter 10's capstone.

127.0.0.1:6379> ZADD ratelimit:user104 1720000000 "req1" (integer) 1 -- prune anything older than 60 seconds before "now" 127.0.0.1:6379> ZREMRANGEBYSCORE ratelimit:user104 -inf 1719999940 (integer) 0 -- count how many requests remain within the window 127.0.0.1:6379> ZCARD ratelimit:user104 (integer) 1

Set vs. Sorted Set

Set

Unique members, no order at all โ€” good for membership tests and intersections (tags, "has this user done X").

Sorted Set

Unique members, ordered by an explicit score โ€” good for rankings, leaderboards, and time-windowed data.

CommandStructurePurpose
SADD / SMEMBERSSetAdd members; list all members
SINTERSetIntersection of multiple sets
ZADDSorted SetAdd a member with a numeric score
ZRANGE / ZREVRANGESorted SetRead members in ascending / descending score order
ZSCORE / ZRANKSorted SetLook up one member's score / rank position
ZREMRANGEBYSCORESorted SetRemove members whose score falls in a range (pruning old entries)
ZCARDSorted SetCount members in a sorted set

๐Ÿ’ป Coding Challenges

Challenge 1: Find Shared Tags

Two posts have tags stored as sets: post:1:tags = {redis, databases, nosql} and post:2:tags = {redis, sql, databases}. Write the command to find tags shared by both posts.

Goal: Practice SINTER for a realistic "what do these two collections have in common" scenario.

โ†’ Solution

Challenge 2: Build a Mini Leaderboard

Add three players to a sorted set called game:leaderboard with scores 300, 750, and 500. Write the command to retrieve them highest-score-first, with scores shown.

Goal: Practice ZADD and ZREVRANGE WITHSCORES together for the standard leaderboard read.

โ†’ Solution

Challenge 3: Explain the Sliding-Window Pattern

Explain, in your own words, why a sorted set with timestamps as scores is a good fit for rate limiting, and what role ZREMRANGEBYSCORE plays in keeping the count accurate over time.

Goal: Practice explaining the mechanics behind this chapter's rate-limiting pattern, not just running the commands.

โ†’ Solution

โš ๏ธ Gotcha: Equal Scores Break Ties Lexicographically

When two members in a sorted set have the exact same score, Redis doesn't leave their relative order undefined โ€” it breaks the tie by comparing the members themselves in lexicographic (dictionary) order. This is easy to overlook until it produces a surprising leaderboard: two players tied at the same score will always appear in the same relative order (by name), not in insertion order or randomly, every time the sorted set is read. If tie-breaking by name isn't the desired behavior, the score itself needs to encode enough information to break ties meaningfully (e.g. combining a primary score with a secondary tiebreaker value).

๐ŸŽฏ What's Next

The next chapter is Expiration & Caching Patterns โ€” TTL/EXPIRE, the cache-aside pattern, and cache stampede prevention, deepening node3-5's brief mention of Redis caching.