Overview:
- Redis is an in-memory data structure store.
- Redis supports several data structures and set is one of them, which implements the mathematical concept of set.
- Redis also provides another set data structure called sorted set.
- A sorted set is a set where the elements are always sorted based on a collection of scores.
- The elements of the set themselves are not ordered but the elements are ordered based on an associated score.
- Sorted set is like a hash map where the elements are sorted based on a key.
- The time complexity for adding an element into a sorted set is O(log(N)).Every time an element is added the set is sorted as well. When an ordered collection is asked for there is no time spent for sorting as the set is already sorted.
- Sorted set in Redis is implemented by using a skip list and a hash map.
- The Redis CLI commands provided in this article can be executed directly from Redis CLI. The equivalent methods of redis-py are used in the Python examples to interact with the Redis server.
Quick Refresh: Skip List
A skip list maintains a collection of subsequences on an ordered set of items. Subsequences are maintained in a hierarchical fashion. The time to search a skip list is O(log(N)) as the number of levels in the hierarchy are O(log (N)). In a skip list, the higher the hierarchy of a subsequence the higher the number of keys skipped. |
Adding elements to a sorted set:
- Elements can be added to a Redis sorted set using the ZADD command.
- The ZADD command is similar to the SADD command of the Redis Set except that the ZADD command expects a score as well to be provided for the element.
- The commands ZRANGE is used to retrieve the elements of the sorted set by specifying a range between minimum index and the maximum index of the elements. 0 is the first index and the -1 is the last index. By default ZRANGE prints in the ascending order.
- ZREVRANGE is similar to ZRANGE except that ZREVRANGE prints in the reverse order.
- The time complexity of both ZREVRANGE and ZRANGE is O (log (N) + M). Where
N is Total number of elements in the Redis sorted set.
M is Number of elements returned.
Example:
import redis
# Create a redis client redisClient = redis.StrictRedis(host='localhost', port=6379, db=0) # Name of the Redis sorted set players = "Players"
# Add a player to the Redis sorted set against the score score = 56 playerName = "Player1" redisClient.zadd(players, score, playerName)
# Add a player to the Redis sorted set against the score score = 25 playerName = "Player2" redisClient.zadd(players, score, playerName)
# Add a player to the Redis sorted set against the score score = 37 playerName = "Player3" redisClient.zadd(players, score, playerName)
# Print all the players based on the score in ascending order print("Contents of the Redis sorted set in ascending order:") print(redisClient.zrange(players, 0, -1))
# Print all the players based on score in descending order print("Contents of the Redis sorted set in descending order:") print(redisClient.zrange(players, 0, -1, desc=True))
# Print all the players based on score in descending order along with the scores print("Contents of the Redis sorted set with scores:") print(redisClient.zrange(players, 0, -1, withscores=True)) |
Output:
Contents of the Redis sorted set in ascending order: [b'Player2', b'Player3', b'Player1'] Contents of the Redis sorted set in descending order: [b'Player1', b'Player3', b'Player2'] Contents of the Redis sorted set with scores: [(b'Player2', 25.0), (b'Player3', 37.0), (b'Player1', 56.0)] |
Retrieve elements from a Redis Sorted Set:
- The command ZSCORE can be used to retrieve element(s) based on the score. When multiple elements are available against the same score the elements are returned in lexicographical order.
- To retrieve elements falling under a range of scores the ZRANGEBYSCORE command is used.
- Similar to SCARD of a set, the ZCARD command of the sorted set provides the cardinality or the size of the sorted set.
- The ZCOUNT is used for getting the count of elements falling under a range of scores.
import redis
# Create a redis client redisClient = redis.StrictRedis(host='localhost', port=6379, db=0) # Name of the Redis sorted set candidates = "Candidates"
redisClient.zadd(candidates, 100, "Candidate1", 56, "Candidate2", 72, "Candidate3", 45, "Candidate5", 45, "Candidate4")
print("Cardinality of the Redis sorted set:") print(redisClient.zcard(candidates))
print("Count of candidates between a score/vote of 50 to 100:") print(redisClient.zcount(candidates, 50, 100))
print("Count of candidates between a score/vote of 0 to 50:") print(redisClient.zcount(candidates, 0, 50))
print("Find the rank/score of an element in the Redis sorted set:") elementValue = "Candidate3" print("Score of the element with value '{}' is ".format(elementValue)) print(redisClient.zscore(candidates, "Candidate3"))
print("Retrieve elements from the Redis sorted set based on a range of scores:") print(redisClient.zrangebyscore(candidates, min=0, max=100, withscores = True))
print("Retrieve elements from the Redis sorted set based on a range of scores in reverse orders:") print(redisClient.zrevrangebyscore(candidates, min=0, max=100, withscores = True)) |
Output:
Cardinality of the Redis sorted set: 5 Count of candidates between a score/vote of 50 to 100: 3 Count of candidates between a score/vote of 0 to 50: 2 Find the rank/score of an element in the Redis sorted set: Score of the element with value 'Candidate3' is 72.0 Retrieve elements from the Redis sorted set based on a range of scores: [(b'Candidate4', 45.0), (b'Candidate5', 45.0), (b'Candidate2', 56.0), (b'Candidate3', 72.0), (b'Candidate1', 100.0)] Retrieve elements from the Redis sorted set based on a range of scores in reverse orders: [(b'Candidate1', 100.0), (b'Candidate3', 72.0), (b'Candidate2', 56.0), (b'Candidate5', 45.0), (b'Candidate4', 45.0)] |
Removing elements from a sorted set:
- The command ZREM is used to remove one or more elements of a Redis sorted set.
- With the command ZREMBYRANGE, elements can be removed from a sorted set by specifying a range of scores.
Example:
import redis
# Create a redis client redisClient = redis.StrictRedis(host='localhost', port=6379, db=0)
# Name of the Redis sorted set teams = "Teams"
# Add elements to the Redis sorted set redisClient.zadd(teams, "291", "Team1") redisClient.zadd(teams, "142", "Team2") redisClient.zadd(teams, "256", "Team3") redisClient.zadd(teams, "197", "Team4") redisClient.zadd(teams, "220", "Team5")
# Print the sorted set print("Contents of the sorted set:") print(redisClient.zrange(teams, 0, -1, desc=True, withscores=True))
# Remove some of the elements print("Removing few elements from the Redis sorted set:") print(redisClient.zrem(teams, "Team2", "Team4"))
# Remove some of the elements by score print("Removing the range of elements by score:") print(redisClient.zremrangebyscore(teams, 200, 250))
# Print the remaining elements after removal print("Remaining elements of the sorted set after removals:") print(redisClient.zrevrange(teams, 0, -1, withscores=True)) |
Output:
Contents of the sorted set: [(b'Team1', 291.0), (b'Team3', 256.0), (b'Team5', 220.0), (b'Team4', 197.0), (b'Team2', 142.0)] Removing few elements from the Redis sorted set: 2 Removing the range of elements by score: 1 Remaining elements of the sorted set after removals: [(b'Team1', 291.0), (b'Team3', 256.0)] |