added discussion of vendor optimization strategy to docs.

////
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
////
[[traversal]]
The Traversal
=============

image::gremlin-running.png[width=125]

At the most general level there is `Traversal<S,E>` which implements `Iterator<E>`, where the `S` stands for start and the `E` stands for end. A traversal is composed of four primary components:

 . `Step<S,E>`: an individual function applied to `S` to yield `E`. Steps are chained within a traversal.
 . `TraversalStrategy`: interceptor methods to alter the execution of the traversal (e.g. query re-writing).
 . `TraversalSideEffects`: key/value pairs that can be used to store global information about the traversal.
 . `Traverser<T>`: the object propagating through the `Traversal` currently representing an object of type `T`.

The classic notion of a graph traversal is provided by `GraphTraversal<S,E>` which extends `Traversal<S,E>`. GraphTraversal provides an interpretation of the graph data in terms of vertices, edges, etc. and thus, a graph traversal link:http://en.wikipedia.org/wiki/Domain-specific_language[DSL].

IMPORTANT: The underlying `Step` implementations provided by TinkerPop should encompass most of the functionality required by a DSL author. It is important that DSL authors leverage the provided steps as then the common optimization and decoration strategies can reason on the underlying traversal sequence. If new steps are introduced, then common traversal strategies may not function properly.

[[graph-traversal-steps]]
Graph Traversal Steps
---------------------

image::step-types.png[width=650]

A `GraphTraversal<S,E>` can be spawned off of a Graph, Vertex, Edge, or VertexProperty. It can also be spawned anonymously (i.e. empty) via `__`. A graph traversal is composed of an ordered list of steps. All the steps provided by `GraphTraversal` inherit from the more general forms diagrammed above. A list of all the steps (and their descriptions) are provided in the TinkerPop3 link:http://www.tinkerpop.com/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/graph/GraphTraversal.html[GraphTraversal JavaDoc]. The following subsections will demonstrate the GraphTraversal steps using the <<gremlin-console,Gremlin Console>>.

NOTE: To reduce the verbosity of the expression, it is good to `import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*`. This way, instead of doing `__.inE()` for an anonymous traversal, it is possible to simply write `inE()`.

[[lambda-steps]]
Lambda Steps
~~~~~~~~~~~~

CAUTION: Lambda steps are presented for educational purposes as they represent the foundational constructs of the Gremlin language. In practice, lambda steps should be avoided and traversal verification strategies exist to disallow their use unless explicitly "turned off." For more information on the problems with lambdas, please read <<a-note-on-lambdas,A Note on Lambdas>>.

There are four generic steps by which all other specific steps described later extend.

[width="100%",cols="10,12",options="header"]
|=========================================================
| Step| Description
| `map(Function<Traverser<S>, E>)` | map the traverser to some object of type `E` for the next step to process.
| `flatMap(Function<Traverser<S>, Iterator<E>>)` | map the traverser to an iterator of `E` objects that are streamed to the next step.
| `filter(Predicate<Traverser<S>>)` | map the traverser to either true or false, where false will not pass the traverser to the next step.
| `sideEffect(Consumer<Traverser<S>>)` | perform some operation on the traverser and pass it to the next step.
| `branch(Function<Traverser<S>,M>)` | split the traverser to all the traversals indexed by the `M` token.
|=========================================================

The `Traverser<S>` object provides access to:

 . The current traversed `S` object -- `Traverser.get()`.
 . The current path traversed by the traverser -- `Traverser.path()`.
  .. A helper shorthand to get a particular path-history object -- `Traverser.path(String) == Traverser.path().get(String)`.
 . The number of times the traverser has gone through the current loop -- `Traverser.loops()`.
 . The number of objects represented by this traverser -- `Traverser.bulk()`.
 . The local data structure associated with this traverser -- `Traverser.sack()`.
 . The side-effects associated with the traversal -- `Traverser.sideEffects()`.
  .. A helper shorthand to get a particular side-effect -- `Traverser.sideEffect(String) == Traverser.sideEffects().get(String)`.

image:map-lambda.png[width=150,float=right]
[gremlin-groovy,modern]
----
g.V(1).out().values('name') <1>
g.V(1).out().map {it.get().value('name')} <2>
----

<1> An outgoing traversal from vertex 1 to the name values of the adjacent vertices.
<2> The same operation, but using a lambda to access the name property values.

image:filter-lambda.png[width=160,float=right]
[gremlin-groovy,modern]
----
g.V().filter {it.get().label() == 'person'} <1>
g.V().hasLabel('person') <2>
----

<1> A filter that only allows the vertex to pass if it has an age-property.
<2> The more specific `has()`-step is implemented as a `filter()` with respective predicate.

image:side-effect-lambda.png[width=175,float=right]
[gremlin-groovy,modern]
----
g.V().hasLabel('person').sideEffect(System.out.&println) <1>
----

<1> Whatever enters `sideEffect()` is passed to the next step, but some intervening process can occur.

image:branch-lambda.png[width=180,float=right]
[gremlin-groovy,modern]
----
g.V().branch(values('name')).
      option('marko', values('age')).
      option(none, values('name')) <1>
g.V().choose(has('name','marko'),
             values('age'),
             values('name')) <2>
----

<1> If the vertex is "marko", get his age, else get the name of the vertex.
<2> The more specific boolean-based `choose()`-step is implemented as a `branch()`.

[[addedge-step]]
AddEdge Step
~~~~~~~~~~~~

It is possible to mutate the graph within a traversal. The typical mutations are adding/removing vertices, edges, and properties. To add edges, there are a collection of `addE()`-steps (*map*/*sideEffect*).

[gremlin-groovy,modern]
----
g.V(1).addOutE('co-worker',g.V(2),'year',2009) <1>
g.V(4).addInE('createdBy',g.V(3,5)) <2>
g.V(1).addOutE('livesNear',g.V(2),'year',2009).inV().inE('livesNear').values('year') <3>
g.V(1).out('livesNear')
----

<1> Add an outgoing co-worker edge from the marko-vertex to the vadas-vertex with a year property of value 2009.
<2> Add incoming createdBy edges from the josh-vertex to the lop- and ripple-vertices.
<3> The newly created edge is a traversable object.

image::addedge-step.png[width=450]

link:http://en.wikipedia.org/wiki/Automated_reasoning[Reasoning] is the process of making explicit in the data was is implicit in the data. What is explicit in a graph are the objects of the graph -- i.e. vertices and edges. What is implicit in the graph is the traversal. In other words, traversals expose meaning where the meaning is defined by the traversal description. For example, take the concept of a "co-developer." Two people are co-developers if they have worked on the same project together. This concept can be represented as a traversal and thus, the concept of "co-developers" can be derived.

[gremlin-groovy,modern]
----
g.V(1).as('a').out('created')
g.V(1).as('a').out('created').in('created')
g.V(1).as('a').out('created').in('created').where(neq('a')) <1>
g.V(1).as('a').out('created').in('created').where(neq('a')).
   addOutE('co-developer','a').outV().
   addInE('co-developer','a')
g.V(1).out('co-developer').values('name')
g.V(1).in('co-developer').values('name')
----

<1> Marko can't be a co-developer with himself.

[[addvertex-step]]
AddVertex Step
~~~~~~~~~~~~~~

The `addV()`-step is used to add vertices to the graph (*map*/*sideEffect*). For every incoming object, a vertex is created. Moreover, `GraphTraversalSource` maintains an `addV()` method.

[gremlin-groovy,modern]
----
g.addV(label,'person','name','stephen')
g.V().values('name')
g.V().outE('knows').addV('name','nothing')
g.V().has('name','nothing')
g.V().has('name','nothing').bothE()
----

[[addproperty-step]]
AddProperty Step
~~~~~~~~~~~~~~~~

The `property()`-step is used to add properties to the elements of the graph (*sideEffect*). Unlike `addV()` and `addE()`, `property()` is a full sideEffect step in that it does not return the property it created, but the element that streamed into it.

[gremlin-groovy,modern]
----
g.V(1).property('country','usa')
g.V(1).property('city','santa fe').property('state','new mexico').valueMap()
g.V(1).property(list,'age',35)
g.V(1).valueMap()
----

[[aggregate-step]]
Aggregate Step
~~~~~~~~~~~~~~

image::aggregate-step.png[width=800]

The `aggregate()`-step (*sideEffect*) is used to aggregate all the objects at a particular point of traversal into a Collection. The step uses link:http://en.wikipedia.org/wiki/Eager_evaluation[eager evaluation] in that no objects continue on until all previous objects have been fully aggregated (as opposed to <<store-step,`store()`>> which link:http://en.wikipedia.org/wiki/Lazy_evaluation[lazily] fills a collection). The eager evaluation nature is crucial in situations where everything at a particular point is required for future computation. An example is provided below.

[gremlin-groovy,modern]
----
g.V(1).out('created') <1>
g.V(1).out('created').aggregate('x') <2>
g.V(1).out('created').aggregate('x').in('created') <3>
g.V(1).out('created').aggregate('x').in('created').out('created') <4>
g.V(1).out('created').aggregate('x').in('created').out('created').
       where(without('x')).values('name') <5>
----

<1> What has marko created?
<2> Aggregate all his creations.
<3> Who are marko's collaborators?
<4> What have marko's collaborators created?
<5> What have marko's collaborators created that he hasn't created?

In link:http://en.wikipedia.org/wiki/Recommender_system[recommendation systems], the above pattern is used:

	"What has userA liked? Who else has liked those things? What have they liked that userA hasn't already liked?"

Finally, `aggregate()`-step can be modulated via `by()`-projection.

[gremlin-groovy,modern]
----
g.V().out('knows').aggregate()
g.V().out('knows').aggregate().by('name')
----

[[and-step]]
And Step
~~~~~~~~

The `and()`-step ensures that all provided traversals yield a result (*filter*). Please see <<or-step,`or()`>> for or-semantics.

[gremlin-groovy,modern]
----
g.V().and(
   outE('knows'),
   values('age').is(lt(30))).
     values('name')
----

The `and()`-step can take an arbitrary number of traversals. All traversals must produce at least one output for the original traverser to pass to the next step.

An link:http://en.wikipedia.org/wiki/Infix_notation[infix notation] can be used as well. Though, with infix notation, only two traversals can be and'd together.

[gremlin-groovy,modern]
----
g.V().has(outE('created').and().outE('knows')).values('name')
----

[[as-step]]
As Step
~~~~~~~

The `as()`-step is not a real step, but a "step modulator" similar to <<by-step,`by()`>> and <<option-step,`option()`>>. With `as()`, it is possible to provide a label to the step that can later be accessed by steps and data structures that make use of such labels -- e.g., <<select-step,`select()`>>, <<match-step,`match()`>>, and path.

[gremlin-groovy,modern]
----
g.V().as('a').out('created').as('b').select()            <1>
g.V().as('a').out('created').as('b').select().by('name') <2>
----

<1> Select the objects labeled "a" and "b" from the path.
<2> Select the objects labeled "a" and "b" from the path and, for each object, project its name value.

A step can have any number of labels associated with it. This is useful for referencing the same step multiple times in a future step.

[gremlin-groovy,modern]
----
g.V().hasLabel('software').as('a','b','c').
   select().
     by('name').
     by('lang').
     by(__.in('created').values('name').fold())
----

[[by-step]]
By Step
~~~~~~~

The `by()`-step is not an actual step, but instead is a "step-modulator" similar to <<as-step,`as()`>> and <<option-step,`option()`>>. If a step is able to accept traversals, functions, comparators, etc. then `by()` is the means by which they are added. The general pattern is `step().by()...by()`. Some steps can only accept one `by()` while others can take an arbitrary amount.

[gremlin-groovy,modern]
----
g.V().group().by(bothE().count())                                  <1>
g.V().group().by(bothE().count()).by('name')                       <2>
g.V().group().by(bothE().count()).by('name').by(count(local))  <3>
----

<1> `by(outE().count())` will group the elements by their edge count (*traversal*).
<2> `by('name')` will process the grouped elements by their name (*element property projection*).
<3> `by(count(local))` will count the number of elements in each group (*traversal*).

[[coalesce-step]]
Coalesce Step
~~~~~~~~~~~~~

The `coalesce()`-step evaluates the provided traversals in order and returns the first traversal that emits at least one element.

[gremlin-groovy,modern]
----
g.V(1).coalesce(outE('knows'), outE('created')).inV().path().by('name').by(label)
g.V(1).coalesce(outE('created'), outE('knows')).inV().path().by('name').by(label)
g.V(1).next().property('nickname', 'okram')
g.V().hasLabel('person').coalesce(values('nickname'), values('name'))
----

[[count-step]]
Count Step
~~~~~~~~~~

image::count-step.png[width=195]

The `count()`-step (*map*) counts the total number of represented traversers in the streams (i.e. the bulk count).

[gremlin-groovy,modern]
----
g.V().count()
g.V().hasLabel('person').count()
g.V().hasLabel('person').outE('created').count().path()  <1>
g.V().hasLabel('person').outE('created').count().map {it.get() * 10}.path() <2>
----

<1> `count()`-step is a <<a-note-on-barrier-steps,reducing barrier step>> meaning that all of the previous traversers are folded into a new traverser.
<2> The path of the traverser emanating from `count()` starts at `count()`.

IMPORTANT: `count(local)` counts the current, local object (not the objects in the traversal stream). This works for `Collection`- and `Map`-type objects. For any other object, a count of 1 is returned.

[[choose-step]]
Choose Step
~~~~~~~~~~~

image::choose-step.png[width=700]

The `choose()`-step (*branch*) routes the current traverser to a particular traversal branch option. With `choose()`, it is possible to implement if/else-based semantics as well as more complicated selections.

[gremlin-groovy,modern]
----
g.V().hasLabel('person').
      choose(values('age').is(lte(30)),
        __.in(),
        __.out()).values('name') <1>
g.V().hasLabel('person').
      choose(values('age')).
        option(27, __.in()).
        option(32, __.out()).values('name') <2>
----

<1> If the traversal yields an element, then do `in`, else do `out` (i.e. true/false-based option selection).
<2> Use the result of the traversal as a key to the map of traversal options (i.e. value-based option selection).

However, note that `choose()` can have an arbitrary number of options and moreover, can take an anonymous traversal as its choice function.

[gremlin-groovy,modern]
----
g.V().hasLabel('person').
      choose(values('name')).
        option('marko', values('age')).
        option('josh', values('name')).
        option('vadas', valueMap()).
        option('peter', label())
----

The `choose()`-step can leverage the `Pick.none` option match. For anything that does not match a specified option, the `none`-option is taken.

[gremlin-groovy,modern]
----
g.V().hasLabel('person').
      choose(values('name')).
        option('marko', values('age')).
        option(none, values('name'))
----

[[coin-step]]
Coin Step
~~~~~~~~~

To randomly filter out a traverser, use the `coin()`-step (*filter*). The provided double argument biases the "coin toss."

[gremlin-groovy,modern]
----
g.V().coin(0.5)
g.V().coin(0.0)
g.V().coin(1.0)
----

[[cyclicpath-step]]
CyclicPath Step
~~~~~~~~~~~~~~~

image::cyclicpath-step.png[width=400]

Each traverser maintains its history through the traversal over the graph -- i.e. its <<path-data-structure,path>>. If it is important that the traverser repeat its course, then `cyclic()`-path should be used (*filter*). The step analyzes the path of the traverser thus far and if there are any repeats, the traverser is filtered out over the traversal computation. If non-cyclic behavior is desired, see <<simplepath-step,`simplePath()`>>.

[gremlin-groovy,modern]
----
g.V(1).both().both()
g.V(1).both().both().cyclicPath()
g.V(1).both().both().cyclicPath().path()
----

[[dedup-step]]
Dedup Step
~~~~~~~~~~

With `dedup()`-step (*filter*), repeatedly seen objects are removed from the traversal stream. Note that if a traverser's bulk is greater than 1, then it is set to 1 before being emitted.

[gremlin-groovy,modern]
----
g.V().values('lang')
g.V().values('lang').dedup()
g.V(1).repeat(bothE('created').dedup().otherV()).emit().path() <1>
----

<1> Traverse all `created` edges, but don't touch any edge twice.

If a by-step modulation is provided to `dedup()`, then the object is processed accordingly prior to determining if it has been seen or not.

[gremlin-groovy,modern]
----
g.V().valueMap(true, 'name')
g.V().dedup().by(label).values('name')
----

WARNING: The `dedup()`-step does not have a correlate in <<traversalvertexprogram,Gremlin OLAP>> when used mid-traversal. When in mid-traversal de-duplication only occurs at the the current processing vertex and thus, is not a global operation as it in Gremlin OLTP. When `dedup()` is an end step, the resultant traversers are de-duplicated by `TraverserMapReduce`.

[[drop-step]]
Drop Step
~~~~~~~~~

