Fork me on GitHub

Redis Cookbook

Implement a Simple Social Graph

Credit: Michael Bleigh
Tags: sets, abstractions

Problem

You want to use Redis to implement a social graph for users in some kind of application, with one and two directional relationships available (following and friendship).

Solution

Use the built-in set functionality of Redis to construct follow, follower, and blocked lists keyed to each user's unique ID. In raw redis it looks something like this:

redis> SADD user:1:follows 2
(integer) 1
redis> SADD user:2:followers 1
(integer) 1
redis> SADD user:3:follows 1
(integer) 1
redis> SADD user:1:followers 3
(integer) 1
redis> SADD user:1:follows 3
(integer) 1
redis> SADD user:3:followers 1
(integer) 1
redis> SINTER user:1:follows user:1:followers
1. 3

Discussion

Redis comes with the ability to construct "sets", which are collections of unique values assigned to a key. By creating both a "follows" and "followers" list for a given user, we are able to quickly and easily pull that information as well as calculate their "friendships" using a simple set intersection.

Implementing such a system in Ruby looks something like this:

REDIS = Redis.new

class User
  def self.find(*ids)
    # gets a set of User objects given IDs
  end

  def follow(other_user)
    REDIS.sadd("user:#{self.id}:follows", other_user.id)
    REDIS.sadd("user:#{other_user.id}:followers", self.id)
  end

  def followers
    User.find(*REDIS.smembers("user:#{self.id}:followers"))
  end

  def follows
    User.find(*REDIS.smembers("user:#{self.id}:follows"))
  end

  def friends
    User.find(*REDIS.sinter("user:#{self.id}:followers", "user:#{self.id}:follows"))
  end
end