Combining Graph Traversals
Finding the start vertex via a geo query
Our first example will locate the start vertex for a graph traversal via a geo index.
We use the city graph and its geo indices:
arangosh> var examples = require("@arangodb/graph-examples/example-graph.js");
arangosh> var g = examples.loadGraph("routeplanner");
We search all german cities in a range of 400 km around the ex-capital Bonn: Hamburg and Cologne.
We won’t find Paris since its in the frenchCity
collection.
FOR startCity IN germanCity
FILTER GEO_DISTANCE(@bonn, startCity.geometry) < @radius
RETURN startCity._key
Bind Parameters:
{
"bonn": [
7.0998,
50.734
],
"radius": 400000
}
Result:
[
"Cologne",
"Hamburg"
]
Lets revalidate that the geo indices are actually used:
FOR startCity IN germanCity
FILTER GEO_DISTANCE(@bonn, startCity.geometry) < @radius
RETURN startCity._key
Bind Parameters:
{
"bonn": [
7.0998,
50.734
],
"radius": 400000
}
Explain:
Query String (119 chars, cacheable: true):
FOR startCity IN germanCity
FILTER GEO_DISTANCE(@bonn, startCity.geometry) < @radius
RETURN startCity._key
Execution plan:
Id NodeType Est. Comment
1 SingletonNode 1 * ROOT
7 IndexNode 3 - FOR startCity IN germanCity /* geo index scan, projections: `_key` */
5 CalculationNode 3 - LET #3 = startCity.`_key` /* attribute expression */ /* collections used: startCity : germanCity */
6 ReturnNode 3 - RETURN #3
Indexes used:
By Name Type Collection Unique Sparse Selectivity Fields Ranges
7 idx_1733157426082873345 geo germanCity false true n/a [ `geometry` ] (GEO_DISTANCE([ 7.0998, 50.734 ], startCity.`geometry`) < 400000)
Optimization rules applied:
Id RuleName
1 move-calculations-up
2 move-filters-up
3 move-calculations-up-2
4 move-filters-up-2
5 geo-index-optimizer
6 remove-unnecessary-calculations-2
7 reduce-extraction-to-projection
Optimization rules with highest execution times:
RuleName Duration [s]
geo-index-optimizer 0.00001
remove-redundant-calculations 0.00000
move-calculations-up 0.00000
reduce-extraction-to-projection 0.00000
remove-unnecessary-calculations-2 0.00000
41 rule(s) executed, 1 plan(s) created
And now combine this with a graph traversal:
FOR startCity IN germanCity
FILTER GEO_DISTANCE(@bonn, startCity.geometry) < @radius
FOR v, e, p IN 1..1 OUTBOUND startCity
GRAPH 'routeplanner'
RETURN {startcity: startCity._key, traversedCity: v._key}
Bind Parameters:
{
"bonn": [
7.0998,
50.734
],
"radius": 400000
}
Result:
[
{
"startcity": "Cologne",
"traversedCity": "Lyon"
},
{
"startcity": "Cologne",
"traversedCity": "Paris"
},
{
"startcity": "Hamburg",
"traversedCity": "Cologne"
},
{
"startcity": "Hamburg",
"traversedCity": "Paris"
},
{
"startcity": "Hamburg",
"traversedCity": "Lyon"
}
]
The geo index query returns us startCity
(Cologne and Hamburg) which we then use as starting point for our graph traversal.
For simplicity we only return their direct neighbours. We format the return result so we can see from which startCity
the traversal came.
Alternatively we could use a LET
statement with a subquery to group the traversals by their startCity
efficiently:
FOR startCity IN germanCity
FILTER GEO_DISTANCE(@bonn, startCity.geometry) < @radius
LET oneCity = (
FOR v, e, p IN 1..1 OUTBOUND startCity
GRAPH 'routeplanner' RETURN v._key
)
RETURN {startCity: startCity._key, connectedCities: oneCity}
Bind Parameters:
{
"bonn": [
7.0998,
50.734
],
"radius": 400000
}
Result:
[
{
"startCity": "Cologne",
"connectedCities": [
"Lyon",
"Paris"
]
},
{
"startCity": "Hamburg",
"connectedCities": [
"Cologne",
"Paris",
"Lyon"
]
}
]
Finally, we clean up again:
arangosh> examples.dropGraph("routeplanner");