The `drop()`-step (*filter*/*sideEffect*) is used to remove element and properties from the graph (i.e. remove). It is a filter step because the traversal yields no outgoing objects.

[gremlin-groovy,modern]
----
g.V().outE().drop()
g.E()
g.V().properties('name').drop()
g.V().valueMap()
g.V().drop()
g.V()
----

[[fold-step]]
Fold Step
~~~~~~~~~

There are situations when the traversal stream needs a "barrier" to aggregate all the objects and emit a computation that is a function of the aggregate. The `fold()`-step (*map*) is one particular instance of this. Please see <<unfold-step,`unfold()`>>-step for the inverse functionality.

[gremlin-groovy,modern]
----
g.V(1).out('knows').values('name')
g.V(1).out('knows').values('name').fold() <1>
g.V(1).out('knows').values('name').fold().next().getClass() <2>
g.V(1).out('knows').values('name').fold(0) {a,b -> a + b.length()} <3>
g.V().values('age').fold(0) {a,b -> a + b} <4>
g.V().values('age').fold(0, sum) <5>
g.V().values('age').sum() <6>
----

<1> A parameterless `fold()` will aggregate all the objects into a list and then emit the list.
<2> A verification of the type of list returned.
<3> `fold()` can be provided two arguments --  a seed value and a reduce bi-function ("vadas" is 5 characters + "josh" with 4 characters).
<4> What is the total age of the people in the graph?
<5> The same as before, but using a built-in bi-function.
<6> The same as before, but using the <<sum-step,`sum()`-step>>.

[[group-step]]
Group Step
~~~~~~~~~~

As traversers propagate across a graph as defined by a traversal, sideEffect computations are sometimes required. That is, the actual path taken or the current location of a traverser is not the ultimate output of the computation, but some other representation of the traversal. The `group()`-step (*sideEffect*) is one such sideEffect that organizes the objects according to some function of the object. Then, if required, that organization (a list) is reduced. An example is provided below.

[gremlin-groovy,modern]
----
g.V().group().by(label) <1>
g.V().group().by(label).by('name') <2>
g.V().group().by(label).by('name').by(count(local)) <3>
----

<1> Group the vertices by their label.
<2> For each vertex in the group, get their name.
<3> For each grouping, what is its size?

The three projection parameters available to `group()` via `by()` are:

. Key-projection: What feature of the object to group on (a function that yields the map key)?
. Value-projection: What feature of the group to store in the key-list?
. Reduce-projection: What feature of the key-list to ultimately return?

WARNING: The `group()`-step does not have a correlate in <<traversalvertexprogram,Gremlin OLAP>> when used mid-traversal. When in mid-traversal grouping only occurs at the the current processing vertex and thus, is not a global operation as it in Gremlin OLTP. However, `GroupMapReduce` provides unified groups at the end of the traversal computation.

[[groupcount-step]]
GroupCount Step
~~~~~~~~~~~~~~~

When it is important to know how many times a particular object has been at a particular part of a traversal, `groupCount()`-step (*sideEffect*) is used.

	"What is the distribution of ages in the graph?"

[gremlin-groovy,modern]
----
g.V().hasLabel('person').values('age').groupCount()
g.V().hasLabel('person').groupCount().by('age') <1>
----

<1> You can also supply a pre-group projection, where the provided <<by-step,`by()`>>-modulation determines what to group the incoming object by.

There is one person that is 32, one person that is 35, one person that is 27, and one person that is 29.

	"Iteratively walk the graph and count the number of times you see the second letter of each name."

image::groupcount-step.png[width=420]

[gremlin-groovy,modern]
----
g.V().repeat(both().groupCount('m').by(label)).times(10).cap('m')
----

The above is interesting in that it demonstrates the use of referencing the internal `Map<Object,Long>` of `groupCount()` with a string variable. Given that `groupCount()` is a sideEffect-step, it simply passes the object it received to its output. Internal to `groupCount()`, the object's count is incremented.

WARNING: The `groupCount()`-step does not have a correlate in <<traversalvertexprogram,Gremlin OLAP>> when used mid-traversal. When in mid-traversal grouping only occurs at the the current processing vertex and thus, is not a global operation as it in Gremlin OLTP. However, `GroupCountMapReduce` provides unified groups at the end of the traversal computation.

[[has-step]]
Has Step
~~~~~~~~

image::has-step.png[width=670]

It is possible to filter vertices, edges, and vertex properties based on their properties using `has()`-step (*filter*). There are numerous variations on `has()` including:

  * `has(key,value)`: Remove the traverser if its element does not have the provided key/value property.
  * `has(key,predicate)`: Remove the traverser if its element does not have a key value that satisfies the bi-predicate.
  * `hasLabel(labels...)`: Remove the traverser if its element does not have any of the labels.
  * `hasId(ids...)`: Remove the traverser if its element does not have any of the ids.
  * `hasKey(keys...)`: Remove the traverser if its property does not have any of the keys.
  * `hasValue(values...)`: Remove the traverser if its property does not have any of the values.
  * `has(key)`: Remove the traverser if its element has a value for the key.
  * `hasNot(key)`: Remove the traverser if its element does not have a value for the  key.
  * `has(traversal)`: Remove the traverser if its object does not yield a result through the traversal.

[gremlin-groovy,modern]
----
g.V().hasLabel('person')
g.V().hasLabel('person').out().has('name',within('vadas','josh'))
g.V().hasLabel('person').out().has('name',within('vadas','josh')).
      outE().hasLabel('created')
g.V().has('age',inside(20,30)).values('age') <1>
g.V().has('age',outside(20,30)).values('age') <2>
----

<1> Find all vertices whose ages are between 20 (inclusive) and 30 (exclusive).
<2> Find all vertices whose ages are not between 20 (inclusive) and 30 (exclusive).

It is also possible to filter any arbitrary object based on a anonymous traversal yielding at least one result.

[gremlin-groovy,modern]
----
g.V().has(out('created')).values('name') <1>
g.V().out('knows').has(out('created')).values('name') <2>
g.V().has(out('created').count().is(gte(2L))).values('name') <3>
g.V().has(out('knows').has(out('created'))).values('name') <4>
----

<1> What are the names of the people who have created a project?
<2> What are the names of the people that are known by someone one and have created a project?
<3> What are the names of the people how have created two or more projects?
<4> What are the names of the people who know someone that has created a project? (This only works in OLTP -- see the `WARNING` below)

WARNING: The anonymous traversal of `has()` processes the current object "locally". In OLAP, where the atomic unit of computing is the the vertex and its local "star graph," it is important that the anonymous traversal does not leave the confines of the vertex's star graph. In other words, it can not traverse to an adjacent vertex's properties or edges.

[[inject-step]]
Inject Step
~~~~~~~~~~~

image::inject-step.png[width=800]

One of the major features of TinkerPop3 is "injectable steps." This makes it possible to insert objects arbitrarily into a traversal stream. In general, `inject()`-step (*sideEffect*) exists and a few examples are provided below.

[gremlin-groovy,modern]
----
g.V(4).out().values('name').inject('daniel')
g.V(4).out().values('name').inject('daniel').map {it.get().length()}
g.V(4).out().values('name').inject('daniel').map {it.get().length()}.path()
----

In the last example above, note that the path starting with `daniel` is only of length 2. This is because the `daniel` string was inserted half-way in the traversal. Finally, a typical use case is provided below -- when the start of the traversal is not a graph object.

[gremlin-groovy,modern]
----
inject(1,2)
inject(1,2).map {it.get() + 1}
inject(1,2).map {it.get() + 1}.map {g.V(it.get()).next()}.values('name')
----

[[is-step]]
Is Step
~~~~~~~

It is possible to filter scalar values using `is()`-step (*filter*).

[gremlin-groovy,modern]
----
g.V().values('age').is(32)
g.V().values('age').is(lte(30))
g.V().values('age').is(inside(30, 40))
g.V().has(__.in('created').count().is(1l)).values('name') <1>
g.V().has(__.in('created').count().is(gte(2l))).values('name') <2>
g.V().has(__.in('created').values('age').
                           mean().is(inside(30d, 35d))).values('name') <3>
----

<1> Find projects having exactly one contributor.
<2> Find projects having two or more contributors.
<3> Find projects whose contributors average age is between 30 and 35.

[[limit-step]]
Limit Step
~~~~~~~~~~

The `limit()`-step is analogous to <<range-step,`range()`-step>> save that the lower end range is set to 0.

[gremlin-groovy,modern]
----
g.V().limit(2)
g.V().range(0, 2)
g.V().limit(2).toString()
----

[[local-step]]
Local Step
~~~~~~~~~~

image::local-step.png[width=450]

A `GraphTraversal` operates on a continuous stream of objects. In many situations, it is important to operate on a single element within that stream. To do such object-local traversal computations, `local()`-step exists (*branch*). Note that the examples below use the <<the-crew-toy-graph,The Crew>> toy data set.

[gremlin-groovy,theCrew]
----
g.V().as('person').
      properties('location').order().by('startTime',incr).limit(2).
      value().as('location').select().by('name').by() <1>
g.V().as('person').
      local(properties('location').order().by('startTime',incr).limit(2)).
      value().as('location').select().by('name').by() <2>
----

<1> Get the first two people and their respective location according to the most historic location start time.
<2> For every person, get their two most historic locations.

The two traversals above look nearly identical save the inclusion of `local()` which wraps a section of the traversal in a object-local traversal. As such, the `order().by()` and the `limit()` refer to a particular object, not to the stream as a whole.

WARNING: The anonymous traversal of `local()` processes the current object "locally." In OLAP, where the atomic unit of computing is the the vertex and its local "star graph," it is important that the anonymous traversal does not leave the confines of the vertex's star graph. In other words, it can not traverse to an adjacent vertex's properties or edges.

[[match-step]]
Match Step
~~~~~~~~~~

The `match()`-step (*map*) is introduced into TinkerPop3 to support a more link:http://en.wikipedia.org/wiki/Declarative_programming[declarative] form of link:http://en.wikipedia.org/wiki/Pattern_matching[pattern matching]. Similar constructs were available in previous TinkerPop versions via the `table()`-step, but that has since been removed in favor of the `match().select()`-pattern. With MatchStep in TinkerPop, a query optimizer similar to the link:http://www.knowledgefrominformation.com/2011/04/16/budget-match-cost-effective-subgraph-matching-on-large-networks/[budget match algorithm] builds and revises query plans on the fly, while a query is in progress. For very large graphs, where the developer is uncertain of the statistics of the graph (e.g. how many `knows`-edges vs. `worksFor`-edges exist in the graph), it is advantageous to use `match()`, as an optimal plan will be determined automatically.  Furthermore, some queries are much easier to express via `match()` than with single-path traversals.

	"Who created a project named 'lop' that was also created by someone who is 29 years old? Return the two creators."

image::match-step.png[width=500]

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('created').as('b'),
        __.as('b').has('name', 'lop'),
        __.as('b').in('created').as('c'),
        __.as('c').has('age', 29)).select('a','c').by('name')
----

Note that the above can also be more concisely written as below which demonstrates that imperative inner-traversals can be arbitrarily defined.

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('created').has('name', 'lop').as('b'),
        __.as('b').in('created').has('age', 29).as('c')).select('a','c').by('name')
----

[[grateful-dead]]
.Grateful Dead
image::grateful-dead-schema.png[width=475]

MatchStep brings functionality similar to link:http://en.wikipedia.org/wiki/SPARQL[SPARQL] to Gremlin. Like SPARQL, MatchStep conjoins a set of patterns applied to a graph.  For example, the following traversal finds exactly those songs which Jerry Garcia has both sung and written (using the Grateful Dead graph distributed in the `data/` directory):

[gremlin-groovy]
----
graph.io(graphml()).readGraph('data/grateful-dead.xml')
g = graph.traversal(standard())
g.V().match('a',
        __.as('a').has('name', 'Garcia'),
        __.as('a').in('writtenBy').as('b'),
        __.as('a').in('sungBy').as('b')).select('b').values('name')
----

Among the features which differentiate `match()` from SPARQL are:

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('created').has('name','lop').as('b'), <1>
        __.as('b').in('created').has('age', 29).as('c'),
        __.as('c').repeat(out()).times(2)). <2>
          select('c').out('knows').dedup().values('name') <3>
----

<1> *Patterns of arbitrary complexity*: `match()` is not restricted to triple patterns or property paths.
<2> *Recursion support*: `match()` supports the branch-based steps within a pattern, including `repeat()`.
<3> *Imperative/declarative hybrid*: Pre and prior to a `match()`, it is possible to leverage classic Gremlin imperative.

To extend point #3, it is possible to support going from imperative, to declarative, to imperative, ad infinitum.

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('knows').as('b'),
        __.as('b').out('created').has('name','lop')).
        select('b').out('created').
          match('a',
            __.as('a').in('created').as('b'),
            __.as('b').out('knows').as('c')).
            select('c').values('name')
----

Like all other steps in Gremlin, `match()` is a function and thus, `match()` within `match()` is a natural consequence of Gremlin's functional foundation (i.e. recursive matching).

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('knows').as('b'),
        __.as('b').out('created').has('name','lop'),
        __.as('b').match('x',
                 __.as('x').out('created').as('y'),
                 __.as('y').has('name','ripple')).
                 select('y').as('c')).
        select('a','c').by('name')
----

WARNING: Currently, `match()` does not operate within a multi-JVM <<graphcomputer,GraphComputer>> OLAP environment. Future work includes a linearization <<traversalstrategy,TraversalStrategy>> for `match()`.

[[using-where-with-match]]
Using Where with Match
^^^^^^^^^^^^^^^^^^^^^^

Match is typically used in conjunction with both `select()` (demonstrated previously) and `where()` (presented here). A `where()` allows the user to further constrain the result set provided by `match()`.

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('created').as('b'),
        __.as('b').in('created').as('c')).
          where('a', neq('c')).select('a','c').by('name')
----

The `where()`-step can take either a `BiPredicate` (first example below) or a `Traversal` (second example below). Using `MatchWhereStrategy`, `where()`-clauses can be automatically folded into `match()` and thus, subject to `match()`-steps budget-match algorithm.

[gremlin-groovy,modern]
----
traversal = g.V().match('a',
                    __.as('a').out('created').as('b'),
                    __.as('b').in('created').as('c')).
                      where(__.as('a').out('knows').as('c')). <1>
                      select('a','c').by('name'); null <2>
traversal.toString() <3>
traversal <4> <5>
traversal.toString() <6>
----

<1> A `where()`-step with a traversal containing variable bindings declared in `match()`.
<2> A useful trick to ensure that that the traversal is not iterated by Gremlin Console.
<3> The string representation of the traversal prior to its strategies being applied.
<4> The Gremlin Console will automatically iterate anything that is an iterator or is iterable.
<5> Both marko and josh are co-developers and marko knows josh.
<6> The string representation of the traversal after the strategies have been applied (and thus, `where()` is folded into `match()`)

[[max-step]]
Max Step
~~~~~~~~

The `max()`-step (*map*) operates on a stream of numbers and determines which is the largest number in the stream.

[gremlin-groovy,modern]
----
g.V().values('age').max()
g.V().repeat(both()).times(3).values('age').max()
----

IMPORTANT: `max(local)` determines the max of the current, local object (not the objects in the traversal stream). This works for `Collection` and `Number`-type objects. For any other object, a max of `Double.NaN` is returned.

[[mean-step]]
Mean Step
~~~~~~~~~

The `mean()`-step (*map*) operates on a stream of numbers and determines the average of those numbers.

[gremlin-groovy,modern]
----
g.V().values('age').mean()
g.V().repeat(both()).times(3).values('age').mean() <1>
g.V().repeat(both()).times(3).values('age').dedup().mean()
----

<1> Realize that traversers are being bulked by `repeat()`. There may be more of a particular number than another, thus altering the average.

IMPORTANT: `mean(local)` determines the mean of the current, local object (not the objects in the traversal stream). This works for `Collection` and `Number`-type objects. For any other object, a mean of `Double.NaN` is returned.

[[min-step]]
Min Step
~~~~~~~~

The `min()`-step (*map*) operates on a stream of numbers and determines which is the smallest number in the stream.

[gremlin-groovy,modern]
----
g.V().values('age').min()
g.V().repeat(both()).times(3).values('age').min()
----

IMPORTANT: `min(local)` determines the min of the current, local object (not the objects in the traversal stream). This works for `Collection` and `Number`-type objects. For any other object, a min of `Double.NaN` is returned.

[[or-step]]
Or Step
~~~~~~~

The `or()`-step ensures that at least one of the provided traversals yield a result (*filter*). Please see <<and-step,`and()`>> for and-semantics.

[gremlin-groovy,modern]
----
g.V().or(
   __.outE('created'),
   __.inE('created').count().is(gt(1l))).
     values('name')
----

The `or()`-step can take an arbitrary number of traversals. At least one of the traversals must produce at least one output for the original traverser to pass to the next step.

An link:http://en.wikipedia.org/wiki/Infix_notation[infix notation] can be used as well. Though, with infix notation, only two traversals can be or'd together.

[gremlin-groovy,modern]
----
g.V().has(outE('created').or().outE('knows')).values('name')
----

[[order-step]]
Order Step
~~~~~~~~~~

When the objects of the traversal stream need to be sorted, `order()`-step (*map*) can be leveraged.

[gremlin-groovy,modern]
----
g.V().values('name').order()
g.V().values('name').order().by(decr)
g.V().hasLabel('person').order().by('age', incr).values('name')
----

One of the most traversed objects in a traversal is an `Element`. An element can have properties associated with it (i.e. key/value pairs). In many situations, it is desirable to sort an element traversal stream according to a comparison of their properties.

[gremlin-groovy,modern]
----
g.V().values('name')
g.V().order().by('name',incr).values('name')
g.V().order().by('name',decr).values('name')
----

The `order()`-step allows the user to provide an arbitrary number of comparators for primary, secondary, etc. sorting. In the example below, the primary ordering is based on the outgoing created-edge count. The secondary ordering is based on the age of the person.

[gremlin-groovy,modern]
----
g.V().hasLabel('person').order().by(outE('created').count(), incr).
                                 by('age', incr).values('name')
g.V().hasLabel('person').order().by(outE('created').count(), incr).
                                 by('age', decr).values('name')
----

Randomizing the order of the traversers at a particular point in the traversal is possible with `Order.shuffle`.

[gremlin-groovy,modern]
----
g.V().hasLabel('person').order().by(shuffle)
g.V().hasLabel('person').order().by(shuffle)
----

IMPORTANT: `order(local)` orders the current, local object (not the objects in the traversal stream). This works for `Collection`- and `Map`-type objects. For any other object, the object is returned unchanged.

[[path-step]]
Path Step
~~~~~~~~~

A traverser is transformed as it moves through a series of steps within a traversal. The history of the traverser is realized by examining its path with `path()`-step (*map*).

image::path-step.png[width=650]

[gremlin-groovy,modern]
----
g.V().out().out().values('name')
g.V().out().out().values('name').path()
----

If edges are required in the path, then be sure to traverser those edges explicitly.

[gremlin-groovy,modern]
----
g.V().outE().inV().outE().inV().path()
----

It is possible to post-process the elements of the path in a round-robin fashion via `by()`.

[gremlin-groovy,modern]
----
g.V().out().out().path().by('name').by('age')
----

Finally, because `by()`-based post-processing, nothing prevents triggering yet another traversal. In the traversal below, for each element of the path traversed thus far, if its a person (as determined by having an `age`-property), then get all of their creations, else if its a creation, get all the people that created it.

[gremlin-groovy,modern]
----
g.V().out().out().path().by(
                   choose(hasLabel('person'),
                                 out('created').values('name'),
                                 __.in('created').values('name')).fold())
----

WARNING: Generating path information is expensive as the history of the traverser is stored into a Java list. With numerous traversers, there are numerous lists. Moreover, in an OLAP <<graphcomputer,`GraphComputer`>> environment this becomes exceedingly prohibitive as there are traversers emanating from all vertices in the graph in parallel. In OLAP there are optimizations provided for traverser populations, but when paths are calculated (and each traverser is unique due to its history), then these optimizations are no longer possible.

[[path-data-structure]]
Path Data Structure
^^^^^^^^^^^^^^^^^^^

The `Path` data structure is an ordered list of objects, where each object is associated to a `Set<String>` of labels. An example is presented below to demonstrate both the `Path` API as well as how a traversal yields labeled paths.

image::path-data-structure.png[width=350]

[gremlin-groovy,modern]
----
path = g.V(1).as('a').has('name').as('b').
              out('knows').out('created').as('c').
              has('name','ripple').values('name').as('d').
              identity().as('e').path().next()
path.size()
path.objects()
path.labels()
path.a
path.b
path.c
path.d == path.e
----

[[profile-step]]
Profile Step
~~~~~~~~~~~~

The `profile()`-step (*sideEffect*) exists to allow developers to profile their traversals to determine statistical information like step runtime, counts, etc.

WARNING: Profiling a Traversal will impede the Traversal's performance. This overhead is mostly excluded from the profile results, but durations are not exact. Thus, durations are best considered in relation to each other.

[gremlin-groovy,modern]
----
g.V().out('created').repeat(both()).times(3).hasLabel('person').values('age').sum().profile().cap(TraversalMetrics.METRICS_KEY)
----

The `profile()`-step generates a `TraversalMetrics` sideEffect object that contains the following information:

* `Step`: A step within the traversal being profiled.
* `Count`: The number of _represented_ traversers that passed through the step.
* `Traversers`: The number of traversers that passed through the step.
* `Time (ms)`: The total time the step was actively executing its behavior.
* `% Dur`: The percentage of total time spent in the step.

image:gremlin-exercise.png[width=120,float=left] It is important to understand the difference between `Count` and `Traversers`. Traversers can be merged and as such, when two traversers are "the same" they may be aggregated into a single traverser. That new traverser has a `Traverser.bulk()` that is the sum of the two merged traverser bulks. On the other hand, the `Count` represents the sum of all `Traverser.bulk()` results and thus, expresses the number of "represented" (not enumerated) traversers. `Traversers` will always be less than or equal to `Count`.

[[range-step]]
Range Step
~~~~~~~~~~

As traversers propagate through the traversal, it is possible to only allow a certain number of them to pass through with `range()`-step (*filter*). When the low-end of the range is not met, objects are continued to be iterated. When within the low and high range (both inclusive), traversers are emitted. Finally, when above the high range, the traversal breaks out of iteration.

[gremlin-groovy,modern]
----
g.V().range(0,3)
g.V().range(1,3)
g.V().repeat(both()).times(1000000).emit().range(6,10)
----

[[repeat-step]]
Repeat Step
~~~~~~~~~~~

image::gremlin-fade.png[width=350]

The `repeat()`-step (*branch*) is used for looping over a traversal given some break predicate. Below are some examples of `repeat()`-step in action.

[gremlin-groovy,modern]
----
g.V(1).repeat(out()).times(2).path().by('name') <1>
g.V().until(has('name','ripple')).
      repeat(out()).path().by('name') <2>
----

<1> do-while semantics stating to do `out()` 2 times.
<2> while-do semantics stating to break if the traverser is at a vertex named "ripple".

IMPORTANT: There are two modulators for `repeat()`: `until()` and `emit()`. If `until()` comes after `repeat()` it is do/while looping. If `until()` comes before `repeat()` it is while/do looping. If `emit()` is placed after `repeat()`, it is evaluated on the traversers leaving the repeat-traversal. If `emit()` is placed before `repeat()`, it is evaluated on the traversers prior to entering the repeat-traversal.

The `repeat()`-step also supports an "emit predicate", where the predicate for an empty argument `emit()` is true (i.e. `emit() == emit{true}`). With `emit()`, the traverser is split in two -- the traverser exits the code block as well as continues back within the code block (assuming `until()` holds true).

[gremlin-groovy,modern]
----
g.V(1).repeat(out()).times(2).emit().path().by('name') <1>
g.V(1).emit().repeat(out()).times(2).path().by('name') <2>
----

<1> The `emit()` comes after `repeat()` and thus, emission happens after the `repeat()` traversal is executed. Thus, no one vertex paths exist.
<2> The `emit()` comes before `repeat()` and thus, emission happens prior to the `repeat()` traversal being executed. Thus, one vertex paths exist.

The `emit()`-modulator can take an arbitrary predicate.

[gremlin-groovy,modern]
----
g.V(1).repeat(out()).times(2).emit(has('lang')).path().by('name')
----

image::repeat-step.png[width=500]

[gremlin-groovy,modern]
----
g.V(1).repeat(out()).times(2).emit().path().by('name')
----

The first time through the `repeat()`, the vertices lop, vadas, and josh are seen. Given that `loops==0`, the traverser repeats. However, because the emit-predicate is declared true, those vertices are emitted. At step 2 (`loops==1`), the vertices traversed are ripple and lop (Josh's created projects, as lop and vadas have no out edges) and are also emitted. Now `loops==1` so the traverser repeats. As ripple and lop have no out edges there are no vertices to traverse. Given that `loops==2`, the until-predicate fails. Therefore, the traverser has seen the vertices: lop, vadas, josh, ripple, and lop.

Finally, note that both `emit()` and `until()` can take a traversal and in such, situations, the predicate is determined by `traversal.hasNext()`. A few examples are provided below.

[gremlin-groovy,modern]
----
g.V(1).repeat(out()).until(hasLabel('software')).path().by('name') <1>
g.V(1).emit(hasLabel('person')).repeat(out()).path().by('name') <2>
g.V(1).repeat(out()).until(outE().count().is(0L)).path().by('name') <3>
----

<1> Starting from vertex 1, keep taking outgoing edges until a software vertex is reached.
<2> Starting from vertex 1, and in an infinite loop, emit the vertex if it is a person and then traverser the outgoing edges.
<3> Starting from vertex 1, keep taking outgoing edges until a vertex is reached that has no more outgoing edges.

WARNING: The anonymous traversal of `emit()` and `until()` (not `repeat()`) process their current objects "locally." In OLAP, where the atomic unit of computing is the the vertex and its local "star graph," it is important that the anonymous traversals do not leave the confines of the vertex's star graph. In other words, they can not traverse to an adjacent vertex's properties or edges.

[[sack-step]]
Sack Step
~~~~~~~~~

image:gremlin-sacks-running.png[width=175,float=right] A traverser can contain a local data structure called a "sack". The `sack()`-step is used to read and write sacks (*sideEffect* or *map*). Each sack of each traverser is created when using `GraphTraversal.withSack(initialValueSupplier,splitOperator?)`.

* *Initial value supplier*: A `Supplier` providing the initial value of each traverser's sack.
* *Split operator*: a `UnaryOperator` that clones the traverser's sack when the traverser splits. If no split operator is provided, then `UnaryOperator.identity()` is assumed.

Two trivial examples are presented below to demonstrate the *initial value supplier*. In the first example below, a traverser is created at each vertex in the graph (`g.V()`), with a 1.0 sack (`withSack(1.0f)`), and then the sack value is accessed (`sack()`). In the second example, a random float supplier is used to generate sack values.

[gremlin-groovy,modern]
----
g.withSack(1.0f).V().sack()
rand = new Random()
g.withSack {rand.nextFloat()}.V().sack()
----

A more complicated initial value supplier example is presented below where the sack values are used in a running computation and then emitted at the end of the traversal. When an edge is traversed, the edge weight is multiplied by the sack value (`sack(mult,'weight')`).

[gremlin-groovy,modern]
----
g.withSack(1.0f).V().repeat(outE().sack(mult,'weight').inV()).times(2)
g.withSack(1.0f).V().repeat(outE().sack(mult,'weight').inV()).times(2).sack()
g.withSack(1.0f).V().repeat(outE().sack(mult,'weight').inV()).times(2).path().
      by().by('weight')
----

image:gremlin-sacks-standing.png[width=100,float=left] When complex objects are used (i.e. non-primitives), then a *split operator* should be defined to ensure that each traverser gets a clone of its parent's sack. The first example does not use a split operator and as such, the same map is propagated to all traversers (a global data structure). The second example, demonstrates how `Map.clone()` ensures that each traverser's sack contains a unique, local sack.

[gremlin-groovy,modern]
----
g.withSack {[:]}.V().out().out().
      sack {m,v -> m[v.value('name')] = v.value('lang'); m}.sack() // BAD: single map
g.withSack {[:]}{it.clone()}.V().out().out().
      sack {m,v -> m[v.value('name')] = v.value('lang'); m}.sack() // GOOD: cloned map
----

NOTE: For primitives (i.e. integers, longs, floats, etc.), a split operator is not required as a primitives are encoded in the memory address of the sack, not as a reference to an object.

[[sample-step]]
Sample Step
~~~~~~~~~~~

The `sample()`-step is useful for sampling some number of traversers previous in the traversal.

[gremlin-groovy,modern]
----
g.V().outE().sample(1).values('weight')
g.V().outE().sample(1).by('weight').values('weight')
g.V().outE().sample(2).by('weight').values('weight')
----

One of the more interesting use cases for `sample()` is when it is used in conjunction with <<local-step,`local()`>>. The combination of the two steps supports the execution of link:http://en.wikipedia.org/wiki/Random_walk[random walks]. In the example below, the traversal starts are vertex 1 and selects one edge to traverse based on a probability distribution generated by the weights of the edges. The output is always a single path as by selecting a single edge, the traverser never splits and continues down a single path in the graph.

[gremlin-groovy,modern]
----
g.V(1).repeat(local(
         bothE().sample(1).by('weight').otherV()
       )).times(5)
g.V(1).repeat(local(
         bothE().sample(1).by('weight').otherV()
       )).times(5).path()
g.V(1).repeat(local(
         bothE().sample(1).by('weight').otherV()
       )).times(10).path()
----

[[select-step]]
Select Step
~~~~~~~~~~~

link:http://en.wikipedia.org/wiki/Functional_programming[Functional languages] make use of function composition and lazy evaluation to create complex computations from primitive operations. This is exactly what `Traversal` does. One of the differentiating aspects of Gremlin's data flow approach to graph processing is that the flow need not always go "forward," but in fact, can go back to a previously seen area of computation. Examples include <<path-step,`path()`>> as well as the `select()`-step (*map*). There are two general ways to use `select()`-step.

. Select labeled steps within a path (as defined by `as()` in a traversal).
. Select objects out of a `Map<String,Object>` flow (i.e. a sub-map).

The first use case is demonstrated via example below.

[gremlin-groovy,modern]
----
g.V().as('a').out().as('b').out().as('c') // no select
g.V().as('a').out().as('b').out().as('c').select()
g.V().as('a').out().as('b').out().as('c').select('a','b')
g.V().as('a').out().as('b').out().as('c').select('a','b').by('name')
g.V().as('a').out().as('b').out().as('c').select('a') <1>
----

<1> If the selection is one step, no map is returned.

When there is only one label selected, then a single object is returned. This is useful for stepping back in a computation and easily moving forward again on the object reverted to.

[gremlin-groovy,modern]
----
g.V().out().out()
g.V().out().out().path()
g.V().as('x').out().out().select('x')
g.V().out().as('x').out().select('x')
g.V().out().out().as('x').select('x') // pointless
----

The second use case is best understood in terms of <<match-step,`match()`>>-step where the result of `match()` is a `Map<String,Object>` of variable bindings. However, any step that emits a `Map<String,Object>` can be selected. A contrived example is presented below.

[gremlin-groovy,modern]
----
g.V().range(0, 2).as('a').map {[b:1,c:2]} <1>
g.V().range(0, 2).as('a').map {[b:1,c:2]}.select(local) <2>
g.V().range(0, 2).as('a').map {[b:1,c:2]}.select(local,'a','c') <3>
g.V().range(0, 2).as('a').map {[b:1,c:2]}.select(local,'c') <4>
----

<1> A contrived example to create a `Map<String,Object>` flow as a foundation for the examples to follow.
<2> Select will grab both labeled steps and `Map<String,Object>` entries.
<3> The same `List<String>` selectivity can be used as demonstrated in the previous example.
<4> If a single selection is used, then the object is emitted not wrapped in a map. Useful for continuing the traversal process without having to do a map projection.

NOTE: When executing a traversal with `select()` on a standard traversal engine (i.e. OLTP), `select()` will do its best to avoid calculating the path history and instead, will rely on a global data structure for storing the currently selected object. As such, if only a subset of the path walked is required, `select()` should be used over the more resource intensive <<path-step,`path()`>>-step.

[[using-where-with-select]]
Using Where with Select
^^^^^^^^^^^^^^^^^^^^^^^

Finally, like <<match-step,`match()`>>-step, it is possible to use `where()`, as where is a filter that processes `Map<String,Object>` streams.

[gremlin-groovy,modern]
----
g.V().as('a').out('created').in('created').as('b').select().by('name') <1>
g.V().as('a').out('created').in('created').as('b').
      select().by('name').where('a',neq('b')) <2>
g.V().as('a').out('created').in('created').as('b').
      select(). <3>
      where('a',neq('b')).
      where(__.as('a').out('knows').as('b')).
      select().by('name')
----

<1> A standard `select()` that generates a `Map<String,Object>` of variables bindings in the path (i.e. `a` and `b`) for the sake of a running example.
<2> The `select().by('name')` projects each binding vertex to their name property value and `where()` operates to ensure respective `a` and `b` strings are not the same.
<3> The first `select()` projects a vertex binding set. A binding is filtered if `a` vertex equals `b` vertex. A binding is filtered if `a` doesn't know `b`. The second and final `select()` projects the name of the vertices.

[[simplepath-step]]
SimplePath Step
~~~~~~~~~~~~~~~

image::simplepath-step.png[width=400]

When it is important that a traverser not repeat its path through the graph, `simplePath()`-step should be used (*filter*). The <<path-data-structure,path>> information of the traverser is analyzed and if the path has repeated objects in it, the traverser is filtered. If cyclic behavior is desired, see <<cyclicpath-step,`cyclicPath()`>>.

[gremlin-groovy,modern]
----
g.V(1).both().both()
g.V(1).both().both().simplePath()
g.V(1).both().both().simplePath().path()
----

[[store-step]]
Store Step
~~~~~~~~~~

When link:http://en.wikipedia.org/wiki/Lazy_evaluation[lazy] aggregation is needed, `store()`-step (*sideEffect*) should be used over <<aggregate-step,`aggregate()`>>. The two steps differ in that `store()` does not block and only stores objects in its side-effect collection as they pass through.

[gremlin-groovy,modern]
----
g.V().aggregate('x').limit(1).cap('x')
g.V().store('x').limit(1).cap('x')
----

It is interesting to note that there are three results in the `store()` side-effect even though the interval selection is for 2 objects. Realize that when the third object is on its way to the `range()` filter (i.e. `[0..1]`), it passes through `store()` and thus, stored before filtered.

[gremlin-groovy,modern]
----
g.E().store().by('weight')
----

[[subgraph-step]]
Subgraph Step
~~~~~~~~~~~~~

image::subgraph-logo.png[width=380]

Extracting a portion of a graph from a larger one for analysis, visualization or other purposes is a fairly common use case for graph analysts and developers. The `subgraph()`-step (*sideEffect*) provides a way to produce an link:http://mathworld.wolfram.com/Edge-InducedSubgraph.html[edge-induced subgraph] from virtually any traversal.  The following example demonstrates how to produce the "knows" subgraph:

[gremlin-groovy,modern]
----
subGraph = g.E().hasLabel('knows').subgraph('subGraph').cap('subGraph').next() <1>
sg = subGraph.traversal(standard())
sg.E() <2>
----

<1> As this function produces "edge-induced" subgraphs, `subgraph()` must be called at edge steps.
<2> The subgraph contains only "knows" edges.

A more common subgraphing use case is to get all of the graph structure surrounding a single vertex:

[gremlin-groovy,modern]
----
subGraph = g.V(3).repeat(__.inE().subgraph('subGraph').outV()).times(3).cap('subGraph').next()  <1>
sg = subGraph.traversal(standard())
sg.E()
----

<1> Starting at vertex `3`, traverse 3 steps away on in-edges, outputting all of that into the subgraph.

There can be multiple `subgraph()` calls within the same traversal. Each operating against either the same graph (i.e. same side-effect key) or different graphs (i.e. different side-effect keys).

[gremlin-groovy,modern]
----
t = g.V().outE('knows').subgraph('knowsG').inV().outE('created').subgraph('createdG').
          inV().inE('created').subgraph('createdG').iterate()
t.sideEffects.get('knowsG').get().traversal(standard()).E()
t.sideEffects.get('createdG').get().traversal(standard()).E()
----

IMPORTANT: The `subgraph()`-step only writes to graphs that support user supplied ids for its elements. Moreover, if no graph is specified via `withSideEffect()`, then <<tinkergraph-gremlin,TinkerGraph>> is assumed.

[[sum-step]]
Sum Step
~~~~~~~~

The `sum()`-step (*map*) operates on a stream of numbers and sums the numbers together to yield a double. Note that the current traverser number is multiplied by the traverser bulk to determine how many such numbers are being represented.

[gremlin-groovy,modern]
----
g.V().values('age').sum()
g.V().repeat(both()).times(3).values('age').sum()
----

IMPORTANT: `sum(local)` determines the sum of the current, local object (not the objects in the traversal stream). This works for `Collection`-type objects. For any other object, a sum of `Double.NaN` is returned.

[[timelimit-step]]
TimeLimit Step
~~~~~~~~~~~~~~

In many situations, a graph traversal is not about getting an exact answer as its about getting a relative ranking. A classic example is link:http://en.wikipedia.org/wiki/Recommender_system[recommendation]. What is desired is a relative ranking of vertices, not their absolute rank. Next, it may be desirable to have the traversal execute for no more than 2 milliseconds. In such situations, `timeLimit()`-step (*filter*) can be used.

image::timelimit-step.png[width=400]

NOTE: The method `clock(int runs, Closure code)` is a utility preloaded in the <<gremlin-console,Gremlin Console>> that can be used to time execution of a body of code.

[gremlin-groovy,modern]
----
g.V().repeat(both().groupCount('m')).times(16).cap('m').order(local).by(valueDecr).next()
clock(1) {g.V().repeat(both().groupCount('m')).times(16).cap('m').order(local).by(valueDecr).next()}
g.V().repeat(timeLimit(2).both().groupCount('m')).times(16).cap('m').order(local).by(valueDecr).next()
clock(1) {g.V().repeat(timeLimit(2).both().groupCount('m')).times(16).cap('m').order(local).by(valueDecr).next()}
----

In essence, the relative order is respected, even through the number of traversers at each vertex is not. The primary benefit being that the calculation is guaranteed to complete at the specified time limit (in milliseconds). Finally, note that the internal clock of `timeLimit()`-step starts when the first traverser enters it. When the time limit is reached, any `next()` evaluation of the step will yield a `NoSuchElementException` and any `hasNext()` evaluation will yield `false`.

[[tree-step]]
Tree Step
~~~~~~~~~

From any one element (i.e. vertex or edge), the emanating paths from that element can be aggregated to form a link:http://en.wikipedia.org/wiki/Tree_(data_structure)[tree]. Gremlin provides `tree()`-step (*sideEffect*) for such this situation.

image::tree-step.png[width=450]

[gremlin-groovy,modern]
----
tree = g.V().out().out().tree().next()
----

It is important to see how the paths of all the emanating traversers are united to form the tree.

image::tree-step2.png[width=500]

The resultant tree data structure can then be manipulated (see link:http://www.tinkerpop.com/javadocs/current/org/apache/tinkerpop/gremlin/process/graph/step/util/Tree.html[Tree JavaDoc]). For the sake of demonstration, a post-processing lambda is applied in the running example below.

[gremlin-groovy,modern]
----
tree = g.V().out().out().tree().by('name').next()
tree['marko']
tree['marko']['josh']
tree.getObjectsAtDepth(3)
----

[[unfold-step]]
Unfold Step
~~~~~~~~~~~

If the object reaching `unfold()` (*flatMap*) is an iterator, iterable, or map, then it is unrolled into a linear form. If not, then the object is simply emitted. Please see <<fold-step,`fold()`>>-step for the inverse behavior.

[gremlin-groovy,modern]
----
g.V(1).out().fold().inject('gremlin',[1.23,2.34])
g.V(1).out().fold().inject('gremlin',[1.23,2.34]).unfold()
----

Note that `unfold()` does not recursively unroll iterators. Instead, `repeat()` can be used to for recursive unrolling.

[gremlin-groovy,modern]
----
inject(1,[2,3,[4,5,[6]]])
inject(1,[2,3,[4,5,[6]]]).unfold()
inject(1,[2,3,[4,5,[6]]]).repeat(unfold()).until(unfold().count().is(1l)).unfold()
----

[[union-step]]
Union Step
~~~~~~~~~~

image::union-step.png[width=650]

The `union()`-step (*branch*) supports the merging of the results of an arbitrary number of traversals. When a traverser reaches a `union()`-step, it is copied to each of its internal steps. The traversers emitted from `union()` are the outputs of the respective internal traversals.

[gremlin-groovy,modern]
----
g.V(4).union(
         __.in().values('age'),
         out().values('lang'))
g.V(4).union(
         __.in().values('age'),
         out().values('lang')).path()
----

[[valuemap-step]]
ValueMap Step
~~~~~~~~~~~~~

The `valueMap()`-step yields a Map representation of the properties of an element.

[gremlin-groovy,modern]
----
g.V().valueMap()
g.V().valueMap('age')
g.V().valueMap('age','blah')
g.E().valueMap()
----

It is important to note that the map of a vertex maintains a list of values for each key. The map of an edge or vertex-property represents a single property (not a list). The reason is that vertices in TinkerPop3 leverage <<vertex-properties,vertex properties>> which are support multiple values per key. Using the <<the-crew-toy-graph,"The Crew">> toy graph, the point is made explicit.

[gremlin-groovy,theCrew]
----
g.V().valueMap()
g.V().has('name','marko').properties('location')
g.V().has('name','marko').properties('location').valueMap()
----

If the `id`, `label`, `key`, and `value` of the `Element` is desired, then a boolean triggers its insertion into the returned map.

[gremlin-groovy,theCrew]
----
g.V().hasLabel('person').valueMap(true)
g.V().hasLabel('person').valueMap(true,'name')
g.V().hasLabel('person').properties('location').valueMap(true)
----

[[vertex-steps]]
Vertex Steps
~~~~~~~~~~~~

image::vertex-steps.png[width=350]

The vertex steps (*flatMap*) are fundamental to the Gremlin language. Via these steps, its possible to "move" on the graph -- i.e. traverse.

* `out(string...)`: Move to the outgoing adjacent vertices given the edge labels.
* `in(string...)`: Move to the incoming adjacent vertices given the edge labels.
* `both(string...)`: Move to both the incoming and outgoing adjacent vertices given the edge labels.
* `outE(string...)`: Move to the outgoing incident edges given the edge labels.
* `inE(string...)`: Move to the incoming incident edges given the edge labels.
* `bothE(string...)`: Move to both the incoming and outgoing incident edges given the edge labels.
* `outV()`: Move to the outgoing vertex.
* `inV()`: Move to the incoming vertex.
* `bothV()`: Move to both vertices.
* `otherV()` : Move to the vertex that was not the vertex that was moved from.

[gremlin-groovy,modern]
----
g.V(4)
g.V(4).outE() <1>
g.V(4).inE('knows') <2>
g.V(4).inE('created') <3>
g.V(4).bothE('knows','created','blah')
g.V(4).bothE('knows','created','blah').otherV()
g.V(4).both('knows','created','blah')
g.V(4).outE().inV() <4>
g.V(4).out() <5>
g.V(4).inE().outV()
g.V(4).inE().bothV()
----

<1> All outgoing edges.
<2> All incoming knows-edges.
<3> All incoming created-edges.
<4> Moving forward touching edges and vertices.
<5> Moving forward only touching vertices.

[[where-step]]
Where Step
~~~~~~~~~~

The `where()`-step filters the current object based on either the object itself (`Scope.local`) or the path history of the object (`Scope.global`) (*filter*). This step is typically used in conjuction with either <<match-step,`match()`>>-step or <<select-step,`select()`>>-step, but can be used in isolation.

[gremlin-groovy,modern]
----
g.V(1).as('a').out('created').in('created').where(neq('a')) <1>
g.withSideEffect('a'){['josh','peter']}.V(1).out('created').in('created').values('name').where(within('a')) <2>
g.V(1).out('created').in('created').where(out('created').count().is(gt(1))).values('name') <3>
----

<1> Who are marko's collaborators, where marko can not be his own collaborator? (predicate)
<2> Of the co-creators of marko, only keep those whose name is josh or peter. (using a sideEffect)
<3> Which of marko's collaborators have worked on more than 1 project? (using a traversal)

IMPORTANT: Please see <<using-where-with-match,`match().where()`>> and <<using-where-with-select,`select().where()`>> for how `where()` can be used in conjunction with `Map<String,Object>` projecting steps -- i.e. `Scope.local`.

[[a-note-on-barrier-steps]]
A Note on Barrier Steps
-----------------------

image:barrier.png[width=165,float=right] Gremlin is primarily a link:http://en.wikipedia.org/wiki/Lazy_evaluation[lazy], stream processing language. This means that Gremlin fully processes (to the best of its abilities) any traversers currently in the traversal pipeline before getting more data from the start/head of the traversal. However, there are numerous situations in which a completely lazy computation is not possible (or impractical). When a computation is not lazy, a "barrier step" exists. There are three types of barriers:

  . `CollectingBarrierStep`: All of the traversers prior to the step are put into a collection and then processed in some way (e.g. ordered) prior to the collection being "drained" one-by-one to the next step. Examples include: <<order-step,`order()`>>, <<sample-step,`sample()`>>, <<aggregate-step,`aggregate()`>>.
  . `ReducingBarrierStep`: All of the traversers prior to the step are processed by a reduce function and once all the previous traversers are processed, a single "reduced value" traverser is emitted to the next step. Examples include: <<fold-step,`fold()`>>, <<count-step,`count()`>>, <<sum-step,`sum()`>>, <<max-step,`max()`>>, <<min-step,`min()`>>.
  . `SupplyingBarrierStep`: All of the traversers prior to the step are iterated (no processing) and then some provided supplier yields a single traverser to continue to the next step. Examples include: <<cap-step,`cap()`>>.

In Gremlin OLAP (see <<traversalvertexprogram,`TraversalVertexProgram`>>), a barrier is introduced at the end of every <<vertex-steps,adjacent vertex step>>. This means that the traversal does its best to compute as much as possible at the current, local vertex. What is can't compute without referencing an adjacent vertex is aggregated into a barrier collection. When there are no more traversers at the local vertex, the barriered traversers are the messages that are propagated to remote vertices for further processing.

[[a-note-on-lambdas]]
A Note On Lambdas
-----------------

image:lambda.png[width=150,float=right] A link:http://en.wikipedia.org/wiki/Anonymous_function[lambda] is a function that can be referenced by software and thus, passed around like any other piece of data. In Gremlin, lambdas make it possible to generalize the behavior of a step such that custom steps can be created (on-the-fly) by the user. However, it is advised to avoid using lambdas if possible.

[gremlin-groovy,modern]
----
g.V().filter{it.get().value('name') == 'marko'}.
      flatMap{it.get().vertices(OUT,'created')}.
      map {it.get().value('name')} <1>
g.V().has('name','marko').out('created').values('name') <2>
----

<1> A lambda-rich Gremlin traversal which should and can be avoided. (*bad*)
<2> The same traversal (result), but without using lambdas. (*good*)

Gremlin attempts to provide the user a comprehensive collection of steps in the hopes that the user will never need to leverage a lambda in practice. It is advised that users only leverage a lambda if and only if there is no corresponding lambda-less step that encompasses the desired functionality. The reason being, lambdas can not be optimized by Gremlin's compiler strategies as they can not be programmatically inspected (see <<traversalstrategy,traversal strategies>>).

In many situations where a lambda could be used, either a corresponding step exists or a traversal can be provided in its place. A `TraversalLambda` behaves like a typical lambda, but it can be optimized and it yields less objects than the corresponding pure-lambda form.

[gremlin-groovy,modern]
----
g.V().out().out().path().by {it.value('name')}.
                         by {it.value('name')}.
                         by {g.V(it).in('created').values('name').fold().next()} <1>
g.V().out().out().path().by('name').
                         by('name').
                         by(__.in('created').values('name').fold()) <2>
----

<1> The length-3 paths have each of their objects transformed by a lambda. (*bad*)
<2> The length-3 paths have their objects transformed by a lambda-less step and a traversal lambda. (*good*)

[[traversalstrategy]]
TraversalStrategy
-----------------

image:traversal-strategy.png[width=125,float=right] A `TraversalStrategy` can analyze a `Traversal` and mutate the traversal as it deems fit. This is useful in multiple situations:

 * There is an application-level feature that can be embedded into the traversal logic (*decoration*).
 * There is a more efficient way to express the traversal at the TinkerPop3 level (*optimization*).
 * There is a more efficient way to express the traversal at the graph vendor level (*vendor optimization*).
 * There are are some final adjustments required before executing the traversal (*finalization*).
 * There are certain traversals that are not legal for the application or traversal engine (*verification*).

A simple `OptimizationStrategy` is the `IdentityRemovalStrategy`.

[source,java]
----
public class IdentityRemovalStrategy extends AbstractTraversalStrategy<TraversalStrategy.OptimizationStrategy> implements TraversalStrategy.OptimizationStrategy {

    private static final IdentityRemovalStrategy INSTANCE = new IdentityRemovalStrategy();

    private IdentityRemovalStrategy() {
    }

    @Override
    public void apply(final Traversal.Admin<?, ?> traversal) {
        if (!TraversalHelper.hasStepOfClass(IdentityStep.class, traversal))
            return;
        TraversalHelper.getStepsOfClass(IdentityStep.class, traversal).stream()
                .filter(step -> !TraversalHelper.isLabeled(step))
                .forEach(step -> traversal.removeStep(step));
    }

    public static IdentityRemovalStrategy instance() {
        return INSTANCE;
    }
}
----

This strategy simply removes any unlabeled `IdentityStep` steps in the Traversal as `aStep().identity().identity().bStep()` is equivalent to `aStep().bStep()`. For those traversal strategies that require other strategies to execute prior or post to the strategy, then the following two methods can be defined in `TraversalStrategy` (with defaults being an empty set). If the `TraversalStrategy` is in a particular traversal category (i.e. decoration, optimization, finalization, or verification), then priors and posts are only possible within the category.

[source,java]
public Set<Class<? extends S>> applyPrior();
public Set<Class<? extends S>> applyPost();

IMPORTANT: `TraversalStrategy` categories are sorted within their category and the categories are then executed in the following order: decoration, optimization, finalization, and verification. If a designed strategy does not fit cleanly into these categories, then it can implement `TraversalStrategy` and its prior and posts can reference strategies within any category.

An example of a `VendorOptimizationStrategy` is provided below.

[source,groovy]
g.V().has('name','marko')

The expression above can be executed in a `O(|V|)` or `O(log(|V|)` fashion in <<tinkergraph-gremlin,TinkerGraph>> depending on whether there is or is not an index defined for "name."

[source,java]
----
public final class TinkerGraphStepStrategy extends AbstractTraversalStrategy<TraversalStrategy.VendorOptimizationStrategy> implements TraversalStrategy.VendorOptimizationStrategy {

    private static final TinkerGraphStepStrategy INSTANCE = new TinkerGraphStepStrategy();

    private TinkerGraphStepStrategy() {
    }

    @Override
    public void apply(final Traversal.Admin<?, ?> traversal) {
        if (traversal.getEngine().isComputer())
            return;

        final Step<?, ?> startStep = traversal.getStartStep();
        if (startStep instanceof GraphStep) {
            final GraphStep<?> originalGraphStep = (GraphStep) startStep;
            final TinkerGraphStep<?> tinkerGraphStep = new TinkerGraphStep<>(originalGraphStep);
            TraversalHelper.replaceStep(startStep, (Step) tinkerGraphStep, traversal);

            Step<?, ?> currentStep = tinkerGraphStep.getNextStep();
            while (true) {
                if (currentStep instanceof HasContainerHolder) {
                    tinkerGraphStep.hasContainers.addAll(((HasContainerHolder) currentStep).getHasContainers());
                    currentStep.getLabels().forEach(tinkerGraphStep::addLabel);
                    traversal.removeStep(currentStep);
                } else {
                    break;
                }
                currentStep = currentStep.getNextStep();
            }
        }
    }

    public static TinkerGraphStepStrategy instance() {
        return INSTANCE;
    }
}
----

The traversal is redefined by simply taking a chain of `has()`-steps after `g.V()` (`TinkerGraphStep`) and providing them to `TinkerGraphStep`. Then its up to TinkerGraphStep to determine if an appropriate index exists. In the code below, review the `vertices()` method and note how if an index exists, for a particular `HasContainer`, then that index is first queried before the remaining `HasContainer` filters are serially applied. Given that the strategy uses non-TinkerPop3 provided steps, it should go into the `VendorOptimizationStrategy` category to ensure the added step does not corrupt the `OptimizationStrategy` strategies.

[gremlin-groovy,modern]
----
t = g.V().has('name','marko'); null
t.toString()
t.iterate(); null
t.toString()
----

A collection of useful `DecorationStrategy` strategies are provided with TinkerPop3 and are generally useful to end-users.  The following sub-sections detail these strategies:

ElementIdStrategy
~~~~~~~~~~~~~~~~~

`ElementIdStrategy` provides control over element identifiers. Some Graph implementations, such as TinkerGraph, allow specification of custom identifiers when creating elements:

[gremlin-groovy]
----
g = TinkerGraph.open().traversal()
v = g.addV(id,'42a')
g.V('42a')
----

Other `Graph` implementations, such as Neo4j, generate element identifiers automatically and cannot be assigned.  As a helper, `ElementIdStrategy` can be used to make identifier assignment possible by using vertex and edge indicies under the hood.

[source,groovy]
----
gremlin> graph = Neo4jGraph.open('/tmp/neo4j')
==>neo4jgraph[EmbeddedGraphDatabase [/tmp/neo4j]]
gremlin> strategy = ElementIdStrategy.build().create()
==>ElementIdStrategy
gremlin> g = GraphTraversalSource.build().with(strategy).create(graph)
==>graphtraversalsource[neo4jgraph[EmbeddedGraphDatabase [/tmp/neo4j]], standard]
gremlin> g.addV(id, '42a').id()
==>42a
----

IMPORTANT: The key that is used to store the assigned identifier should be indexed in the underlying graph database. If it is not indexed, then lookups for the elements that use these identifiers will perform a linear scan.

EventStrategy
~~~~~~~~~~~~~

The purpose of the `EventStrategy` is to raise events to one or more `MutationListener` objects as changes to the underlying `Graph` occur within a `Traversal`. Such a strategy is useful for logging changes, triggering certain actions based on change, or any application that needs notification of some mutating operation during a `Traversal`.  Graphs that do not support transactions will generate events immediately upon mutation, while those graphs that support transactions will queue the mutations until that transaction is committed and will then raise the events.  If the transaction is rolled back, the event queue is reset.

The following events are raised to the `MutationListener`:

* New vertex
* New edge
* Vertex property changed
* Edge property changed
* Vertex property removed
* Edge property removed
* Vertex removed
* Edge removed

To start processing events from a `Traversal` first implement the `MutationListener` interface. An example of this implementation is the `ConsoleMutationListener` which writes output to the console for each event.  The following console session displays the basic usage:

[gremlin-groovy]
----
graph = TinkerFactory.createModern()
l = new ConsoleMutationListener(graph)
strategy = EventStrategy.build().addListener(l).create()
g = GraphTraversalSource.build().with(strategy).create(graph)
g.addV('name','stephen')
g.E().drop()
----

The example above uses TinkerGraph which does not support transactions.  As mentioned previously, for these types of graph implementations events are raised as they occur within execution of a `Step`.  As such, the final line of Gremlin execution that drops all edges shows a bit of an inconsistent count, where the removed edge count is accounted for after the event is raised.

CAUTION: `EventStrategy` is not meant for usage in tracking global mutations across separate processes.  In other words, an mutation in what JVM process is not raised as an event in a different JVM process.  In addition, events are not raised when mutations occur outside of the `Traversal` context.

PartitionStrategy
~~~~~~~~~~~~~~~~~

image::partition-graph.png[width=325]

`PartitionStrategy` partitions the vertices and edges of a graph into `String` named partitions (i.e. buckets, subgraphs, etc.). The idea behind `PartitionStrategy` is presented in the image above where each element is in a single partition (represented by its color). Partitions can be read from, written to, and linked/joined by edges that span one or two partitions (e.g. a tail vertex in one partition and a head vertex in another).

There are three primary variables in `PartitionStrategy`:

. Partition Key - The property key that denotes a String value representing a partition.
. Write Partition - A `String` denoting what partition all future written elements will be in.
. Read Partitions - A `Set<String>` of partitions that can be read from.

The best way to understand `PartitionStrategy` is via example.

[gremlin-groovy]
----
graph = TinkerFactory.createModern()
strategyA = PartitionStrategy.build().partitionKey("_partition").writePartition("a").addReadPartition("a").create()
strategyB = PartitionStrategy.build().partitionKey("_partition").writePartition("b").addReadPartition("b").create()
gA = GraphTraversalSource.build().with(strategyA).create(graph)
gA.addV() // this vertex has a property of {_partition:"a"}
gB = GraphTraversalSource.build().with(strategyB).create(graph)
gB.addV() // this vertex has a property of {_partition:"b"}
gA.V()
gB.V()
----

By writing elements to particular partitions and then restricting read partitions, the developer is able to create multiple graphs within a single address space. Moreover, by supporting references between partitions, it is possible to merge those multiple graphs (i.e. join partitions).

ReadOnlyStrategy
~~~~~~~~~~~~~~~~

`ReadOnlyStrategy` is largely self-explanatory.  A `Traversal` that has this strategy applied will throw an `IllegalStateException` if the `Traversal` has any mutating steps within it.

SubgraphStrategy
~~~~~~~~~~~~~~~~

`SubgraphStrategy` is quite similar to `PartitionStrategy` in that it restrains a `Traversal` to certain vertices and edges as determined by a `Predicate` defined individually for each.

[gremlin-groovy]
----
graph = TinkerFactory.createModern()
vertexCriterion = { vertex -> true }
edgeCriterion = { edge -> edge.id() >= 8 && edge.id() <= 10}
strategy = SubgraphStrategy.build().vertexPredicate(vertexCriterion).edgePredicate(edgeCriterion).create()
g = GraphTraversalSource.build().with(strategy).create(graph)
g.V() // shows all vertices as they all pass the vertexCriterion
g.E() // shows only the edges defined in the edgeCriterion
----

Note that `SubgraphStrategy` directly passes the edge and vertex criterion `Predicate` objects  to an injected `filter` step and as such may not take advantage of important optimizations provided by the various `Graph` implementations (given the use of lambda expressions).

////
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
////
[[traversal]]
The Traversal
=============

image::gremlin-running.png[width=125]

At the most general level there is `Traversal<S,E>` which implements `Iterator<E>`, where the `S` stands for start and the `E` stands for end. A traversal is composed of four primary components:

 . `Step<S,E>`: an individual function applied to `S` to yield `E`. Steps are chained within a traversal.
 . `TraversalStrategy`: interceptor methods to alter the execution of the traversal (e.g. query re-writing).
 . `TraversalSideEffects`: key/value pairs that can be used to store global information about the traversal.
 . `Traverser<T>`: the object propagating through the `Traversal` currently representing an object of type `T`.

The classic notion of a graph traversal is provided by `GraphTraversal<S,E>` which extends `Traversal<S,E>`. GraphTraversal provides an interpretation of the graph data in terms of vertices, edges, etc. and thus, a graph traversal link:http://en.wikipedia.org/wiki/Domain-specific_language[DSL].

IMPORTANT: The underlying `Step` implementations provided by TinkerPop should encompass most of the functionality required by a DSL author. It is important that DSL authors leverage the provided steps as then the common optimization and decoration strategies can reason on the underlying traversal sequence. If new steps are introduced, then common traversal strategies may not function properly.

[[graph-traversal-steps]]
Graph Traversal Steps
---------------------

image::step-types.png[width=650]

A `GraphTraversal<S,E>` can be spawned off of a Graph, Vertex, Edge, or VertexProperty. It can also be spawned anonymously (i.e. empty) via `__`. A graph traversal is composed of an ordered list of steps. All the steps provided by `GraphTraversal` inherit from the more general forms diagrammed above. A list of all the steps (and their descriptions) are provided in the TinkerPop3 link:http://www.tinkerpop.com/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/graph/GraphTraversal.html[GraphTraversal JavaDoc]. The following subsections will demonstrate the GraphTraversal steps using the <<gremlin-console,Gremlin Console>>.

NOTE: To reduce the verbosity of the expression, it is good to `import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*`. This way, instead of doing `__.inE()` for an anonymous traversal, it is possible to simply write `inE()`.

[[lambda-steps]]
Lambda Steps
~~~~~~~~~~~~

CAUTION: Lambda steps are presented for educational purposes as they represent the foundational constructs of the Gremlin language. In practice, lambda steps should be avoided and traversal verification strategies exist to disallow their use unless explicitly "turned off." For more information on the problems with lambdas, please read <<a-note-on-lambdas,A Note on Lambdas>>.

There are four generic steps by which all other specific steps described later extend.

[width="100%",cols="10,12",options="header"]
|=========================================================
| Step| Description
| `map(Function<Traverser<S>, E>)` | map the traverser to some object of type `E` for the next step to process.
| `flatMap(Function<Traverser<S>, Iterator<E>>)` | map the traverser to an iterator of `E` objects that are streamed to the next step.
| `filter(Predicate<Traverser<S>>)` | map the traverser to either true or false, where false will not pass the traverser to the next step.
| `sideEffect(Consumer<Traverser<S>>)` | perform some operation on the traverser and pass it to the next step.
| `branch(Function<Traverser<S>,M>)` | split the traverser to all the traversals indexed by the `M` token.
|=========================================================

The `Traverser<S>` object provides access to:

 . The current traversed `S` object -- `Traverser.get()`.
 . The current path traversed by the traverser -- `Traverser.path()`.
  .. A helper shorthand to get a particular path-history object -- `Traverser.path(String) == Traverser.path().get(String)`.
 . The number of times the traverser has gone through the current loop -- `Traverser.loops()`.
 . The number of objects represented by this traverser -- `Traverser.bulk()`.
 . The local data structure associated with this traverser -- `Traverser.sack()`.
 . The side-effects associated with the traversal -- `Traverser.sideEffects()`.
  .. A helper shorthand to get a particular side-effect -- `Traverser.sideEffect(String) == Traverser.sideEffects().get(String)`.

image:map-lambda.png[width=150,float=right]
[gremlin-groovy,modern]
----
g.V(1).out().values('name') <1>
g.V(1).out().map {it.get().value('name')} <2>
----

<1> An outgoing traversal from vertex 1 to the name values of the adjacent vertices.
<2> The same operation, but using a lambda to access the name property values.

image:filter-lambda.png[width=160,float=right]
[gremlin-groovy,modern]
----
g.V().filter {it.get().label() == 'person'} <1>
g.V().hasLabel('person') <2>
----

<1> A filter that only allows the vertex to pass if it has an age-property.
<2> The more specific `has()`-step is implemented as a `filter()` with respective predicate.

image:side-effect-lambda.png[width=175,float=right]
[gremlin-groovy,modern]
----
g.V().hasLabel('person').sideEffect(System.out.&println) <1>
----

<1> Whatever enters `sideEffect()` is passed to the next step, but some intervening process can occur.

image:branch-lambda.png[width=180,float=right]
[gremlin-groovy,modern]
----
g.V().branch(values('name')).
      option('marko', values('age')).
      option(none, values('name')) <1>
g.V().choose(has('name','marko'),
             values('age'),
             values('name')) <2>
----

<1> If the vertex is "marko", get his age, else get the name of the vertex.
<2> The more specific boolean-based `choose()`-step is implemented as a `branch()`.

[[addedge-step]]
AddEdge Step
~~~~~~~~~~~~

It is possible to mutate the graph within a traversal. The typical mutations are adding/removing vertices, edges, and properties. To add edges, there are a collection of `addE()`-steps (*map*/*sideEffect*).

