Filter Step
The filter
step narrows a traversal by keeping only vertices or edges that match a specified predicate.
In this diagram:
- An Input Stream contains elements A (age=35), B (age=25), and C (age=40).
- The
.filter(|v| v.age > 30)
step processes each element, applying the predicate. - Elements A and C satisfy the predicate (age > 30) and pass through to the Output Stream.
- Element B does not satisfy the predicate and is Discarded, marked with an 'X'.
Syntax
walker.filter(|element, context| /* predicate logic */)
Parameters
predicate
: A function that takes a reference to a graph element and optional context, and returns a boolean.- Returns
true
to keep the element in the traversal - Returns
false
to remove it from the traversal
- Returns
Return Value
Returns a new walker containing only the elements that match the predicate.
Examples
Basic Filter
Filter vertices based on a simple condition:
// Basic filter using a closure
let adult_people = graph
.walk()
.vertices(Vertex::person())
.filter_by_person(|person, _| person.age() >= 18)
.collect::<Vec<_>>();
println!("Found {} adults", adult_people.len());
Type-Specific Filtering
Use the type-specific filter methods generated by derive macros:
// Use the type-specific filter methods generated by the VertexExt derive macro
let people_named_b = graph
.walk()
.vertices(Vertex::person())
.filter_by_person(|person, _| {
// This closure gets a strongly-typed view of the Person data
person.name().starts_with('B')
})
.collect::<Vec<_>>();
println!(
"Found {} people whose names start with B",
people_named_b.len()
);
Chained Filters
Combine multiple filters for complex queries:
// Chain multiple filters for complex conditions
let specific_people = graph
.walk()
.vertices(Vertex::person())
// First filter: age range
.filter_by_person(|person, _| person.age() > 25 && person.age() < 40)
// Second filter: name contains 'y'
.filter_by_person(|person, _| person.name().contains('y'))
.collect::<Vec<_>>();
println!(
"Found {} people aged 26-39 with 'y' in their name",
specific_people.len()
);
Filter with Context
Filter based on context information:
// Use filter with context
let result = graph
.walk()
.vertices(Vertex::person())
.push_context(|v, _| {
// Store original vertex in context
if let Some(person) = v.project::<Person<_>>() {
person.name().to_string()
} else {
String::new()
}
})
.filter(|_, ctx| {
// Filter based on context
ctx.len() > 3
})
.collect::<Vec<_>>();
println!(
"Found {} people with names longer than 3 characters",
result.len()
);
Best Practices
- Prefer indexed searches over filter steps when querying by property values
- Break complex filtering logic into multiple chained filters for readability
- Use pattern matching to handle different vertex or edge types correctly
- Leverage generated filter methods from derive macros for stronger type safety
Common Use Cases
- Post-retrieval refinement: Filtering elements after initial selection when indexes don't fully cover criteria
- Dynamic filtering: Applying runtime conditions that can't be encoded in initial searches
- Complex conditions: Implementing filtering logic that combines multiple properties or calculations
- Context-aware filtering: Using information from previous traversal steps to inform filtering decisions