Graph Patterns
Friend-of-Friend Queries
Social graph traversal patterns for recommendations and connection discovery.
// 2nd-degree connections (friends of friends)
MATCH (me:Person {name: "Alice"})-[:KNOWS]->(friend)-[:KNOWS]->(fof:Person)
WHERE NOT (me)-[:KNOWS]->(fof) // exclude direct friends
AND fof.name <> "Alice"
RETURN DISTINCT fof.name, count(*) AS mutual_friends
ORDER BY mutual_friends DESC
LIMIT 10;
// Mutual friends between two people
MATCH (a:Person {name:"Alice"})-[:KNOWS]->(mutual)<-[:KNOWS]-(b:Person {name:"Bob"})
RETURN mutual.name AS mutual_friend;
// Recommend products (collaborative filtering)
MATCH (me:User {id:1})-[:BOUGHT]->(p:Product)<-[:BOUGHT]-(similar:User)
-[:BOUGHT]->(rec:Product)
WHERE NOT (me)-[:BOUGHT]->(rec)
RETURN rec.name, count(similar) AS score
ORDER BY score DESC LIMIT 10;
Shortest Path
// Shortest path (unweighted)
MATCH path = shortestPath(
(a:Person {name:"Alice"})-[:KNOWS*]-(b:Person {name:"Dave"})
)
RETURN path, length(path);
// All shortest paths
MATCH path = allShortestPaths(
(a:Person {name:"Alice"})-[:KNOWS*]-(b:Person {name:"Dave"})
)
RETURN path;
// Dijkstra weighted shortest path (GDS required for large graphs)
// Cypher built-in: apoc.algo.dijkstra
MATCH (start:City {name:"NYC"}), (end:City {name:"LA"})
CALL apoc.algo.dijkstra(start, end, 'ROAD', 'distance') YIELD path, weight
RETURN [n IN nodes(path) | n.name] AS route, weight AS distance;
// Check if two nodes are connected
MATCH (a:Person {name:"Alice"}), (b:Person {name:"Zed"})
RETURN exists((a)-[:KNOWS*]-(b)) AS connected;
Graph Data Science (GDS) Algorithms
// Graph Data Science library must be installed
// https://neo4j.com/docs/graph-data-science/
// Project a graph into memory
CALL gds.graph.project(
'social',
'Person',
{ KNOWS: { orientation: 'UNDIRECTED' } }
);
// PageRank: measure node influence
CALL gds.pageRank.stream('social')
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC LIMIT 10;
// Betweenness Centrality: find bridge nodes
CALL gds.betweenness.stream('social')
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name, score
ORDER BY score DESC LIMIT 5;
// Louvain Community Detection
CALL gds.louvain.stream('social')
YIELD nodeId, communityId
RETURN communityId, collect(gds.util.asNode(nodeId).name) AS members
ORDER BY size(members) DESC;
// Clean up
CALL gds.graph.drop('social');
Path Functions & Pattern Predicates
// nodes() and relationships() on a path
MATCH path = (a:Person)-[:KNOWS*1..4]->(b:Person {name:"Dave"})
RETURN [n IN nodes(path) | n.name] AS names,
length(path) AS hops;
// exists(): check if pattern exists
MATCH (p:Person)
WHERE exists((p)-[:MANAGES]->(:Team))
RETURN p.name AS manager;
// none() / any() / all() / single() predicates
MATCH path = (a:Person)-[:KNOWS*]->(b:Person)
WHERE none(r IN relationships(path) WHERE r.blocked = true)
RETURN path;
// Pattern comprehension: collect paths as list
MATCH (a:Person {name:"Alice"})
RETURN [(a)-[:KNOWS]->(f) | f.name] AS friend_names;
// reduce(): accumulate over path
MATCH path = (a:City)-[:ROAD*]->(b:City)
RETURN reduce(total = 0, r IN relationships(path) | total + r.distance) AS dist;
Common Graph Schema Patterns
| Pattern | Example |
|---|---|
| Social network | (Person)-[:KNOWS]->(Person) |
| Roles on relationships | (User)-[:MEMBER_OF {role:"admin"}]->(Org) |
| Event sourcing | (User)-[:PERFORMED {at:dt}]->(Action) |
| Product catalog | (Product)-[:BELONGS_TO]->(Category)-[:PARENT]->(Category) |
| Knowledge graph | (Concept)-[:RELATED_TO {weight:0.8}]->(Concept) |
| Dependency graph | (Package)-[:DEPENDS_ON {version:"^2.0"}]->(Package) |