[gremlin-groovy,modern]
----
g.V(1).addOutE('co-worker',g.V(2),'year',2009) <1>
g.V(4).addInE('createdBy',g.V(3,5)) <2>
g.V(1).addOutE('livesNear',g.V(2),'year',2009).inV().inE('livesNear').values('year') <3>
g.V(1).out('livesNear')
----

<1> Add an outgoing co-worker edge from the marko-vertex to the vadas-vertex with a year property of value 2009.
<2> Add incoming createdBy edges from the josh-vertex to the lop- and ripple-vertices.
<3> The newly created edge is a traversable object.

image::addedge-step.png[width=450]

link:http://en.wikipedia.org/wiki/Automated_reasoning[Reasoning] is the process of making explicit in the data was is implicit in the data. What is explicit in a graph are the objects of the graph -- i.e. vertices and edges. What is implicit in the graph is the traversal. In other words, traversals expose meaning where the meaning is defined by the traversal description. For example, take the concept of a "co-developer." Two people are co-developers if they have worked on the same project together. This concept can be represented as a traversal and thus, the concept of "co-developers" can be derived.

[gremlin-groovy,modern]
----
g.V(1).as('a').out('created')
g.V(1).as('a').out('created').in('created')
g.V(1).as('a').out('created').in('created').where(neq('a')) <1>
g.V(1).as('a').out('created').in('created').where(neq('a')).
   addOutE('co-developer','a').outV().
   addInE('co-developer','a')
