Skip to content

Graph Database: Graph Patterns

Graph Database: Graph Patterns

Part of: Graph Database User Guide


Graph patterns describe the structure you’re looking for. HeliosDB supports various pattern types.

Simple Paths: (a)-[r]->(b)

Find direct connections between two nodes.

Example 14: Direct Friendship

// Pattern: (person1)-[FRIEND_OF]->(person2)
let pattern = Pattern {
nodes: vec![
NodePattern {
variable: "person1".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
},
NodePattern {
variable: "person2".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
},
],
relationships: vec![RelationshipPattern {
variable: Some("friendship".to_string()),
types: vec!["FRIEND_OF".to_string()],
direction: Direction::Outgoing,
properties: HashMap::new(),
length: PathLength::Fixed(1),
}],
};

Example 15: Bidirectional Relationship

// Pattern: (a)-[KNOWS]-(b) (either direction)
let pattern = Pattern {
nodes: vec![
NodePattern {
variable: "a".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
},
NodePattern {
variable: "b".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
},
],
relationships: vec![RelationshipPattern {
variable: None,
types: vec!["KNOWS".to_string()],
direction: Direction::Both, // Either direction
properties: HashMap::new(),
length: PathLength::Fixed(1),
}],
};

Variable Length: (a)-[*1..5]->(b)

Match paths of varying lengths.

Example 16: Friends Within 3 Hops

// Pattern: (alice)-[FRIEND_OF*1..3]->(friend)
let pattern = Pattern {
nodes: vec![
NodePattern {
variable: "alice".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::from([
("name".to_string(), json!("Alice")),
]),
},
NodePattern {
variable: "friend".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
},
],
relationships: vec![RelationshipPattern {
variable: None,
types: vec!["FRIEND_OF".to_string()],
direction: Direction::Outgoing,
properties: HashMap::new(),
length: PathLength::Range(1, 3), // 1 to 3 hops
}],
};
// Alternative: Use BFS for better performance
let options = BfsOptions {
max_depth: 3,
max_nodes: 10000,
enable_early_termination: false,
target: None,
};
let result = bfs(&storage, alice_id, options).await?;

Example 17: Unlimited Path Length

// Pattern: (start)-[CONNECTED_TO*]->(end)
let pattern = Pattern {
nodes: vec![
NodePattern {
variable: "start".to_string(),
labels: vec!["Node".to_string()],
properties: HashMap::new(),
},
NodePattern {
variable: "end".to_string(),
labels: vec!["Node".to_string()],
properties: HashMap::new(),
},
],
relationships: vec![RelationshipPattern {
variable: None,
types: vec!["CONNECTED_TO".to_string()],
direction: Direction::Outgoing,
properties: HashMap::new(),
length: PathLength::Unbounded, // Any length
}],
};

Shortest Path: shortestPath((a)-[*]->(b))

Find the shortest path between two nodes.

Example 18: Shortest Path Between Two People

use heliosdb_graph::traversal::dijkstra;
// Find shortest path from Alice to Charlie
let result = dijkstra(&storage, alice_id, charlie_id).await?;
if let Some(path) = result {
println!("Shortest path found:");
println!(" Length: {} hops", path.path.len() - 1);
println!(" Cost: {}", path.cost);
println!(" Path: {:?}", path.path);
} else {
println!("No path found");
}

Example 19: Weighted Shortest Path

// When edges have weights representing distance, cost, etc.
// Dijkstra automatically uses edge weights
let result = dijkstra(&storage, source_id, target_id).await?;
if let Some(path) = result {
println!("Cheapest path:");
println!(" Total cost: {}", path.cost);
for (i, node_id) in path.path.iter().enumerate() {
if let Some(node) = storage.get_vertex(*node_id).await? {
println!(" Step {}: {}", i + 1, node.properties.get("name").unwrap());
}
}
}

Multiple Patterns

Combine multiple patterns in one query.

Example 20: Complex Pattern

// Find people who bought the same product
// Pattern: (p1)-[:PURCHASED]->(product)<-[:PURCHASED]-(p2)
let query = CypherQuery {
match_clause: Some(MatchClause {
patterns: vec![Pattern {
nodes: vec![
NodePattern {
variable: "p1".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
},
NodePattern {
variable: "product".to_string(),
labels: vec!["Product".to_string()],
properties: HashMap::new(),
},
NodePattern {
variable: "p2".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
},
],
relationships: vec![
RelationshipPattern {
variable: None,
types: vec!["PURCHASED".to_string()],
direction: Direction::Outgoing,
properties: HashMap::new(),
length: PathLength::Fixed(1),
},
RelationshipPattern {
variable: None,
types: vec!["PURCHASED".to_string()],
direction: Direction::Incoming,
properties: HashMap::new(),
length: PathLength::Fixed(1),
},
],
}],
}),
where_clause: Some(WhereClause {
condition: Condition::Comparison {
left: Expression::Property {
variable: "p1".to_string(),
property: "id".to_string(),
},
op: ComparisonOp::Ne,
right: Expression::Property {
variable: "p2".to_string(),
property: "id".to_string(),
},
},
}),
return_clause: ReturnClause {
items: vec![
ReturnItem {
expression: Expression::Property {
variable: "p1".to_string(),
property: "name".to_string(),
},
alias: Some("person1".to_string()),
},
ReturnItem {
expression: Expression::Property {
variable: "p2".to_string(),
property: "name".to_string(),
},
alias: Some("person2".to_string()),
},
ReturnItem {
expression: Expression::Property {
variable: "product".to_string(),
property: "name".to_string(),
},
alias: Some("product".to_string()),
},
],
distinct: true,
},
order_by: None,
limit: None,
skip: None,
};

Optional Matches

Handle cases where relationships might not exist (planned feature).



Version: 6.5 Last Updated: November 17, 2025