Friends of friends melts a join — the pointer walk that replaces the self-join
In a relational store every extra hop of 'friends of friends' is another self-join of the friendship table, so the intermediate rows explode combinatorially (50 → 2,500 → 6.25M → 312M), while the same question answered by walking from person to person only ever touches the people you actually reach.
Scene 01
Friends of friends melts a join
- Watch
- Try it
- Predict
- Capture
One question: 'who are Alice's friends of friends of friends?' On the LEFT, a relational store answers it by joining the friendship table to itself once per hop — watch the intermediate-row counter as the depth climbs. On the RIGHT, the same question is answered by walking from Alice, person to person, lighting up only the people the walk actually reaches. Watch the two numbers pull apart.
Highlighted lines are the ones running in the diagram right now.
def friends_of_friends(start, depth):rows = [(start,)] # depth 0: just Alicefor hop in range(depth): # ONE self-join per hop# join USER_FRIEND again: every row fans to its friendsrows = [(*r, f)for r in rowsfor f in friends_of(r[-1])] # ~degree eachreturn dedup(last_col(rows)) # ...after materializing rows
def expand(start, depth):seen = {start}frontier = [start]for hop in range(depth): # one step per hopnxt = []for person in frontier:for friend in neighbors(person): # follow an edgeif friend not in seen: # skip the visitedseen.add(friend); nxt.append(friend)frontier = nxt # only the newly reachedreturn seen - {start}
def relational_cost(depth):return DEGREE ** depth # 50^d candidate rowsdef walk_cost(depth):# bounded by distinct people reachable, not 50^dreturn len(reachable_within(start, depth))
Where this sits in Build a graph database (Neo4j / Dgraph-style)
Scene 01 of 16, in the Why graphs act — Friends-of-friends melts a join; edges go first-class.. The canonical graph workload — 'friends of friends of friends' — is one self-join per hop, and the intermediate row count explodes combinatorially until a relational engine can't finish; the same query as a pointer walk visits only the people you actually reach.
Up next. The pointer walk won because it treated a friendship as a thing you can FOLLOW, not a row you have to re-join. But we drew that edge by hand — we never said how the data is actually shaped so that an edge becomes followable. Before we can make hops cheap, we need a data model where an edge is a first-class object, not a row in a join table.
All 16 scenes in Build a graph database (Neo4j / Dgraph-style) · Every curriculum