g.V(1).out('co-developer').values('name')
g.V(1).in('co-developer').values('name')
----

<1> Marko can't be a co-developer with himself.

[[addvertex-step]]
AddVertex Step
~~~~~~~~~~~~~~

The `addV()`-step is used to add vertices to the graph (*map*/*sideEffect*). For every incoming object, a vertex is created. Moreover, `GraphTraversalSource` maintains an `addV()` method.

[gremlin-groovy,modern]
----
g.addV(label,'person','name','stephen')
g.V().values('name')
g.V().outE('knows').addV('name','nothing')
g.V().has('name','nothing')
g.V().has('name','nothing').bothE()
----

[[addproperty-step]]
AddProperty Step
~~~~~~~~~~~~~~~~

The `property()`-step is used to add properties to the elements of the graph (*sideEffect*). Unlike `addV()` and `addE()`, `property()` is a full sideEffect step in that it does not return the property it created, but the element that streamed into it.

[gremlin-groovy,modern]
----
g.V(1).property('country','usa')
g.V(1).property('city','santa fe').property('state','new mexico').valueMap()
g.V(1).property(list,'age',35)
g.V(1).valueMap()
----

[[aggregate-step]]
Aggregate Step
~~~~~~~~~~~~~~

image::aggregate-step.png[width=800]

The `aggregate()`-step (*sideEffect*) is used to aggregate all the objects at a particular point of traversal into a Collection. The step uses link:http://en.wikipedia.org/wiki/Eager_evaluation[eager evaluation] in that no objects continue on until all previous objects have been fully aggregated (as opposed to <<store-step,`store()`>> which link:http://en.wikipedia.org/wiki/Lazy_evaluation[lazily] fills a collection). The eager evaluation nature is crucial in situations where everything at a particular point is required for future computation. An example is provided below.

[gremlin-groovy,modern]
----
g.V(1).out('created') <1>
g.V(1).out('created').aggregate('x') <2>
g.V(1).out('created').aggregate('x').in('created') <3>
g.V(1).out('created').aggregate('x').in('created').out('created') <4>
g.V(1).out('created').aggregate('x').in('created').out('created').
       where(without('x')).values('name') <5>
----

<1> What has marko created?
<2> Aggregate all his creations.
<3> Who are marko's collaborators?
<4> What have marko's collaborators created?
<5> What have marko's collaborators created that he hasn't created?

In link:http://en.wikipedia.org/wiki/Recommender_system[recommendation systems], the above pattern is used:

	"What has userA liked? Who else has liked those things? What have they liked that userA hasn't already liked?"

Finally, `aggregate()`-step can be modulated via `by()`-projection.

[gremlin-groovy,modern]
----
g.V().out('knows').aggregate()
g.V().out('knows').aggregate().by('name')
----

[[and-step]]
And Step
~~~~~~~~

The `and()`-step ensures that all provided traversals yield a result (*filter*). Please see <<or-step,`or()`>> for or-semantics.

[gremlin-groovy,modern]
----
g.V().and(
   outE('knows'),
   values('age').is(lt(30))).
     values('name')
----

The `and()`-step can take an arbitrary number of traversals. All traversals must produce at least one output for the original traverser to pass to the next step.

An link:http://en.wikipedia.org/wiki/Infix_notation[infix notation] can be used as well. Though, with infix notation, only two traversals can be and'd together.

[gremlin-groovy,modern]
----
g.V().has(outE('created').and().outE('knows')).values('name')
----

[[as-step]]
As Step
~~~~~~~

The `as()`-step is not a real step, but a "step modulator" similar to <<by-step,`by()`>> and <<option-step,`option()`>>. With `as()`, it is possible to provide a label to the step that can later be accessed by steps and data structures that make use of such labels -- e.g., <<select-step,`select()`>>, <<match-step,`match()`>>, and path.

[gremlin-groovy,modern]
----
g.V().as('a').out('created').as('b').select()            <1>
g.V().as('a').out('created').as('b').select().by('name') <2>
----

<1> Select the objects labeled "a" and "b" from the path.
<2> Select the objects labeled "a" and "b" from the path and, for each object, project its name value.

A step can have any number of labels associated with it. This is useful for referencing the same step multiple times in a future step.

[gremlin-groovy,modern]
----
g.V().hasLabel('software').as('a','b','c').
   select().
     by('name').
     by('lang').
     by(__.in('created').values('name').fold())
----

[[by-step]]
By Step
~~~~~~~

The `by()`-step is not an actual step, but instead is a "step-modulator" similar to <<as-step,`as()`>> and <<option-step,`option()`>>. If a step is able to accept traversals, functions, comparators, etc. then `by()` is the means by which they are added. The general pattern is `step().by()...by()`. Some steps can only accept one `by()` while others can take an arbitrary amount.

[gremlin-groovy,modern]
----
g.V().group().by(bothE().count())                                  <1>
g.V().group().by(bothE().count()).by('name')                       <2>
g.V().group().by(bothE().count()).by('name').by(count(local))  <3>
----

<1> `by(outE().count())` will group the elements by their edge count (*traversal*).
<2> `by('name')` will process the grouped elements by their name (*element property projection*).
<3> `by(count(local))` will count the number of elements in each group (*traversal*).

[[coalesce-step]]
Coalesce Step
~~~~~~~~~~~~~

The `coalesce()`-step evaluates the provided traversals in order and returns the first traversal that emits at least one element.

[gremlin-groovy,modern]
----
g.V(1).coalesce(outE('knows'), outE('created')).inV().path().by('name').by(label)
g.V(1).coalesce(outE('created'), outE('knows')).inV().path().by('name').by(label)
g.V(1).next().property('nickname', 'okram')
g.V().hasLabel('person').coalesce(values('nickname'), values('name'))
----

[[count-step]]
Count Step
~~~~~~~~~~

image::count-step.png[width=195]

The `count()`-step (*map*) counts the total number of represented traversers in the streams (i.e. the bulk count).

[gremlin-groovy,modern]
----
g.V().count()
g.V().hasLabel('person').count()
g.V().hasLabel('person').outE('created').count().path()  <1>
g.V().hasLabel('person').outE('created').count().map {it.get() * 10}.path() <2>
----

<1> `count()`-step is a <<a-note-on-barrier-steps,reducing barrier step>> meaning that all of the previous traversers are folded into a new traverser.
<2> The path of the traverser emanating from `count()` starts at `count()`.

IMPORTANT: `count(local)` counts the current, local object (not the objects in the traversal stream). This works for `Collection`- and `Map`-type objects. For any other object, a count of 1 is returned.

[[choose-step]]
Choose Step
~~~~~~~~~~~

image::choose-step.png[width=700]

The `choose()`-step (*branch*) routes the current traverser to a particular traversal branch option. With `choose()`, it is possible to implement if/else-based semantics as well as more complicated selections.

[gremlin-groovy,modern]
----
g.V().hasLabel('person').
      choose(values('age').is(lte(30)),
        __.in(),
        __.out()).values('name') <1>
g.V().hasLabel('person').
      choose(values('age')).
        option(27, __.in()).
        option(32, __.out()).values('name') <2>
----

<1> If the traversal yields an element, then do `in`, else do `out` (i.e. true/false-based option selection).
<2> Use the result of the traversal as a key to the map of traversal options (i.e. value-based option selection).

However, note that `choose()` can have an arbitrary number of options and moreover, can take an anonymous traversal as its choice function.

[gremlin-groovy,modern]
----
g.V().hasLabel('person').
      choose(values('name')).
        option('marko', values('age')).
        option('josh', values('name')).
        option('vadas', valueMap()).
        option('peter', label())
----

The `choose()`-step can leverage the `Pick.none` option match. For anything that does not match a specified option, the `none`-option is taken.

[gremlin-groovy,modern]
----
g.V().hasLabel('person').
      choose(values('name')).
        option('marko', values('age')).
        option(none, values('name'))
----

[[coin-step]]
Coin Step
~~~~~~~~~

To randomly filter out a traverser, use the `coin()`-step (*filter*). The provided double argument biases the "coin toss."

[gremlin-groovy,modern]
----
g.V().coin(0.5)
g.V().coin(0.0)
g.V().coin(1.0)
----

[[cyclicpath-step]]
CyclicPath Step
~~~~~~~~~~~~~~~

image::cyclicpath-step.png[width=400]

Each traverser maintains its history through the traversal over the graph -- i.e. its <<path-data-structure,path>>. If it is important that the traverser repeat its course, then `cyclic()`-path should be used (*filter*). The step analyzes the path of the traverser thus far and if there are any repeats, the traverser is filtered out over the traversal computation. If non-cyclic behavior is desired, see <<simplepath-step,`simplePath()`>>.

[gremlin-groovy,modern]
----
g.V(1).both().both()
g.V(1).both().both().cyclicPath()
g.V(1).both().both().cyclicPath().path()
----

[[dedup-step]]
Dedup Step
~~~~~~~~~~

With `dedup()`-step (*filter*), repeatedly seen objects are removed from the traversal stream. Note that if a traverser's bulk is greater than 1, then it is set to 1 before being emitted.

[gremlin-groovy,modern]
----
g.V().values('lang')
g.V().values('lang').dedup()
g.V(1).repeat(bothE('created').dedup().otherV()).emit().path() <1>
----

<1> Traverse all `created` edges, but don't touch any edge twice.

If a by-step modulation is provided to `dedup()`, then the object is processed accordingly prior to determining if it has been seen or not.

[gremlin-groovy,modern]
----
g.V().valueMap(true, 'name')
g.V().dedup().by(label).values('name')
----

WARNING: The `dedup()`-step does not have a correlate in <<traversalvertexprogram,Gremlin OLAP>> when used mid-traversal. When in mid-traversal de-duplication only occurs at the the current processing vertex and thus, is not a global operation as it in Gremlin OLTP. When `dedup()` is an end step, the resultant traversers are de-duplicated by `TraverserMapReduce`.

[[drop-step]]
Drop Step
~~~~~~~~~

The `drop()`-step (*filter*/*sideEffect*) is used to remove element and properties from the graph (i.e. remove). It is a filter step because the traversal yields no outgoing objects.

