Redis Sorted Set: Skip List + Dict

Introduction

Redis is an in-memory data structure store that can be used as a database, cache, and message broker. One of the data structures provided by Redis is the Sorted Set, which is an ordered collection of unique elements.

In this article, we will explore how Redis implements the Sorted Set data structure using a combination of Skip List and Dictionary. We will discuss the characteristics of these data structures and their benefits for efficient Sorted Set operations. We will also provide code examples to demonstrate the usage of Redis Sorted Sets.

Skip List

A Skip List is a data structure that allows for efficient search, insertion, and deletion operations. It consists of a series of linked lists, where each list is a subset of the previous list. The first list contains all elements and subsequent lists contain a fraction of the elements, reducing the number of comparisons required for search operations.

The Skip List used in Redis Sorted Sets is implemented as a linked list of sorted nodes. Each node contains a score (used for ordering) and a value (the actual element). The linked lists are built in levels, with each level having a different probability of including an element. This allows for a fast search with a logarithmic time complexity.

Let's take a look at the code that represents a Skip List node:

class SkipListNode:
    def __init__(self, score, value):
        self.score = score
        self.value = value
        self.forward = []

The SkipListNode class represents a node in the Skip List. It has a score attribute to store the ordering value and a value attribute to store the actual element. The forward attribute is a list that contains pointers to the next nodes in each level.

Dictionary

In addition to the Skip List, Redis uses a Dictionary data structure to store the elements of the Sorted Set. The Dictionary is implemented as a Hash Table, which provides constant time complexity for search, insertion, and deletion operations on average.

The Dictionary used in Redis Sorted Sets is a mapping of elements to their corresponding scores. It allows for efficient retrieval of elements based on their score values.

Let's represent the Dictionary using code:

class SortedSetDict:
    def __init__(self):
        self.dict = {}

    def add(self, value, score):
        self.dict[value] = score

    def remove(self, value):
        del self.dict[value]

    def get_score(self, value):
        return self.dict.get(value)

The SortedSetDict class represents the Dictionary used in Redis Sorted Sets. It has methods to add, remove, and retrieve elements based on their scores.

Sorted Set Operations

Now that we have an understanding of the underlying data structures, let's explore the operations that can be performed on Redis Sorted Sets. The following are some of the common operations:

  • Add: Adds an element to the Sorted Set with a given score.
  • Remove: Removes an element from the Sorted Set.
  • Get Rank: Returns the rank of an element in the Sorted Set based on its score.
  • Get Range: Returns a range of elements from the Sorted Set based on their ranks.
  • Get Score: Returns the score of an element in the Sorted Set.
  • Get Rank by Score: Returns the rank of an element in the Sorted Set based on its score.

Let's demonstrate the usage of these operations with code:

class RedisSortedSet:
    def __init__(self):
        self.skip_list = []
        self.dict = SortedSetDict()

    def add(self, value, score):
        node = SkipListNode(score, value)
        self.skip_list.append(node)
        self.dict.add(value, score)

    def remove(self, value):
        node = self.get_node(value)
        if node:
            self.skip_list.remove(node)
            self.dict.remove(value)

    def get_rank(self, value):
        score = self.dict.get_score(value)
        if score:
            rank = sum(1 for node in self.skip_list if node.score < score)
            return rank + 1

    def get_range(self, start_rank, end_rank):
        nodes = self.skip_list[start_rank-1:end_rank]
        return [node.value for node in nodes]

    def get_score(self, value):
        return self.dict.get_score(value)

    def get_rank_by_score(self, score):
        rank = sum(1 for node in self.skip_list if node.score < score)
        return rank + 1

The RedisSortedSet class represents the Redis Sorted Set. It uses the Skip List and Dictionary data structures to perform the required operations. The add method adds an element to the Sorted Set by creating a new node in the Skip List and adding the element to the Dictionary. The remove method removes an element by finding the node in the Skip List and removing the element from the Dictionary. The get_rank method returns the rank of an element based on its score, and the get_range method returns a range of elements based on their ranks. The get_score method retrieves the score of an element, and the get_rank_by_score method returns the rank of an element based on its score.

Conclusion

Redis implements the Sorted Set data structure using a combination of Skip List and Dictionary. The