Redis Sorted Sets (Part 1)
A sorted set is a set with scores, where elements are sorted by score. This lesson covers basic sorted set operations.
What is a Sorted Set?
Sorted set features:
- Ordered: elements are sorted by score (ascending)
- Unique: elements are unique, but scores can repeat
- Each element has a score: used for sorting
leaderboard
├─ "player1" → score: 100
├─ "player2" → score: 200
├─ "player3" → score: 300
└─ "player4" → score: 400
💡 Internal implementation: Sorted sets use a skip list + hash table. The skip list supports efficient sorting and range queries, while the hash table enables fast score lookups.
ZADD: Add Elements
Basic Usage
REDIS
# Add a single element
ZADD leaderboard 100 "player1"
(integer) 1 # Returns number of newly added elements
# Add multiple elements
ZADD leaderboard 200 "player2" 300 "player3" 400 "player4"
(integer) 3
ZADD Parameters
REDIS
# NX: Only add new elements, don't update existing ones
ZADD leaderboard NX 150 "player1"
(integer) 0 # player1 already exists, not updated
# XX: Only update existing elements, don't add new ones
ZADD leaderboard XX 500 "player5"
(integer) 0 # player5 doesn't exist, not added
# CH: Return the number of changed elements (including updates)
ZADD leaderboard CH 120 "player1"
(integer) 1 # Updated player1's score
# INCR: Increment score (equivalent to ZINCRBY)
ZADD leaderboard INCR 50 "player1"
"170" # Returns new score
Updating an Existing Element's Score
REDIS
# If element already exists, update its score
ZADD leaderboard 250 "player1"
# View new score
ZSCORE leaderboard "player1"
"250"
ZSCORE: Get Element Score
REDIS
ZADD leaderboard 100 "player1" 200 "player2"
# Get score
ZSCORE leaderboard "player1"
"100"
# Element does not exist
ZSCORE leaderboard "notexist"
(nil)
ZRANK and ZREVRANK: Get Rank
ZRANK: Rank from Low to High
REDIS
ZADD leaderboard 100 "player1" 200 "player2" 300 "player3"
# Rank starts at 0
ZRANK leaderboard "player1"
(integer) 0 # 1st place (lowest score)
ZRANK leaderboard "player2"
(integer) 1 # 2nd place
ZRANK leaderboard "player3"
(integer) 2 # 3rd place
ZREVRANK: Rank from High to Low
REDIS
# Rank from high to low (highest score is rank 0)
ZREVRANK leaderboard "player3"
(integer) 0 # 1st place (highest score)
ZREVRANK leaderboard "player2"
(integer) 1 # 2nd place
ZREVRANK leaderboard "player1"
(integer) 2 # 3rd place
💡 Rank rules:
- ZRANK: low to high score, lowest score has rank 0
- ZREVRANK: high to low score, highest score has rank 0
- Rank starts at 0, 1st place has rank 0
ZRANGE and ZREVRANGE: Get Elements by Rank Range
ZRANGE: Get by Rank Range (Low to High)
REDIS
ZADD leaderboard 100 "player1" 200 "player2" 300 "player3" 400 "player4"
# Get all elements
ZRANGE leaderboard 0 -1
1) "player1"
2) "player2"
3) "player3"
4) "player4"
# Get first 2 elements
ZRANGE leaderboard 0 1
1) "player1"
2) "player2"
# Get last 2 elements
ZRANGE leaderboard -2 -1
1) "player3"
2) "player4"
# Get elements with scores
ZRANGE leaderboard 0 -1 WITHSCORES
1) "player1"
2) "100"
3) "player2"
4) "200"
5) "player3"
6) "300"
7) "player4"
8) "400"
ZREVRANGE: Get by Rank Range (High to Low)
REDIS
# Get all elements from high to low
ZREVRANGE leaderboard 0 -1 WITHSCORES
1) "player4"
2) "400"
3) "player3"
4) "300"
5) "player2"
6) "200"
7) "player1"
8) "100"
# Get top 3 (highest scores)
ZREVRANGE leaderboard 0 2 WITHSCORES
1) "player4"
2) "400"
3) "player3"
4) "300"
5) "player2"
6) "200"
ZCARD: Get Element Count
REDIS
ZADD leaderboard 100 "player1" 200 "player2" 300 "player3"
ZCARD leaderboard
(integer) 3
ZCOUNT: Count Elements Within a Score Range
REDIS
ZADD leaderboard 100 "player1" 150 "player2" 200 "player3" 250 "player4" 300 "player5"
# Count elements with scores between 150 and 250
ZCOUNT leaderboard 150 250
(integer) 3 # player2, player3, player4
# Use -inf and +inf for negative/positive infinity
ZCOUNT leaderboard -inf +inf
(integer) 5 # All elements
ZREM: Remove Elements
REDIS
ZADD leaderboard 100 "player1" 200 "player2" 300 "player3"
# Remove a single element
ZREM leaderboard "player1"
(integer) 1
# Remove multiple elements
ZREM leaderboard "player2" "player3"
(integer) 2
# Remove a non-existent element
ZREM leaderboard "notexist"
(integer) 0
ZINCRBY: Increment Score
REDIS
ZADD leaderboard 100 "player1"
# Increase score by 50
ZINCRBY leaderboard 50 "player1"
"150" # Returns new score
# Decrease score (pass a negative number)
ZINCRBY leaderboard -20 "player1"
"130"
Sorted Set Use Cases
Use Case 1: Gaming Leaderboard
REDIS
# Update player scores
ZADD game:leaderboard 1500 "player:123"
ZADD game:leaderboard 2300 "player:456"
ZADD game:leaderboard 1800 "player:789"
# Get top 10
ZREVRANGE game:leaderboard 0 9 WITHSCORES
# Get player rank
ZREVRANK game:leaderboard "player:123"
# Increase player score
ZINCRBY game:leaderboard 100 "player:123"
Use Case 2: Trending Search
REDIS
# Update trending heat scores
ZADD hot:search 10000 "Redis tutorial"
ZADD hot:search 8000 "Python basics"
ZADD hot:search 15000 "JavaScript"
# Get top 10 trending
ZREVRANGE hot:search 0 9 WITHSCORES
# Increase heat score
ZINCRBY hot:search 100 "Redis tutorial"
Use Case 3: Delayed Queue
REDIS
# Add delayed tasks (score is execution timestamp)
ZADD delay:queue 1719129600 "task:1" # 2024-06-23 10:00:00
ZADD delay:queue 1719133200 "task:2" # 2024-06-23 11:00:00
# Get tasks before current time (tasks to execute)
ZRANGEBYSCORE delay:queue -inf 1719129600
Use Case 4: Weighted Tags
REDIS
# User interest tags (score is interest level)
ZADD user:1:interests 100 "redis"
ZADD user:1:interests 80 "database"
ZADD user:1:interests 60 "cache"
# Get user's most interesting tags
ZREVRANGE user:1:interests 0 4 WITHSCORES
Use Case 5: Exam Rankings
REDIS
# Student scores
ZADD exam:math 95 "student:1"
ZADD exam:math 88 "student:2"
ZADD exam:math 92 "student:3"
# Get score ranking
ZREVRANGE exam:math 0 -1 WITHSCORES
# Get student rank
ZREVRANK exam:math "student:1"
Sorted Set Encoding Optimization
Redis automatically selects encoding based on sorted set size:
| Encoding | Condition | Description |
|---|---|---|
| ziplist | Elements <= 128, element length <= 64 bytes | Compressed list, saves memory |
| skiplist | Elements > 128 or element length > 64 bytes | Skip list + hash table, better performance |
Checking Encoding Type
REDIS
ZADD small:zset 1 "a" 2 "b" 3 "c"
OBJECT ENCODING small:zset
"ziplist"
# After adding many elements
OBJECT ENCODING large:zset
"skiplist"
❓ FAQ
Q What's the difference between a sorted set and a set?
A Every element in a sorted set has a score and is sorted by it. Sets are unordered. Sorted sets are ideal for leaderboards and ranking scenarios.
Q Can scores be decimals?
A Yes. Scores are double-precision floating-point numbers, supporting decimals.
Q Does ZRANK return ranks starting from 0 or 1?
A From 0. 1st place has rank 0, 2nd place has rank 1.
Q How do I get the element with the highest score?
A Use
ZREVRANGE key 0 0 or ZRANGE key -1 -1.Q Can elements be duplicated?
A No. Elements are unique, but scores can be duplicated.
📖 Summary
- Sorted sets are sets with scores; elements are sorted by score
- ZADD adds elements, ZSCORE gets scores
- ZRANK/ZREVRANK get rank (low-to-high / high-to-low)
- ZRANGE/ZREVRANGE get elements by rank range
- ZCARD gets element count, ZCOUNT counts elements in a score range
- ZREM removes elements, ZINCRBY increments scores
- Sorted set applications: leaderboards, trending, delayed queues, rankings
📝 Exercises
- Leaderboard: Use a sorted set to implement a gaming leaderboard — update scores, view ranks, get top 10
- Trending list: Implement a trending search list — update heat scores, view trending, increase heat
- Exam ranking: Store student scores in a sorted set, view rankings and scores
- Delayed queue: Use a sorted set to implement a delayed task queue — add tasks, get due tasks
Next Lesson
In the next lesson, we will learn Redis Sorted Sets (Part 2), covering advanced sorted set operations.



