Friend-of-friend recommendation with strength
Objective
LinkedIn's "People You May Know" ranks suggestions by mutual-connection count and interaction strength. We will replicate it on a 12-person network with weighted friendships, returning the top connection candidates for a target user — all in one Cypher query.
Step 1: Create the graph
MERGE (sarah:Person {name: "Sarah Chen"})
MERGE (raj:Person {name: "Raj Patel"})
MERGE (mia:Person {name: "Mia Rossi"})
MERGE (leo:Person {name: "Leo Park"})
MERGE (eli:Person {name: "Eli Tanaka"})
MERGE (zoe:Person {name: "Zoe Williams"})
MERGE (kai:Person {name: "Kai Nakamura"})
MERGE (ana:Person {name: "Ana Mendez"})
MERGE (dev:Person {name: "Dev Singh"})
MERGE (fin:Person {name: "Fin O'Connor"})
MERGE (gus:Person {name: "Gus Albrecht"})
MERGE (han:Person {name: "Hannah Lee"})
// Weighted friendships — interactions per month (proxy for tie strength)
MERGE (sarah)-[:KNOWS {strength: 9}]->(raj)
MERGE (sarah)-[:KNOWS {strength: 6}]->(mia)
MERGE (sarah)-[:KNOWS {strength: 3}]->(kai)
MERGE (raj)-[:KNOWS {strength: 8}]->(leo)
MERGE (raj)-[:KNOWS {strength: 4}]->(eli)
MERGE (raj)-[:KNOWS {strength: 7}]->(dev)
MERGE (mia)-[:KNOWS {strength: 5}]->(zoe)
MERGE (mia)-[:KNOWS {strength: 6}]->(ana)
MERGE (leo)-[:KNOWS {strength: 9}]->(zoe)
MERGE (eli)-[:KNOWS {strength: 5}]->(zoe)
MERGE (kai)-[:KNOWS {strength: 7}]->(fin)
MERGE (ana)-[:KNOWS {strength: 4}]->(gus)
MERGE (dev)-[:KNOWS {strength: 6}]->(han)
MERGE (zoe)-[:KNOWS {strength: 5}]->(han);
Step 2: Suggest connections for Sarah
// Score = number of mutual friends * sum of edge weights along the path.
MATCH (sarah:Person {name: "Sarah Chen"})-[r1:KNOWS]-(mutual)-[r2:KNOWS]-(candidate)
WHERE candidate <> sarah
AND NOT (sarah)-[:KNOWS]-(candidate)
RETURN candidate.name AS suggestion,
count(DISTINCT mutual) AS mutual_friends,
sum(r1.strength + r2.strength) AS tie_score
ORDER BY tie_score DESC, mutual_friends DESC
LIMIT 5;
What's happening
- Bidirectional edges are matched with
-[:KNOWS]-(no arrow) so direction does not matter. - We sum edge weights along each path to combine "who knows them" with "how well" — relationship properties make this trivial; SQL would need composite joins on a weights table.
- Unlike a simple JOIN, the query naturally degrades to mutual-friend count if weights are absent.
- The
NOT (sarah)-[:KNOWS]-(candidate)anti-pattern excludes existing connections in one line. - Swap the
LIMITand ordering to expose this as a real recommendation API in production.
Try this next
MATCH (a:Person)-[r:KNOWS]-(b:Person)
RETURN a.name AS person, sum(r.strength) AS social_capital
ORDER BY social_capital DESC LIMIT 5;
MATCH (a:Person {name: "Sarah Chen"}), (b:Person {name: "Hannah Lee"}),
path = shortestPath((a)-[:KNOWS*..6]-(b))
RETURN [n IN nodes(path) | n.name] AS introduction_chain;
MATCH (p:Person)-[:KNOWS]-(other)
RETURN p.name AS person, count(other) AS degree
ORDER BY degree DESC;