[gremlin-groovy,modern]
----
g.V().outE().drop()
g.E()
g.V().properties('name').drop()
g.V().valueMap()
g.V().drop()
g.V()
----

[[fold-step]]
Fold Step
~~~~~~~~~

There are situations when the traversal stream needs a "barrier" to aggregate all the objects and emit a computation that is a function of the aggregate. The `fold()`-step (*map*) is one particular instance of this. Please see <<unfold-step,`unfold()`>>-step for the inverse functionality.

[gremlin-groovy,modern]
----
g.V(1).out('knows').values('name')
g.V(1).out('knows').values('name').fold() <1>
g.V(1).out('knows').values('name').fold().next().getClass() <2>
g.V(1).out('knows').values('name').fold(0) {a,b -> a + b.length()} <3>
g.V().values('age').fold(0) {a,b -> a + b} <4>
g.V().values('age').fold(0, sum) <5>
g.V().values('age').sum() <6>
----

<1> A parameterless `fold()` will aggregate all the objects into a list and then emit the list.
<2> A verification of the type of list returned.
<3> `fold()` can be provided two arguments --  a seed value and a reduce bi-function ("vadas" is 5 characters + "josh" with 4 characters).
<4> What is the total age of the people in the graph?
<5> The same as before, but using a built-in bi-function.
<6> The same as before, but using the <<sum-step,`sum()`-step>>.

[[group-step]]
Group Step
~~~~~~~~~~

As traversers propagate across a graph as defined by a traversal, sideEffect computations are sometimes required. That is, the actual path taken or the current location of a traverser is not the ultimate output of the computation, but some other representation of the traversal. The `group()`-step (*sideEffect*) is one such sideEffect that organizes the objects according to some function of the object. Then, if required, that organization (a list) is reduced. An example is provided below.

[gremlin-groovy,modern]
----
g.V().group().by(label) <1>
g.V().group().by(label).by('name') <2>
g.V().group().by(label).by('name').by(count(local)) <3>
----

<1> Group the vertices by their label.
<2> For each vertex in the group, get their name.
<3> For each grouping, what is its size?

The three projection parameters available to `group()` via `by()` are:

