Native Gremlin step support in Amazon Neptune - Amazon Neptune
Services or capabilities described in Amazon Web Services documentation might vary by Region. To see the differences applicable to the China Regions, see Getting Started with Amazon Web Services in China (PDF).

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 a property() 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 a property() 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 the unfold() 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 pattern recommended 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 with by(), from(), or to() 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 a sideEffect() or optional() 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()
  • 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 of sack():

      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 of by() statements following the project() 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 another repeat() 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 and max is being used.

    • If sack() is used inside a where() 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 pattern recommended 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, and without 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().