Skip to content

Commit

Permalink
Add social graph recipe.
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Bleigh authored and tlossen committed Apr 12, 2010
1 parent 1713916 commit 94258e7
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: Implement a Simple Social Graph
credit:
- Michael Bleigh
tags:
- sets
- abstractions
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
### 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:

{% code_snippet social_graph.rb %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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

0 comments on commit 94258e7

Please sign in to comment.