. Key-projection: What feature of the object to group on (a function that yields the map key)?
. Value-projection: What feature of the group to store in the key-list?
. Reduce-projection: What feature of the key-list to ultimately return?

WARNING: The `group()`-step does not have a correlate in <<traversalvertexprogram,Gremlin OLAP>> when used mid-traversal. When in mid-traversal grouping only occurs at the the current processing vertex and thus, is not a global operation as it in Gremlin OLTP. However, `GroupMapReduce` provides unified groups at the end of the traversal computation.

[[groupcount-step]]
GroupCount Step
~~~~~~~~~~~~~~~

When it is important to know how many times a particular object has been at a particular part of a traversal, `groupCount()`-step (*sideEffect*) is used.

	"What is the distribution of ages in the graph?"

[gremlin-groovy,modern]
----
g.V().hasLabel('person').values('age').groupCount()
g.V().hasLabel('person').groupCount().by('age') <1>
----

<1> You can also supply a pre-group projection, where the provided <<by-step,`by()`>>-modulation determines what to group the incoming object by.

There is one person that is 32, one person that is 35, one person that is 27, and one person that is 29.

	"Iteratively walk the graph and count the number of times you see the second letter of each name."

image::groupcount-step.png[width=420]

[gremlin-groovy,modern]
----
g.V().repeat(both().groupCount('m').by(label)).times(10).cap('m')
----

The above is interesting in that it demonstrates the use of referencing the internal `Map<Object,Long>` of `groupCount()` with a string variable. Given that `groupCount()` is a sideEffect-step, it simply passes the object it received to its output. Internal to `groupCount()`, the object's count is incremented.

WARNING: The `groupCount()`-step does not have a correlate in <<traversalvertexprogram,Gremlin OLAP>> when used mid-traversal. When in mid-traversal grouping only occurs at the the current processing vertex and thus, is not a global operation as it in Gremlin OLTP. However, `GroupCountMapReduce` provides unified groups at the end of the traversal computation.

[[has-step]]
Has Step
~~~~~~~~

image::has-step.png[width=670]

It is possible to filter vertices, edges, and vertex properties based on their properties using `has()`-step (*filter*). There are numerous variations on `has()` including:

  * `has(key,value)`: Remove the traverser if its element does not have the provided key/value property.
  * `has(key,predicate)`: Remove the traverser if its element does not have a key value that satisfies the bi-predicate.
  * `hasLabel(labels...)`: Remove the traverser if its element does not have any of the labels.
  * `hasId(ids...)`: Remove the traverser if its element does not have any of the ids.
  * `hasKey(keys...)`: Remove the traverser if its property does not have any of the keys.
  * `hasValue(values...)`: Remove the traverser if its property does not have any of the values.
  * `has(key)`: Remove the traverser if its element has a value for the key.
  * `hasNot(key)`: Remove the traverser if its element does not have a value for the  key.
  * `has(traversal)`: Remove the traverser if its object does not yield a result through the traversal.

[gremlin-groovy,modern]
----
g.V().hasLabel('person')
g.V().hasLabel('person').out().has('name',within('vadas','josh'))
g.V().hasLabel('person').out().has('name',within('vadas','josh')).
      outE().hasLabel('created')
g.V().has('age',inside(20,30)).values('age') <1>
g.V().has('age',outside(20,30)).values('age') <2>
----

<1> Find all vertices whose ages are between 20 (inclusive) and 30 (exclusive).
<2> Find all vertices whose ages are not between 20 (inclusive) and 30 (exclusive).

It is also possible to filter any arbitrary object based on a anonymous traversal yielding at least one result.

[gremlin-groovy,modern]
----
g.V().has(out('created')).values('name') <1>
g.V().out('knows').has(out('created')).values('name') <2>
g.V().has(out('created').count().is(gte(2L))).values('name') <3>
g.V().has(out('knows').has(out('created'))).values('name') <4>
----

<1> What are the names of the people who have created a project?
<2> What are the names of the people that are known by someone one and have created a project?
<3> What are the names of the people how have created two or more projects?
<4> What are the names of the people who know someone that has created a project? (This only works in OLTP -- see the `WARNING` below)

WARNING: The anonymous traversal of `has()` processes the current object "locally". In OLAP, where the atomic unit of computing is the the vertex and its local "star graph," it is important that the anonymous traversal does not leave the confines of the vertex's star graph. In other words, it can not traverse to an adjacent vertex's properties or edges.

[[inject-step]]
Inject Step
~~~~~~~~~~~

image::inject-step.png[width=800]

One of the major features of TinkerPop3 is "injectable steps." This makes it possible to insert objects arbitrarily into a traversal stream. In general, `inject()`-step (*sideEffect*) exists and a few examples are provided below.

[gremlin-groovy,modern]
----
g.V(4).out().values('name').inject('daniel')
g.V(4).out().values('name').inject('daniel').map {it.get().length()}
g.V(4).out().values('name').inject('daniel').map {it.get().length()}.path()
----

In the last example above, note that the path starting with `daniel` is only of length 2. This is because the `daniel` string was inserted half-way in the traversal. Finally, a typical use case is provided below -- when the start of the traversal is not a graph object.

[gremlin-groovy,modern]
----
inject(1,2)
inject(1,2).map {it.get() + 1}
inject(1,2).map {it.get() + 1}.map {g.V(it.get()).next()}.values('name')
----

[[is-step]]
Is Step
~~~~~~~

It is possible to filter scalar values using `is()`-step (*filter*).

[gremlin-groovy,modern]
----
g.V().values('age').is(32)
g.V().values('age').is(lte(30))
g.V().values('age').is(inside(30, 40))
g.V().has(__.in('created').count().is(1l)).values('name') <1>
g.V().has(__.in('created').count().is(gte(2l))).values('name') <2>
g.V().has(__.in('created').values('age').
                           mean().is(inside(30d, 35d))).values('name') <3>
----

<1> Find projects having exactly one contributor.
<2> Find projects having two or more contributors.
<3> Find projects whose contributors average age is between 30 and 35.

[[limit-step]]
Limit Step
~~~~~~~~~~

The `limit()`-step is analogous to <<range-step,`range()`-step>> save that the lower end range is set to 0.

[gremlin-groovy,modern]
----
g.V().limit(2)
g.V().range(0, 2)
g.V().limit(2).toString()
----

[[local-step]]
Local Step
~~~~~~~~~~

image::local-step.png[width=450]

A `GraphTraversal` operates on a continuous stream of objects. In many situations, it is important to operate on a single element within that stream. To do such object-local traversal computations, `local()`-step exists (*branch*). Note that the examples below use the <<the-crew-toy-graph,The Crew>> toy data set.

[gremlin-groovy,theCrew]
----
g.V().as('person').
      properties('location').order().by('startTime',incr).limit(2).
      value().as('location').select().by('name').by() <1>
g.V().as('person').
      local(properties('location').order().by('startTime',incr).limit(2)).
      value().as('location').select().by('name').by() <2>
----

<1> Get the first two people and their respective location according to the most historic location start time.
<2> For every person, get their two most historic locations.

The two traversals above look nearly identical save the inclusion of `local()` which wraps a section of the traversal in a object-local traversal. As such, the `order().by()` and the `limit()` refer to a particular object, not to the stream as a whole.

WARNING: The anonymous traversal of `local()` processes the current object "locally." In OLAP, where the atomic unit of computing is the the vertex and its local "star graph," it is important that the anonymous traversal does not leave the confines of the vertex's star graph. In other words, it can not traverse to an adjacent vertex's properties or edges.

[[match-step]]
Match Step
~~~~~~~~~~

The `match()`-step (*map*) is introduced into TinkerPop3 to support a more link:http://en.wikipedia.org/wiki/Declarative_programming[declarative] form of link:http://en.wikipedia.org/wiki/Pattern_matching[pattern matching]. Similar constructs were available in previous TinkerPop versions via the `table()`-step, but that has since been removed in favor of the `match().select()`-pattern. With MatchStep in TinkerPop, a query optimizer similar to the link:http://www.knowledgefrominformation.com/2011/04/16/budget-match-cost-effective-subgraph-matching-on-large-networks/[budget match algorithm] builds and revises query plans on the fly, while a query is in progress. For very large graphs, where the developer is uncertain of the statistics of the graph (e.g. how many `knows`-edges vs. `worksFor`-edges exist in the graph), it is advantageous to use `match()`, as an optimal plan will be determined automatically.  Furthermore, some queries are much easier to express via `match()` than with single-path traversals.

	"Who created a project named 'lop' that was also created by someone who is 29 years old? Return the two creators."

image::match-step.png[width=500]

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('created').as('b'),
        __.as('b').has('name', 'lop'),
        __.as('b').in('created').as('c'),
        __.as('c').has('age', 29)).select('a','c').by('name')
----

Note that the above can also be more concisely written as below which demonstrates that imperative inner-traversals can be arbitrarily defined.

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('created').has('name', 'lop').as('b'),
        __.as('b').in('created').has('age', 29).as('c')).select('a','c').by('name')
----

[[grateful-dead]]
.Grateful Dead
image::grateful-dead-schema.png[width=475]

MatchStep brings functionality similar to link:http://en.wikipedia.org/wiki/SPARQL[SPARQL] to Gremlin. Like SPARQL, MatchStep conjoins a set of patterns applied to a graph.  For example, the following traversal finds exactly those songs which Jerry Garcia has both sung and written (using the Grateful Dead graph distributed in the `data/` directory):

[gremlin-groovy]
----
graph.io(graphml()).readGraph('data/grateful-dead.xml')
g = graph.traversal(standard())
g.V().match('a',
        __.as('a').has('name', 'Garcia'),
        __.as('a').in('writtenBy').as('b'),
        __.as('a').in('sungBy').as('b')).select('b').values('name')
----

Among the features which differentiate `match()` from SPARQL are:

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('created').has('name','lop').as('b'), <1>
        __.as('b').in('created').has('age', 29).as('c'),
        __.as('c').repeat(out()).times(2)). <2>
          select('c').out('knows').dedup().values('name') <3>
----

<1> *Patterns of arbitrary complexity*: `match()` is not restricted to triple patterns or property paths.
<2> *Recursion support*: `match()` supports the branch-based steps within a pattern, including `repeat()`.
<3> *Imperative/declarative hybrid*: Pre and prior to a `match()`, it is possible to leverage classic Gremlin imperative.

To extend point #3, it is possible to support going from imperative, to declarative, to imperative, ad infinitum.

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('knows').as('b'),
        __.as('b').out('created').has('name','lop')).
        select('b').out('created').
          match('a',
            __.as('a').in('created').as('b'),
            __.as('b').out('knows').as('c')).
            select('c').values('name')
----

Like all other steps in Gremlin, `match()` is a function and thus, `match()` within `match()` is a natural consequence of Gremlin's functional foundation (i.e. recursive matching).

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('knows').as('b'),
        __.as('b').out('created').has('name','lop'),
        __.as('b').match('x',
                 __.as('x').out('created').as('y'),
                 __.as('y').has('name','ripple')).
                 select('y').as('c')).
        select('a','c').by('name')
----

WARNING: Currently, `match()` does not operate within a multi-JVM <<graphcomputer,GraphComputer>> OLAP environment. Future work includes a linearization <<traversalstrategy,TraversalStrategy>> for `match()`.

[[using-where-with-match]]
Using Where with Match
^^^^^^^^^^^^^^^^^^^^^^

Match is typically used in conjunction with both `select()` (demonstrated previously) and `where()` (presented here). A `where()` allows the user to further constrain the result set provided by `match()`.

[gremlin-groovy,modern]
----
g.V().match('a',
        __.as('a').out('created').as('b'),
        __.as('b').in('created').as('c')).
          where('a', neq('c')).select('a','c').by('name')
----

The `where()`-step can take either a `BiPredicate` (first example below) or a `Traversal` (second example below). Using `MatchWhereStrategy`, `where()`-clauses can be automatically folded into `match()` and thus, subject to `match()`-steps budget-match algorithm.

[gremlin-groovy,modern]
----
traversal = g.V().match('a',
                    __.as('a').out('created').as('b'),
                    __.as('b').in('created').as('c')).
                      where(__.as('a').out('knows').as('c')). <1>
                      select('a','c').by('name'); null <2>
traversal.toString() <3>
traversal <4> <5>
traversal.toString() <6>
----

<1> A `where()`-step with a traversal containing variable bindings declared in `match()`.
<2> A useful trick to ensure that that the traversal is not iterated by Gremlin Console.
<3> The string representation of the traversal prior to its strategies being applied.
<4> The Gremlin Console will automatically iterate anything that is an iterator or is iterable.
<5> Both marko and josh are co-developers and marko knows josh.
<6> The string representation of the traversal after the strategies have been applied (and thus, `where()` is folded into `match()`)

[[max-step]]
Max Step
~~~~~~~~

The `max()`-step (*map*) operates on a stream of numbers and determines which is the largest number in the stream.

[gremlin-groovy,modern]
----
g.V().values('age').max()
g.V().repeat(both()).times(3).values('age').max()
----

IMPORTANT: `max(local)` determines the max of the current, local object (not the objects in the traversal stream). This works for `Collection` and `Number`-type objects. For any other object, a max of `Double.NaN` is returned.

[[mean-step]]
Mean Step
~~~~~~~~~

The `mean()`-step (*map*) operates on a stream of numbers and determines the average of those numbers.

[gremlin-groovy,modern]
----
g.V().values('age').mean()
g.V().repeat(both()).times(3).values('age').mean() <1>
g.V().repeat(both()).times(3).values('age').dedup().mean()
----

<1> Realize that traversers are being bulked by `repeat()`. There may be more of a particular number than another, thus altering the average.

IMPORTANT: `mean(local)` determines the mean of the current, local object (not the objects in the traversal stream). This works for `Collection` and `Number`-type objects. For any other object, a mean of `Double.NaN` is returned.

[[min-step]]
Min Step
~~~~~~~~

The `min()`-step (*map*) operates on a stream of numbers and determines which is the smallest number in the stream.

[gremlin-groovy,modern]
----
g.V().values('age').min()
g.V().repeat(both()).times(3).values('age').min()
----

IMPORTANT: `min(local)` determines the min of the current, local object (not the objects in the traversal stream). This works for `Collection` and `Number`-type objects. For any other object, a min of `Double.NaN` is returned.

[[or-step]]
Or Step
~~~~~~~

The `or()`-step ensures that at least one of the provided traversals yield a result (*filter*). Please see <<and-step,`and()`>> for and-semantics.

[gremlin-groovy,modern]
----
g.V().or(
   __.outE('created'),
   __.inE('created').count().is(gt(1l))).
     values('name')
----

The `or()`-step can take an arbitrary number of traversals. At least one of the traversals must produce at least one output for the original traverser to pass to the next step.

An link:http://en.wikipedia.org/wiki/Infix_notation[infix notation] can be used as well. Though, with infix notation, only two traversals can be or'd together.

[gremlin-groovy,modern]
----
g.V().has(outE('created').or().outE('knows')).values('name')
----

[[order-step]]
Order Step
~~~~~~~~~~

When the objects of the traversal stream need to be sorted, `order()`-step (*map*) can be leveraged.

[gremlin-groovy,modern]
----
g.V().values('name').order()
g.V().values('name').order().by(decr)
g.V().hasLabel('person').order().by('age', incr).values('name')
----

One of the most traversed objects in a traversal is an `Element`. An element can have properties associated with it (i.e. key/value pairs). In many situations, it is desirable to sort an element traversal stream according to a comparison of their properties.

[gremlin-groovy,modern]
----
g.V().values('name')
g.V().order().by('name',incr).values('name')
g.V().order().by('name',decr).values('name')
----

The `order()`-step allows the user to provide an arbitrary number of comparators for primary, secondary, etc. sorting. In the example below, the primary ordering is based on the outgoing created-edge count. The secondary ordering is based on the age of the person.

[gremlin-groovy,modern]
----
g.V().hasLabel('person').order().by(outE('created').count(), incr).
                                 by('age', incr).values('name')
g.V().hasLabel('person').order().by(outE('created').count(), incr).
                                 by('age', decr).values('name')
----

Randomizing the order of the traversers at a particular point in the traversal is possible with `Order.shuffle`.

[gremlin-groovy,modern]
----
g.V().hasLabel('person').order().by(shuffle)
g.V().hasLabel('person').order().by(shuffle)
----

IMPORTANT: `order(local)` orders the current, local object (not the objects in the traversal stream). This works for `Collection`- and `Map`-type objects. For any other object, the object is returned unchanged.

[[path-step]]
Path Step
~~~~~~~~~

A traverser is transformed as it moves through a series of steps within a traversal. The history of the traverser is realized by examining its path with `path()`-step (*map*).

image::path-step.png[width=650]

[gremlin-groovy,modern]
----
g.V().out().out().values('name')
g.V().out().out().values('name').path()
----

If edges are required in the path, then be sure to traverser those edges explicitly.

[gremlin-groovy,modern]
----
g.V().outE().inV().outE().inV().path()
----

It is possible to post-process the elements of the path in a round-robin fashion via `by()`.

[gremlin-groovy,modern]
----
g.V().out().out().path().by('name').by('age')
----

Finally, because `by()`-based post-processing, nothing prevents triggering yet another traversal. In the traversal below, for each element of the path traversed thus far, if its a person (as determined by having an `age`-property), then get all of their creations, else if its a creation, get all the people that created it.

[gremlin-groovy,modern]
----
g.V().out().out().path().by(
                   choose(hasLabel('person'),
                                 out('created').values('name'),
                                 __.in('created').values('name')).fold())
----

WARNING: Generating path information is expensive as the history of the traverser is stored into a Java list. With numerous traversers, there are numerous lists. Moreover, in an OLAP <<graphcomputer,`GraphComputer`>> environment this becomes exceedingly prohibitive as there are traversers emanating from all vertices in the graph in parallel. In OLAP there are optimizations provided for traverser populations, but when paths are calculated (and each traverser is unique due to its history), then these optimizations are no longer possible.

[[path-data-structure]]
Path Data Structure
^^^^^^^^^^^^^^^^^^^

The `Path` data structure is an ordered list of objects, where each object is associated to a `Set<String>` of labels. An example is presented below to demonstrate both the `Path` API as well as how a traversal yields labeled paths.

image::path-data-structure.png[width=350]

[gremlin-groovy,modern]
----
path = g.V(1).as('a').has('name').as('b').
              out('knows').out('created').as('c').
              has('name','ripple').values('name').as('d').
              identity().as('e').path().next()
path.size()
path.objects()
path.labels()
path.a
path.b
path.c
path.d == path.e
----

[[profile-step]]
Profile Step
~~~~~~~~~~~~

The `profile()`-step (*sideEffect*) exists to allow developers to profile their traversals to determine statistical information like step runtime, counts, etc.

WARNING: Profiling a Traversal will impede the Traversal's performance. This overhead is mostly excluded from the profile results, but durations are not exact. Thus, durations are best considered in relation to each other.

[gremlin-groovy,modern]
----
g.V().out('created').repeat(both()).times(3).hasLabel('person').values('age').sum().profile().cap(TraversalMetrics.METRICS_KEY)
----

