Native Gremlin step support in Amazon Neptune
The Amazon Neptune engine does not currently have full native support for all Gremlin steps, as explained in Tuning Gremlin queries. Current support falls into four categories:
Gremlin steps that can always be converted to native Neptune engine operations
Many Gremlin steps can be converted to native Neptune engine operations as long as they meet the following conditions:
They are not preceded in the query by a step that cannot be converted.
Their parent step, if any, can be converted,
All their child traversals, if any, can be converted.
The following Gremlin steps are always converted to native Neptune engine operations if they meet those conditions:
Gremlin steps that can be converted to native Neptune engine operations in some cases
Some Gremlin steps can be converted to native Neptune engine operations in some situations but not in others:
addE( )
– The addE()
step can generally be converted to a native Neptune engine operation, unless it is immediately followed by aproperty()
step containing a traversal as a key.addV( )
– The addV()
step can generally be converted to a native Neptune engine operation, unless it is immediately followed by aproperty()
step containing a traversal as a key, or unless multiple labels are assigned.-
aggregate( )
– The aggregate()
step can generally be converted to a native Neptune engine operation, unless the step is used in a child traversal or sub-traversal, or unless the value being stored is something other than a vertex, edge, id, label or property value.In example below,
aggregate()
is not converted because it is being used in a child traversal:g.V().has('code','ANC').as('a') .project('flights').by(select('a') .outE().aggregate('x'))
In this example, aggregate() is not converted because what is stored is the
min()
of a value:g.V().has('code','ANC').outE().aggregate('x').by(values('dist').min())
barrier( )
– The barrier()
step can generally be converted to a native Neptune engine operation, unless the step following it is not converted.-
cap( )
– The only case in which the cap()
step is converted is when it is combined with theunfold()
step to return an unfolded version of an aggregate of vertex, edge, id, or poperty values. In this example,cap()
will be converted because it is followed by.unfold()
:g.V().has('airport','country','IE').aggregate('airport').limit(2) .cap('airport').unfold()
However, if you remove the
.unfold()
,cap()
will not be converted:g.V().has('airport','country','IE').aggregate('airport').limit(2) .cap('airport')
coalesce( )
– The only case where the coalesce()
step is converted is when it follows the Upsert patternrecommended on the TinkerPop recipes page . Other coalesce() patterns are not allowed. Conversion is limited to the case where all child traversals can be converted, they all produce the same type as output (vertex, edge, id, value, key, or label), they all traverse to a new element, and they do not contain the repeat()
step.-
constant( )
– The constant() step is currently only converted if it is used within a sack().by()
part of a traversal to assign a constant value, like this:g.V().has('code','ANC').sack(assign).by(constant(10)).out().limit(2)
-
cyclicPath( )
– The cyclicPath()
step can generally be converted to a native Neptune engine operation, unless the step is used withby()
,from()
, orto()
modulators. In the following queries, for example,cyclicPath()
is not converted:g.V().has('code','ANC').as('a').out().out().cyclicPath().by('code') g.V().has('code','ANC').as('a').out().out().cyclicPath().from('a') g.V().has('code','ANC').as('a').out().out().cyclicPath().to('a')
drop( )
– The drop()
step can generally be converted to a native Neptune engine operation, unless the step is used inside asideEffect(
) oroptional()
step.-
fold( )
– There are only two situations where the fold() step can be converted, namely when it is used in the Upsert pattern recommended on the TinkerPop recipes page , and when it is used in a group().by()
context like this:g.V().has('code','ANC').out().group().by().by(values('code', 'city').fold())
-
id( )
– The id()
step is converted unless it is used on a property, like this:g.V().has('code','ANC').properties('code').id()
-
mergeE()
– The mergeE()
step can be converted to a native Neptune engine operation if the parameters (the merge condition, theonCreate
andonMatch
) are constant (eithernull
, a constantMap
, orselect()
of aMap
). All examples in upserting edges can be converted. -
mergeV()
– The mergeV() step can be converted to a native Neptune engine operation if the parameters (the merge condition, the onCreate
andonMatch
) are constant (eithernull
, a constantMap
, orselect()
of aMap
). All examples in upserting vertices can be converted. -
order( )
– The order()
step can generally be converted to a native Neptune engine operation, unless one of the following is true:-
The
order()
step is within a nested child traversal, like this:g.V().has('code','ANC').where(V().out().order().by(id))
Local ordering is being used, as for example with
order(local)
.-
A custom comparator is being used in the
by()
modulation to order by. An example is this use ofsack()
:g.withSack(0). V().has('code','ANC'). repeat(outE().sack(sum).by('dist').inV()).times(2).limit(10). order().by(sack())
There are multiple orderings on the same element.
-
-
project( )
– The project()
step can generally be converted to a native Neptune engine operation, unless the number ofby()
statements following theproject()
does not match the number of labels specified, as here:g.V().has('code','ANC').project('x', 'y').by(id)
range( )
– The range()
step is only converted when the lower end of the range in question is zero (for example,range(0,3)
).-
repeat( )
– The repeat()
step can generally be converted to a native Neptune engine operation, unless it is nested within anotherrepeat()
step, like this:g.V().has('code','ANC').repeat(out().repeat(out()).times(2)).times(2)
-
sack( )
– The sack()
step can generally be converted to a native Neptune engine operation, except in the following cases:If a non-numeric sack operator is being used.
If a numeric sack operator other than
+
,-
,mult
,div
,min
andmax
is being used.-
If
sack()
is used inside awhere()
step to filter based on a sack value, as here:g.V().has('code','ANC').sack(assign).by(values('code')).where(sack().is('ANC'))
-
sum( )
– The sum()
step can generally be converted to a native Neptune engine operation, but not when used to calculate a global summation, like this:g.V().has('code','ANC').outE('routes').values('dist').sum()
union( )
– The union()
step can be converted to a native Neptune engine operation as long as it is the last step in the query aside from the terminal step.-
unfold( )
– The unfold()
step can only be converted to a native Neptune engine operation when it is used in the Upsert patternrecommended on the TinkerPop recipes page , and when it is used together with cap()
like this:g.V().has('airport','country','IE').aggregate('airport').limit(2) .cap('airport').unfold()
-
where( )
– The where()
step can generally be converted to a native Neptune engine operation, except in the following cases:-
When by() modulations are used, like this:
g.V().hasLabel('airport').as('a') .where(gt('a')).by('runways')
When comparison operators other than
eq
,neq
,within
, andwithout
are used.When user-supplied aggregations are used.
-
Gremlin steps that are never converted to native Neptune engine operations
The following Gremlin steps are supported in Neptune but are never converted to native Neptune engine operations. Instead, they are executed by the Gremlin server.
Gremlin steps that are not supported in Neptune at all
The following Gremlin steps are not supported at all in Neptune. In most cases
this is because they require a GraphComputer
, which Neptune does not
currently support.
The io()
step is actually partially supported, in that it can be
used to read()
from a URL but not to write()
.