The `profile()`-step generates a `TraversalMetrics` sideEffect object that contains the following information:

* `Step`: A step within the traversal being profiled.
* `Count`: The number of _represented_ traversers that passed through the step.
* `Traversers`: The number of traversers that passed through the step.
* `Time (ms)`: The total time the step was actively executing its behavior.
* `% Dur`: The percentage of total time spent in the step.

image:gremlin-exercise.png[width=120,float=left] It is important to understand the difference between `Count` and `Traversers`. Traversers can be merged and as such, when two traversers are "the same" they may be aggregated into a single traverser. That new traverser has a `Traverser.bulk()` that is the sum of the two merged traverser bulks. On the other hand, the `Count` represents the sum of all `Traverser.bulk()` results and thus, expresses the number of "represented" (not enumerated) traversers. `Traversers` will always be less than or equal to `Count`.

[[range-step]]
Range Step
~~~~~~~~~~

As traversers propagate through the traversal, it is possible to only allow a certain number of them to pass through with `range()`-step (*filter*). When the low-end of the range is not met, objects are continued to be iterated. When within the low and high range (both inclusive), traversers are emitted. Finally, when above the high range, the traversal breaks out of iteration.

[gremlin-groovy,modern]
----
g.V().range(0,3)
g.V().range(1,3)
g.V().repeat(both()).times(1000000).emit().range(6,10)
----

[[repeat-step]]
Repeat Step
~~~~~~~~~~~

image::gremlin-fade.png[width=350]

The `repeat()`-step (*branch*) is used for looping over a traversal given some break predicate. Below are some examples of `repeat()`-step in action.

[gremlin-groovy,modern]
----
g.V(1).repeat(out()).times(2).path().by('name') <1>
g.V().until(has('name','ripple')).
      repeat(out()).path().by('name') <2>
----

<1> do-while semantics stating to do `out()` 2 times.
<2> while-do semantics stating to break if the traverser is at a vertex named "ripple".

IMPORTANT: There are two modulators for `repeat()`: `until()` and `emit()`. If `until()` comes after `repeat()` it is do/while looping. If `until()` comes before `repeat()` it is while/do looping. If `emit()` is placed after `repeat()`, it is evaluated on the traversers leaving the repeat-traversal. If `emit()` is placed before `repeat()`, it is evaluated on the traversers prior to entering the repeat-traversal.

The `repeat()`-step also supports an "emit predicate", where the predicate for an empty argument `emit()` is true (i.e. `emit() == emit{true}`). With `emit()`, the traverser is split in two -- the traverser exits the code block as well as continues back within the code block (assuming `until()` holds true).

[gremlin-groovy,modern]
----
g.V(1).repeat(out()).times(2).emit().path().by('name') <1>
g.V(1).emit().repeat(out()).times(2).path().by('name') <2>
----

<1> The `emit()` comes after `repeat()` and thus, emission happens after the `repeat()` traversal is executed. Thus, no one vertex paths exist.
<2> The `emit()` comes before `repeat()` and thus, emission happens prior to the `repeat()` traversal being executed. Thus, one vertex paths exist.

The `emit()`-modulator can take an arbitrary predicate.

[gremlin-groovy,modern]
----
g.V(1).repeat(out()).times(2).emit(has('lang')).path().by('name')
----

image::repeat-step.png[width=500]

[gremlin-groovy,modern]
----
g.V(1).repeat(out()).times(2).emit().path().by('name')
----

The first time through the `repeat()`, the vertices lop, vadas, and josh are seen. Given that `loops==0`, the traverser repeats. However, because the emit-predicate is declared true, those vertices are emitted. At step 2 (`loops==1`), the vertices traversed are ripple and lop (Josh's created projects, as lop and vadas have no out edges) and are also emitted. Now `loops==1` so the traverser repeats. As ripple and lop have no out edges there are no vertices to traverse. Given that `loops==2`, the until-predicate fails. Therefore, the traverser has seen the vertices: lop, vadas, josh, ripple, and lop.

Finally, note that both `emit()` and `until()` can take a traversal and in such, situations, the predicate is determined by `traversal.hasNext()`. A few examples are provided below.

[gremlin-groovy,modern]
----
g.V(1).repeat(out()).until(hasLabel('software')).path().by('name') <1>
g.V(1).emit(hasLabel('person')).repeat(out()).path().by('name') <2>
g.V(1).repeat(out()).until(outE().count().is(0L)).path().by('name') <3>
----

<1> Starting from vertex 1, keep taking outgoing edges until a software vertex is reached.
<2> Starting from vertex 1, and in an infinite loop, emit the vertex if it is a person and then traverser the outgoing edges.
<3> Starting from vertex 1, keep taking outgoing edges until a vertex is reached that has no more outgoing edges.

WARNING: The anonymous traversal of `emit()` and `until()` (not `repeat()`) process their current objects "locally." In OLAP, where the atomic unit of computing is the the vertex and its local "star graph," it is important that the anonymous traversals do not leave the confines of the vertex's star graph. In other words, they can not traverse to an adjacent vertex's properties or edges.

[[sack-step]]
Sack Step
~~~~~~~~~

image:gremlin-sacks-running.png[width=175,float=right] A traverser can contain a local data structure called a "sack". The `sack()`-step is used to read and write sacks (*sideEffect* or *map*). Each sack of each traverser is created when using `GraphTraversal.withSack(initialValueSupplier,splitOperator?)`.

* *Initial value supplier*: A `Supplier` providing the initial value of each traverser's sack.
* *Split operator*: a `UnaryOperator` that clones the traverser's sack when the traverser splits. If no split operator is provided, then `UnaryOperator.identity()` is assumed.

Two trivial examples are presented below to demonstrate the *initial value supplier*. In the first example below, a traverser is created at each vertex in the graph (`g.V()`), with a 1.0 sack (`withSack(1.0f)`), and then the sack value is accessed (`sack()`). In the second example, a random float supplier is used to generate sack values.

[gremlin-groovy,modern]
----
g.withSack(1.0f).V().sack()
rand = new Random()
g.withSack {rand.nextFloat()}.V().sack()
----

A more complicated initial value supplier example is presented below where the sack values are used in a running computation and then emitted at the end of the traversal. When an edge is traversed, the edge weight is multiplied by the sack value (`sack(mult,'weight')`).

[gremlin-groovy,modern]
----
g.withSack(1.0f).V().repeat(outE().sack(mult,'weight').inV()).times(2)
g.withSack(1.0f).V().repeat(outE().sack(mult,'weight').inV()).times(2).sack()
g.withSack(1.0f).V().repeat(outE().sack(mult,'weight').inV()).times(2).path().
      by().by('weight')
----

image:gremlin-sacks-standing.png[width=100,float=left] When complex objects are used (i.e. non-primitives), then a *split operator* should be defined to ensure that each traverser gets a clone of its parent's sack. The first example does not use a split operator and as such, the same map is propagated to all traversers (a global data structure). The second example, demonstrates how `Map.clone()` ensures that each traverser's sack contains a unique, local sack.

[gremlin-groovy,modern]
----
g.withSack {[:]}.V().out().out().
      sack {m,v -> m[v.value('name')] = v.value('lang'); m}.sack() // BAD: single map
g.withSack {[:]}{it.clone()}.V().out().out().
      sack {m,v -> m[v.value('name')] = v.value('lang'); m}.sack() // GOOD: cloned map
----

NOTE: For primitives (i.e. integers, longs, floats, etc.), a split operator is not required as a primitives are encoded in the memory address of the sack, not as a reference to an object.

[[sample-step]]
Sample Step
~~~~~~~~~~~

The `sample()`-step is useful for sampling some number of traversers previous in the traversal.

[gremlin-groovy,modern]
----
g.V().outE().sample(1).values('weight')
g.V().outE().sample(1).by('weight').values('weight')
g.V().outE().sample(2).by('weight').values('weight')
----

One of the more interesting use cases for `sample()` is when it is used in conjunction with <<local-step,`local()`>>. The combination of the two steps supports the execution of link:http://en.wikipedia.org/wiki/Random_walk[random walks]. In the example below, the traversal starts are vertex 1 and selects one edge to traverse based on a probability distribution generated by the weights of the edges. The output is always a single path as by selecting a single edge, the traverser never splits and continues down a single path in the graph.

[gremlin-groovy,modern]
----
g.V(1).repeat(local(
         bothE().sample(1).by('weight').otherV()
       )).times(5)
g.V(1).repeat(local(
         bothE().sample(1).by('weight').otherV()
       )).times(5).path()
g.V(1).repeat(local(
         bothE().sample(1).by('weight').otherV()
       )).times(10).path()
----

[[select-step]]
Select Step
~~~~~~~~~~~

link:http://en.wikipedia.org/wiki/Functional_programming[Functional languages] make use of function composition and lazy evaluation to create complex computations from primitive operations. This is exactly what `Traversal` does. One of the differentiating aspects of Gremlin's data flow approach to graph processing is that the flow need not always go "forward," but in fact, can go back to a previously seen area of computation. Examples include <<path-step,`path()`>> as well as the `select()`-step (*map*). There are two general ways to use `select()`-step.

. Select labeled steps within a path (as defined by `as()` in a traversal).
. Select objects out of a `Map<String,Object>` flow (i.e. a sub-map).

The first use case is demonstrated via example below.

[gremlin-groovy,modern]
----
g.V().as('a').out().as('b').out().as('c') // no select
g.V().as('a').out().as('b').out().as('c').select()
g.V().as('a').out().as('b').out().as('c').select('a','b')
g.V().as('a').out().as('b').out().as('c').select('a','b').by('name')
g.V().as('a').out().as('b').out().as('c').select('a') <1>
----

<1> If the selection is one step, no map is returned.

When there is only one label selected, then a single object is returned. This is useful for stepping back in a computation and easily moving forward again on the object reverted to.

[gremlin-groovy,modern]
----
g.V().out().out()
g.V().out().out().path()
g.V().as('x').out().out().select('x')
g.V().out().as('x').out().select('x')
g.V().out().out().as('x').select('x') // pointless
----

The second use case is best understood in terms of <<match-step,`match()`>>-step where the result of `match()` is a `Map<String,Object>` of variable bindings. However, any step that emits a `Map<String,Object>` can be selected. A contrived example is presented below.

[gremlin-groovy,modern]
----
g.V().range(0, 2).as('a').map {[b:1,c:2]} <1>
g.V().range(0, 2).as('a').map {[b:1,c:2]}.select(local) <2>
g.V().range(0, 2).as('a').map {[b:1,c:2]}.select(local,'a','c') <3>
g.V().range(0, 2).as('a').map {[b:1,c:2]}.select(local,'c') <4>
----

<1> A contrived example to create a `Map<String,Object>` flow as a foundation for the examples to follow.
<2> Select will grab both labeled steps and `Map<String,Object>` entries.
<3> The same `List<String>` selectivity can be used as demonstrated in the previous example.
<4> If a single selection is used, then the object is emitted not wrapped in a map. Useful for continuing the traversal process without having to do a map projection.

NOTE: When executing a traversal with `select()` on a standard traversal engine (i.e. OLTP), `select()` will do its best to avoid calculating the path history and instead, will rely on a global data structure for storing the currently selected object. As such, if only a subset of the path walked is required, `select()` should be used over the more resource intensive <<path-step,`path()`>>-step.

[[using-where-with-select]]
Using Where with Select
^^^^^^^^^^^^^^^^^^^^^^^

Finally, like <<match-step,`match()`>>-step, it is possible to use `where()`, as where is a filter that processes `Map<String,Object>` streams.

[gremlin-groovy,modern]
----
g.V().as('a').out('created').in('created').as('b').select().by('name') <1>
g.V().as('a').out('created').in('created').as('b').
      select().by('name').where('a',neq('b')) <2>
g.V().as('a').out('created').in('created').as('b').
      select(). <3>
      where('a',neq('b')).
      where(__.as('a').out('knows').as('b')).
      select().by('name')
----

<1> A standard `select()` that generates a `Map<String,Object>` of variables bindings in the path (i.e. `a` and `b`) for the sake of a running example.
<2> The `select().by('name')` projects each binding vertex to their name property value and `where()` operates to ensure respective `a` and `b` strings are not the same.
<3> The first `select()` projects a vertex binding set. A binding is filtered if `a` vertex equals `b` vertex. A binding is filtered if `a` doesn't know `b`. The second and final `select()` projects the name of the vertices.

[[simplepath-step]]
SimplePath Step
~~~~~~~~~~~~~~~

image::simplepath-step.png[width=400]

When it is important that a traverser not repeat its path through the graph, `simplePath()`-step should be used (*filter*). The <<path-data-structure,path>> information of the traverser is analyzed and if the path has repeated objects in it, the traverser is filtered. If cyclic behavior is desired, see <<cyclicpath-step,`cyclicPath()`>>.

[gremlin-groovy,modern]
----
g.V(1).both().both()
g.V(1).both().both().simplePath()
g.V(1).both().both().simplePath().path()
----

[[store-step]]
Store Step
~~~~~~~~~~

When link:http://en.wikipedia.org/wiki/Lazy_evaluation[lazy] aggregation is needed, `store()`-step (*sideEffect*) should be used over <<aggregate-step,`aggregate()`>>. The two steps differ in that `store()` does not block and only stores objects in its side-effect collection as they pass through.

[gremlin-groovy,modern]
----
g.V().aggregate('x').limit(1).cap('x')
g.V().store('x').limit(1).cap('x')
----

It is interesting to note that there are three results in the `store()` side-effect even though the interval selection is for 2 objects. Realize that when the third object is on its way to the `range()` filter (i.e. `[0..1]`), it passes through `store()` and thus, stored before filtered.

[gremlin-groovy,modern]
----
g.E().store().by('weight')
----

[[subgraph-step]]
Subgraph Step
~~~~~~~~~~~~~

image::subgraph-logo.png[width=380]

Extracting a portion of a graph from a larger one for analysis, visualization or other purposes is a fairly common use case for graph analysts and developers. The `subgraph()`-step (*sideEffect*) provides a way to produce an link:http://mathworld.wolfram.com/Edge-InducedSubgraph.html[edge-induced subgraph] from virtually any traversal.  The following example demonstrates how to produce the "knows" subgraph:

[gremlin-groovy,modern]
----
subGraph = g.E().hasLabel('knows').subgraph('subGraph').cap('subGraph').next() <1>
sg = subGraph.traversal(standard())
sg.E() <2>
----

<1> As this function produces "edge-induced" subgraphs, `subgraph()` must be called at edge steps.
<2> The subgraph contains only "knows" edges.

A more common subgraphing use case is to get all of the graph structure surrounding a single vertex:

[gremlin-groovy,modern]
----
subGraph = g.V(3).repeat(__.inE().subgraph('subGraph').outV()).times(3).cap('subGraph').next()  <1>
sg = subGraph.traversal(standard())
sg.E()
----

<1> Starting at vertex `3`, traverse 3 steps away on in-edges, outputting all of that into the subgraph.

There can be multiple `subgraph()` calls within the same traversal. Each operating against either the same graph (i.e. same side-effect key) or different graphs (i.e. different side-effect keys).

[gremlin-groovy,modern]
----
t = g.V().outE('knows').subgraph('knowsG').inV().outE('created').subgraph('createdG').
          inV().inE('created').subgraph('createdG').iterate()
t.sideEffects.get('knowsG').get().traversal(standard()).E()
t.sideEffects.get('createdG').get().traversal(standard()).E()
----

IMPORTANT: The `subgraph()`-step only writes to graphs that support user supplied ids for its elements. Moreover, if no graph is specified via `withSideEffect()`, then <<tinkergraph-gremlin,TinkerGraph>> is assumed.

[[sum-step]]
Sum Step
~~~~~~~~

The `sum()`-step (*map*) operates on a stream of numbers and sums the numbers together to yield a double. Note that the current traverser number is multiplied by the traverser bulk to determine how many such numbers are being represented.

[gremlin-groovy,modern]
----
g.V().values('age').sum()
g.V().repeat(both()).times(3).values('age').sum()
----

IMPORTANT: `sum(local)` determines the sum of the current, local object (not the objects in the traversal stream). This works for `Collection`-type objects. For any other object, a sum of `Double.NaN` is returned.

[[timelimit-step]]
TimeLimit Step
~~~~~~~~~~~~~~

In many situations, a graph traversal is not about getting an exact answer as its about getting a relative ranking. A classic example is link:http://en.wikipedia.org/wiki/Recommender_system[recommendation]. What is desired is a relative ranking of vertices, not their absolute rank. Next, it may be desirable to have the traversal execute for no more than 2 milliseconds. In such situations, `timeLimit()`-step (*filter*) can be used.

image::timelimit-step.png[width=400]

NOTE: The method `clock(int runs, Closure code)` is a utility preloaded in the <<gremlin-console,Gremlin Console>> that can be used to time execution of a body of code.

[gremlin-groovy,modern]
----
g.V().repeat(both().groupCount('m')).times(16).cap('m').order(local).by(valueDecr).next()
clock(1) {g.V().repeat(both().groupCount('m')).times(16).cap('m').order(local).by(valueDecr).next()}
g.V().repeat(timeLimit(2).both().groupCount('m')).times(16).cap('m').order(local).by(valueDecr).next()
clock(1) {g.V().repeat(timeLimit(2).both().groupCount('m')).times(16).cap('m').order(local).by(valueDecr).next()}
----

In essence, the relative order is respected, even through the number of traversers at each vertex is not. The primary benefit being that the calculation is guaranteed to complete at the specified time limit (in milliseconds). Finally, note that the internal clock of `timeLimit()`-step starts when the first traverser enters it. When the time limit is reached, any `next()` evaluation of the step will yield a `NoSuchElementException` and any `hasNext()` evaluation will yield `false`.

[[tree-step]]
Tree Step
~~~~~~~~~

From any one element (i.e. vertex or edge), the emanating paths from that element can be aggregated to form a link:http://en.wikipedia.org/wiki/Tree_(data_structure)[tree]. Gremlin provides `tree()`-step (*sideEffect*) for such this situation.

image::tree-step.png[width=450]

[gremlin-groovy,modern]
----
tree = g.V().out().out().tree().next()
----

It is important to see how the paths of all the emanating traversers are united to form the tree.

image::tree-step2.png[width=500]

The resultant tree data structure can then be manipulated (see link:http://www.tinkerpop.com/javadocs/current/org/apache/tinkerpop/gremlin/process/graph/step/util/Tree.html[Tree JavaDoc]). For the sake of demonstration, a post-processing lambda is applied in the running example below.

[gremlin-groovy,modern]
----
tree = g.V().out().out().tree().by('name').next()
tree['marko']
tree['marko']['josh']
tree.getObjectsAtDepth(3)
----

[[unfold-step]]
Unfold Step
~~~~~~~~~~~

If the object reaching `unfold()` (*flatMap*) is an iterator, iterable, or map, then it is unrolled into a linear form. If not, then the object is simply emitted. Please see <<fold-step,`fold()`>>-step for the inverse behavior.

[gremlin-groovy,modern]
----
g.V(1).out().fold().inject('gremlin',[1.23,2.34])
g.V(1).out().fold().inject('gremlin',[1.23,2.34]).unfold()
----

Note that `unfold()` does not recursively unroll iterators. Instead, `repeat()` can be used to for recursive unrolling.

[gremlin-groovy,modern]
----
inject(1,[2,3,[4,5,[6]]])
inject(1,[2,3,[4,5,[6]]]).unfold()
inject(1,[2,3,[4,5,[6]]]).repeat(unfold()).until(unfold().count().is(1l)).unfold()
----

[[union-step]]
Union Step
~~~~~~~~~~

image::union-step.png[width=650]

The `union()`-step (*branch*) supports the merging of the results of an arbitrary number of traversals. When a traverser reaches a `union()`-step, it is copied to each of its internal steps. The traversers emitted from `union()` are the outputs of the respective internal traversals.

[gremlin-groovy,modern]
----
g.V(4).union(
         __.in().values('age'),
         out().values('lang'))
g.V(4).union(
         __.in().values('age'),
         out().values('lang')).path()
----

[[valuemap-step]]
ValueMap Step
~~~~~~~~~~~~~

The `valueMap()`-step yields a Map representation of the properties of an element.

[gremlin-groovy,modern]
----
g.V().valueMap()
g.V().valueMap('age')
g.V().valueMap('age','blah')
g.E().valueMap()
----

It is important to note that the map of a vertex maintains a list of values for each key. The map of an edge or vertex-property represents a single property (not a list). The reason is that vertices in TinkerPop3 leverage <<vertex-properties,vertex properties>> which are support multiple values per key. Using the <<the-crew-toy-graph,"The Crew">> toy graph, the point is made explicit.

[gremlin-groovy,theCrew]
----
g.V().valueMap()
g.V().has('name','marko').properties('location')
g.V().has('name','marko').properties('location').valueMap()
----

If the `id`, `label`, `key`, and `value` of the `Element` is desired, then a boolean triggers its insertion into the returned map.

[gremlin-groovy,theCrew]
----
g.V().hasLabel('person').valueMap(true)
g.V().hasLabel('person').valueMap(true,'name')
g.V().hasLabel('person').properties('location').valueMap(true)
----

[[vertex-steps]]
Vertex Steps
~~~~~~~~~~~~

image::vertex-steps.png[width=350]

The vertex steps (*flatMap*) are fundamental to the Gremlin language. Via these steps, its possible to "move" on the graph -- i.e. traverse.

* `out(string...)`: Move to the outgoing adjacent vertices given the edge labels.
* `in(string...)`: Move to the incoming adjacent vertices given the edge labels.
* `both(string...)`: Move to both the incoming and outgoing adjacent vertices given the edge labels.
* `outE(string...)`: Move to the outgoing incident edges given the edge labels.
* `inE(string...)`: Move to the incoming incident edges given the edge labels.
* `bothE(string...)`: Move to both the incoming and outgoing incident edges given the edge labels.
* `outV()`: Move to the outgoing vertex.
* `inV()`: Move to the incoming vertex.
* `bothV()`: Move to both vertices.
* `otherV()` : Move to the vertex that was not the vertex that was moved from.

[gremlin-groovy,modern]
----
g.V(4)
g.V(4).outE() <1>
g.V(4).inE('knows') <2>
g.V(4).inE('created') <3>
g.V(4).bothE('knows','created','blah')
g.V(4).bothE('knows','created','blah').otherV()
g.V(4).both('knows','created','blah')
g.V(4).outE().inV() <4>
g.V(4).out() <5>
g.V(4).inE().outV()
g.V(4).inE().bothV()
----

<1> All outgoing edges.
<2> All incoming knows-edges.
<3> All incoming created-edges.
<4> Moving forward touching edges and vertices.
<5> Moving forward only touching vertices.

[[where-step]]
Where Step
~~~~~~~~~~

The `where()`-step filters the current object based on either the object itself (`Scope.local`) or the path history of the object (`Scope.global`) (*filter*). This step is typically used in conjuction with either <<match-step,`match()`>>-step or <<select-step,`select()`>>-step, but can be used in isolation.

[gremlin-groovy,modern]
----
g.V(1).as('a').out('created').in('created').where(neq('a')) <1>
g.withSideEffect('a'){['josh','peter']}.V(1).out('created').in('created').values('name').where(within('a')) <2>
g.V(1).out('created').in('created').where(out('created').count().is(gt(1))).values('name') <3>
----

<1> Who are marko's collaborators, where marko can not be his own collaborator? (predicate)
<2> Of the co-creators of marko, only keep those whose name is josh or peter. (using a sideEffect)
<3> Which of marko's collaborators have worked on more than 1 project? (using a traversal)

IMPORTANT: Please see <<using-where-with-match,`match().where()`>> and <<using-where-with-select,`select().where()`>> for how `where()` can be used in conjunction with `Map<String,Object>` projecting steps -- i.e. `Scope.local`.

[[a-note-on-barrier-steps]]
A Note on Barrier Steps
-----------------------

image:barrier.png[width=165,float=right] Gremlin is primarily a link:http://en.wikipedia.org/wiki/Lazy_evaluation[lazy], stream processing language. This means that Gremlin fully processes (to the best of its abilities) any traversers currently in the traversal pipeline before getting more data from the start/head of the traversal. However, there are numerous situations in which a completely lazy computation is not possible (or impractical). When a computation is not lazy, a "barrier step" exists. There are three types of barriers:

  . `CollectingBarrierStep`: All of the traversers prior to the step are put into a collection and then processed in some way (e.g. ordered) prior to the collection being "drained" one-by-one to the next step. Examples include: <<order-step,`order()`>>, <<sample-step,`sample()`>>, <<aggregate-step,`aggregate()`>>.
  . `ReducingBarrierStep`: All of the traversers prior to the step are processed by a reduce function and once all the previous traversers are processed, a single "reduced value" traverser is emitted to the next step. Examples include: <<fold-step,`fold()`>>, <<count-step,`count()`>>, <<sum-step,`sum()`>>, <<max-step,`max()`>>, <<min-step,`min()`>>.
  . `SupplyingBarrierStep`: All of the traversers prior to the step are iterated (no processing) and then some provided supplier yields a single traverser to continue to the next step. Examples include: <<cap-step,`cap()`>>.

In Gremlin OLAP (see <<traversalvertexprogram,`TraversalVertexProgram`>>), a barrier is introduced at the end of every <<vertex-steps,adjacent vertex step>>. This means that the traversal does its best to compute as much as possible at the current, local vertex. What is can't compute without referencing an adjacent vertex is aggregated into a barrier collection. When there are no more traversers at the local vertex, the barriered traversers are the messages that are propagated to remote vertices for further processing.

[[a-note-on-lambdas]]
A Note On Lambdas
-----------------

image:lambda.png[width=150,float=right] A link:http://en.wikipedia.org/wiki/Anonymous_function[lambda] is a function that can be referenced by software and thus, passed around like any other piece of data. In Gremlin, lambdas make it possible to generalize the behavior of a step such that custom steps can be created (on-the-fly) by the user. However, it is advised to avoid using lambdas if possible.

[gremlin-groovy,modern]
----
g.V().filter{it.get().value('name') == 'marko'}.
      flatMap{it.get().vertices(OUT,'created')}.
      map {it.get().value('name')} <1>
g.V().has('name','marko').out('created').values('name') <2>
----

<1> A lambda-rich Gremlin traversal which should and can be avoided. (*bad*)
<2> The same traversal (result), but without using lambdas. (*good*)

Gremlin attempts to provide the user a comprehensive collection of steps in the hopes that the user will never need to leverage a lambda in practice. It is advised that users only leverage a lambda if and only if there is no corresponding lambda-less step that encompasses the desired functionality. The reason being, lambdas can not be optimized by Gremlin's compiler strategies as they can not be programmatically inspected (see <<traversalstrategy,traversal strategies>>).

In many situations where a lambda could be used, either a corresponding step exists or a traversal can be provided in its place. A `TraversalLambda` behaves like a typical lambda, but it can be optimized and it yields less objects than the corresponding pure-lambda form.

[gremlin-groovy,modern]
----
g.V().out().out().path().by {it.value('name')}.
                         by {it.value('name')}.
                         by {g.V(it).in('created').values('name').fold().next()} <1>
g.V().out().out().path().by('name').
                         by('name').
                         by(__.in('created').values('name').fold()) <2>
----

<1> The length-3 paths have each of their objects transformed by a lambda. (*bad*)
<2> The length-3 paths have their objects transformed by a lambda-less step and a traversal lambda. (*good*)

[[traversalstrategy]]
TraversalStrategy
-----------------

image:traversal-strategy.png[width=125,float=right] A `TraversalStrategy` can analyze a `Traversal` and mutate the traversal as it deems fit. This is useful in multiple situations:

 * There is an application-level feature that can be embedded into the traversal logic (*decoration*).
 * There is a more efficient way to express the traversal at the TinkerPop3 or graph vendor level (*optimization*).
 * There are are some final adjustments required before executing the traversal (*finalization*).
 * There are certain traversals that are not legal for the application or traversal engine (*verification*).

A simple `OptimizationStrategy` is the `IdentityRemovalStrategy`.

[source,java]
----
public class IdentityRemovalStrategy extends AbstractTraversalStrategy<TraversalStrategy.OptimizationStrategy> implements TraversalStrategy.OptimizationStrategy {

    private static final IdentityRemovalStrategy INSTANCE = new IdentityRemovalStrategy();

    private IdentityRemovalStrategy() {
    }

    @Override
    public void apply(final Traversal.Admin<?, ?> traversal) {
        if (!TraversalHelper.hasStepOfClass(IdentityStep.class, traversal))
            return;
        TraversalHelper.getStepsOfClass(IdentityStep.class, traversal).stream()
                .filter(step -> !TraversalHelper.isLabeled(step))
                .forEach(step -> traversal.removeStep(step));
    }

    public static IdentityRemovalStrategy instance() {
        return INSTANCE;
    }
}
----

This strategy simply removes any unlabeled `IdentityStep` steps in the Traversal as `aStep().identity().identity().bStep()` is equivalent to `aStep().bStep()`. For those traversal strategies that require other strategies to execute prior or post to the strategy, then the following two methods can be defined in `TraversalStrategy` (with defaults being an empty set). If the `TraversalStrategy` is in a particular traversal category (i.e. decoration, optimization, finalization, or verification), then priors and posts are only possible within the category.

[source,java]
public Set<Class<? extends S>> applyPrior();
public Set<Class<? extends S>> applyPost();

IMPORTANT: `TraversalStrategy` categories are sorted within their category and the categories are then executed in the following order: decoration, optimization, finalization, and verification. If a designed strategy does not fit cleanly into these categories, then it can implement `TraversalStrategy` and its prior and posts can reference strategies within any category.

Another example `OptimizationStrategy` in action is provided below.

[source,groovy]
g.V().has('name','marko')

The expression above can be executed in a `O(|V|)` or `O(log(|V|)` fashion in <<tinkergraph-gremlin,TinkerGraph>> depending on whether there is or is not an index defined for "name."

[source,java]
----
public final class TinkerGraphStepStrategy extends AbstractTraversalStrategy<TraversalStrategy.OptimizationStrategy> implements TraversalStrategy.OptimizationStrategy {

    private static final TinkerGraphStepStrategy INSTANCE = new TinkerGraphStepStrategy();
    private static final Set<Class<? extends OptimizationStrategy>> PRIORS = new HashSet<>();

    static {
        PRIORS.add(IdentityRemovalStrategy.class);
    }

    private TinkerGraphStepStrategy() {
    }

    @Override
    public void apply(final Traversal.Admin<?, ?> traversal) {
        if (traversal.getEngine().isComputer())
            return;

        final Step<?, ?> startStep = traversal.getStartStep();
        if (startStep instanceof GraphStep) {
            final GraphStep<?> originalGraphStep = (GraphStep) startStep;
            final TinkerGraphStep<?> tinkerGraphStep = new TinkerGraphStep<>(originalGraphStep);
            TraversalHelper.replaceStep(startStep, (Step) tinkerGraphStep, traversal);

            Step<?, ?> currentStep = tinkerGraphStep.getNextStep();
            while (true) {
                if (currentStep instanceof HasContainerHolder) {
                    tinkerGraphStep.hasContainers.addAll(((HasContainerHolder) currentStep).getHasContainers());
                    currentStep.getLabels().forEach(tinkerGraphStep::addLabel);
                    traversal.removeStep(currentStep);
                } else {
                    break;
                }
                currentStep = currentStep.getNextStep();
            }
        }
    }

    @Override
    public Set<Class<? extends OptimizationStrategy>> applyPrior() {
        return PRIORS;
    }

    public static TinkerGraphStepStrategy instance() {
        return INSTANCE;
    }
}
----

The traversal is redefined by simply taking a chain of `has()`-steps after `g.V()` (`TinkerGraphStep`) and providing them to `TinkerGraphStep`. Then its up to TinkerGraphStep to determine if an appropriate index exists. In the code below, review the `vertices()` method and note how if an index exists, for a particular `HasContainer`, then that index is first queried before the remaining `HasContainer` filters are serially applied.

[gremlin-groovy,modern]
----
t = g.V().has('name','marko'); null
t.toString()
t.iterate(); null
t.toString()
----

A collection of useful `DecorationStrategy` strategies are provided with TinkerPop3 and are generally useful to end-users.  The following sub-sections detail these strategies:

ElementIdStrategy
~~~~~~~~~~~~~~~~~

`ElementIdStrategy` provides control over element identifiers. Some Graph implementations, such as TinkerGraph, allow specification of custom identifiers when creating elements:

[gremlin-groovy]
----
g = TinkerGraph.open().traversal()
v = g.addV(id,'42a')
g.V('42a')
----

Other `Graph` implementations, such as Neo4j, generate element identifiers automatically and cannot be assigned.  As a helper, `ElementIdStrategy` can be used to make identifier assignment possible by using vertex and edge indicies under the hood.

[source,groovy]
----
gremlin> graph = Neo4jGraph.open('/tmp/neo4j')
==>neo4jgraph[EmbeddedGraphDatabase [/tmp/neo4j]]
gremlin> strategy = ElementIdStrategy.build().create()
==>ElementIdStrategy
gremlin> g = GraphTraversalSource.build().with(strategy).create(graph)
==>graphtraversalsource[neo4jgraph[EmbeddedGraphDatabase [/tmp/neo4j]], standard]
gremlin> g.addV(id, '42a').id()
==>42a
----

IMPORTANT: The key that is used to store the assigned identifier should be indexed in the underlying graph database. If it is not indexed, then lookups for the elements that use these identifiers will perform a linear scan.

EventStrategy
~~~~~~~~~~~~~

The purpose of the `EventStrategy` is to raise events to one or more `MutationListener` objects as changes to the underlying `Graph` occur within a `Traversal`. Such a strategy is useful for logging changes, triggering certain actions based on change, or any application that needs notification of some mutating operation during a `Traversal`.  Graphs that do not support transactions will generate events immediately upon mutation, while those graphs that support transactions will queue the mutations until that transaction is committed and will then raise the events.  If the transaction is rolled back, the event queue is reset.

The following events are raised to the `MutationListener`:

* New vertex
* New edge
* Vertex property changed
* Edge property changed
* Vertex property removed
* Edge property removed
* Vertex removed
* Edge removed

To start processing events from a `Traversal` first implement the `MutationListener` interface. An example of this implementation is the `ConsoleMutationListener` which writes output to the console for each event.  The following console session displays the basic usage:

[gremlin-groovy]
----
graph = TinkerFactory.createModern()
l = new ConsoleMutationListener(graph)
strategy = EventStrategy.build().addListener(l).create()
g = GraphTraversalSource.build().with(strategy).create(graph)
g.addV('name','stephen')
g.E().drop()
----

The example above uses TinkerGraph which does not support transactions.  As mentioned previously, for these types of graph implementations events are raised as they occur within execution of a `Step`.  As such, the final line of Gremlin execution that drops all edges shows a bit of an inconsistent count, where the removed edge count is accounted for after the event is raised.

CAUTION: `EventStrategy` is not meant for usage in tracking global mutations across separate processes.  In other words, an mutation in what JVM process is not raised as an event in a different JVM process.  In addition, events are not raised when mutations occur outside of the `Traversal` context.

PartitionStrategy
~~~~~~~~~~~~~~~~~

image::partition-graph.png[width=325]

`PartitionStrategy` partitions the vertices and edges of a graph into `String` named partitions (i.e. buckets, subgraphs, etc.). The idea behind `PartitionStrategy` is presented in the image above where each element is in a single partition (represented by its color). Partitions can be read from, written to, and linked/joined by edges that span one or two partitions (e.g. a tail vertex in one partition and a head vertex in another).

There are three primary variables in `PartitionStrategy`:

. Partition Key - The property key that denotes a String value representing a partition.
. Write Partition - A `String` denoting what partition all future written elements will be in.
. Read Partitions - A `Set<String>` of partitions that can be read from.

The best way to understand `PartitionStrategy` is via example.

[gremlin-groovy]
----
graph = TinkerFactory.createModern()
strategyA = PartitionStrategy.build().partitionKey("_partition").writePartition("a").addReadPartition("a").create()
strategyB = PartitionStrategy.build().partitionKey("_partition").writePartition("b").addReadPartition("b").create()
gA = GraphTraversalSource.build().with(strategyA).create(graph)
gA.addV() // this vertex has a property of {_partition:"a"}
gB = GraphTraversalSource.build().with(strategyB).create(graph)
gB.addV() // this vertex has a property of {_partition:"b"}
gA.V()
gB.V()
----

By writing elements to particular partitions and then restricting read partitions, the developer is able to create multiple graphs within a single address space. Moreover, by supporting references between partitions, it is possible to merge those multiple graphs (i.e. join partitions).

ReadOnlyStrategy
~~~~~~~~~~~~~~~~

`ReadOnlyStrategy` is largely self-explanatory.  A `Traversal` that has this strategy applied will throw an `IllegalStateException` if the `Traversal` has any mutating steps within it.

SubgraphStrategy
~~~~~~~~~~~~~~~~

`SubgraphStrategy` is quite similar to `PartitionStrategy` in that it restrains a `Traversal` to certain vertices and edges as determined by a `Predicate` defined individually for each.

[gremlin-groovy]
----
graph = TinkerFactory.createModern()
vertexCriterion = { vertex -> true }
edgeCriterion = { edge -> edge.id() >= 8 && edge.id() <= 10}
strategy = SubgraphStrategy.build().vertexPredicate(vertexCriterion).edgePredicate(edgeCriterion).create()
g = GraphTraversalSource.build().with(strategy).create(graph)
g.V() // shows all vertices as they all pass the vertexCriterion
g.E() // shows only the edges defined in the edgeCriterion
----

Note that `SubgraphStrategy` directly passes the edge and vertex criterion `Predicate` objects  to an injected `filter` step and as such may not take advantage of important optimizations provided by the various `Graph` implementations (given the use of lambda expressions).