You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2015/11/22 06:59:21 UTC

[06/22] incubator-tinkerpop git commit: Made subdirectories for various "books" in the docs.

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/bc46d649/docs/src/reference/the-traversal.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
new file mode 100644
index 0000000..0b82823
--- /dev/null
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -0,0 +1,2378 @@
+////
+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>` is spawned from a `GraphTraversalSource`. 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://tinkerpop.incubator.apache.org/javadocs/3.0.2-incubating/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/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()`. Be aware of language-specific reserved keywords
+when using anonymous traversals. For example, `in` and `as` are reserved keywords in Groovy, therefore you must use
+the verbose syntax `__.in()` and `__.as()` to avoid collisions.
+
+[[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 t
+heir 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
+~~~~~~~~~~~~
+
+link:http://en.wikipedia.org/wiki/Automated_reasoning[Reasoning] is the process of making explicit what 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 determined by the
+traversal definition. 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. Moreover, what was once implicit can be made explicit via the `addE()`-step
+(*map*/*sideEffect*).
+
+image::addedge-step.png[width=450]
+
+[gremlin-groovy,modern]
+----
+g.V(1).as('a').out('created').in('created').where(neq('a')).
+  addE('co-developer').from('a').property('year',2009) <1>
+g.V(3,4,5).aggregate('x').has('name','josh').as('a').
+  select('x').unfold().hasLabel('software').addE('createdBy').to('a') <2>
+g.V().as('a').out('created').addE('createdBy').to('a').property('acl','public') <3>
+g.V(1).as('a').out('knows').
+  addE('livesNear').from('a').property('year',2009).
+  inV().inE('livesNear').values('year') <4>
+g.V().match(
+        __.as('a').out('knows').as('b'),
+        __.as('a').out('created').as('c'),
+        __.as('b').out('created').as('c')).
+      addE('friendlyCollaborator').from('a').to('b').
+        property(id,13).property('project',select('c').values('name')) <5>
+g.E(13).valueMap()
+----
+
+<1> Add a co-developer edge with a year-property between marko and his collaborators.
+<2> Add incoming createdBy edges from the josh-vertex to the lop- and ripple-vertices.
+<3> Add an inverse createdBy edge for all created edges.
+<4> The newly created edge is a traversable object.
+<5> Two arbitrary bindings in a traversal can be joined `from()`->`to()`, where `id` can be provided for graphs that
+supports user provided ids.
+
+[[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('person').property('name','stephen')
+g.V().values('name')
+g.V().outE('knows').addV().property('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. Moreover, if `property()` follows an `addV()` or `addE()`, then it is "folded" into the
+previous step to enable vertex and edge creation with all its properties in one creation operation.
+
+[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)  <1>
+g.V(1).valueMap()
+g.V(1).property('friendWeight',outE('knows').values('weight').sum(),'acl','private') <2>
+g.V(1).properties('friendWeight').valueMap() <3>
+----
+
+<1> For vertices, a cardinality can be provided for <<vertex properties,vertex-properties>>.
+<2> It is possible to select the property value (as well as key) via a traversal.
+<3> For vertices, the `property()`-step can add meta-properties.
+
+
+[[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('x').cap('x')
+g.V().out('knows').aggregate('x').by('name').cap('x')
+----
+
+[[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().where(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('a','b')            <1>
+g.V().as('a').out('created').as('b').select('a','b').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('a','b','c').
+     by('name').
+     by('lang').
+     by(__.in('created').values('name').fold())
+----
+
+[[barrier-step]]
+Barrier Step
+~~~~~~~~~~~~
+
+The `barrier()`-step (*barrier*) turns the the lazy traversal pipeline into a bulk-synchronous pipeline. This step is
+useful in the following situations:
+
+  * When everything prior to `barrier()` needs to be executed before moving onto the steps after the `barrier()` (i.e. ordering).
+  * When "stalling" the traversal may lead to a "bulking optimization" in traversals that repeatedly touch many of the same elements (i.e. optimizing).
+
+[gremlin-groovy,modern]
+----
+g.V().sideEffect{println "first: ${it}"}.sideEffect{println "second: ${it}"}.iterate()
+g.V().sideEffect{println "first: ${it}"}.barrier().sideEffect{println "second: ${it}"}.iterate()
+----
+
+The theory behind a "bulking optimization" is simple. If there are one million traversers at vertex 1, then there is
+no need to calculate one million `both()`-computations. Instead, represent those one million traversers as a single
+traverser with a `Traverser.bulk()` equal to one million and execute `both()` once. A bulking optimization example is
+made more salient on a larger graph. Therefore, the example below leverages the <<grateful-dead,Grateful Dead graph>>.
+
+[gremlin-groovy]
+----
+graph = TinkerGraph.open()
+graph.io(graphml()).readGraph('data/grateful-dead.xml')
+g = graph.traversal(standard())
+clockWithResult(1){g.V().both().both().both().count().next()} <1>
+clockWithResult(1){g.V().repeat(both()).times(3).count().next()} <2>
+clockWithResult(1){g.V().both().barrier().both().barrier().both().barrier().count().next()} <3>
+----
+
+<1> A non-bulking traversal where each traverser is processed.
+<2> Each traverser entering `repeat()` has its recursion bulked.
+<3> A bulking traversal where implicit traversers are not processed.
+
+If `barrier()` is provided an integer argument, then the barrier will only hold `n`-number of unique traversers in its
+barrier before draining the aggregated traversers to the next step. This is useful in the aforementioned bulking
+optimization scenario, but reduces the risk of an out-of-memory exception.
+
+The non-default `LazyBarrierStrategy` inserts `barrier()`-steps in a traversal where appropriate in order to gain the
+"bulking optimization."
+
+[gremlin-groovy]
+----
+graph = TinkerGraph.open()
+graph.io(graphml()).readGraph('data/grateful-dead.xml')
+g = graph.traversal(GraphTraversalSource.build().with(LazyBarrierStrategy.instance()).engine(StandardTraversalEngine.build()))
+clockWithResult(1){g.V().both().both().both().count().next()}
+g.V().both().both().both().count().iterate().toString()  <1>
+----
+
+<1> With `LazyBarrierStrategy` activated, `barrier()` steps are automatically inserted where appropriate.
+
+[[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(count())  <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())` will count the number of elements in each group (*traversal*).
+
+[cap-step]]
+Cap Step
+~~~~~~~~
+
+The `cap()`-step (*barrier*) iterates the traversal up to itself and emits the sideEffect referenced by the provided
+key. If multiple keys are provided, then a `Map<String,Object>` of sideEffects is emitted.
+
+[gremlin-groovy,modern]
+----
+g.V().groupCount('a').by(label).cap('a')      <1>
+g.V().groupCount('a').by(label).groupCount('b').by(outE().count()).cap('a','b')   <2>
+----
+
+<1> Group and count verticies by their label.  Emit the side effect labeled 'a', which is the group count by label.
+<2> Same as statement 1, but also emit the side effect labeled 'b' which groups vertices by the number of out edges.
+
+[[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)
+----
+
+[[constant-step]]
+Constant Step
+~~~~~~~~~~~~~
+
+To specify a constant value for a traverser, use the `constant()`-step (*map*).  This is often useful with conditional
+steps like <<choose-step,`choose()`-step>> or <<coalesce-step,`coalesce()`-step>>.
+
+[gremlin-groovy,modern]
+----
+g.V().choose(__.hasLabel('person'),
+    __.values('name'),
+    __.constant('inhuman')) <1>
+g.V().coalesce(
+    __.hasLabel('person').values('name'),
+    __.constant('inhuman')) <2>
+----
+
+<1> Show the names of people, but show "inhuman" for other vertices.
+<2> Same as statement 1 (unless there is a person vertex with no name).
+
+[[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')
+----
+
+Finally, if `dedup()` is provided an array of strings, then it will ensure that the de-duplication is not with respect
+to the current traverser object, but to the path history of the traverser.
+
+[gremlin-groovy,modern]
+----
+g.V().as('a').out('created').as('b').in('created').as('c').select('a','b','c')
+g.V().as('a').out('created').as('b').in('created').as('c').dedup('a','b').select('a','b','c') <1>
+----
+
+<1> If the current `a` and `b` combination has been seen previously, then filter the traverser.
+
+[[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()
+----
+
+[[explain-step]]
+Explain Step
+~~~~~~~~~~~~
+
+The `explain()`-step (*sideEffect*) will return a `TraversalExplanation`. A traversal explanation details how the
+traversal (prior to `explain()`) will be compiled given the registered <<traversalstrategy,traversal strategies>>.
+A `TraversalExplanation` has a `toString()` representation with 3-columns. The first column is the
+traversal strategy being applied. The second column is the traversal strategy category: [D]ecoration, [O]ptimization,
+[P]rovider optimization, [F]inalization, and [V]erification. Finally, the third column is the state of the traversal
+post strategy application. The final traversal is the resultant execution plan.
+
+[gremlin-groovy,modern]
+----
+g.V().outE().identity().inV().count().is(gt(5)).explain()
+----
+
+For traversal profiling information, please see <<profile-step,`profile()`>>-step.
+
+[[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>>.
+
+[[graph-step]]
+Graph Step
+~~~~~~~~~~
+
+The `V()`-step is usually used to start a `GraphTraversal`, but can also be used mid-traversal.
+
+[gremlin-groovy,modern]
+----
+g.V().has('name', within('marko', 'vadas', 'josh')).as('person').
+  V().has('name', within('lop', 'ripple')).addE('uses').from('person')
+----
+
+NOTE: Whether a mid-traversal `V()` uses an index or not, depends on a) whether suitable index exists and b) if the particular graph system provider implemented this functionality.
+
+[gremlin-groovy,modern]
+----
+g.V().has('name', within('marko', 'vadas', 'josh')).as('person').
+  V().has('name', within('lop', 'ripple')).addE('uses').from('person').toString() <1>
+g.V().has('name', within('marko', 'vadas', 'josh')).as('person').
+  V().has('name', within('lop', 'ripple')).addE('uses').from('person').iterate().toString() <2>
+----
+
+<1> Normally the `V()`-step will iterate over all vertices. However, graph strategies can fold `HasContainer`'s into a `GraphStep` to allow index lookups.
+<2> Whether the graph system provider supports mid-traversal `V()` index lookups or not can easily be determined by inspecting the `toString()` output of the iterated traversal. If `has` conditions were folded into the `V()`-step, an index - if one exists - will be used.
+
+[[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 (*map*/*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(count()) <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?
+
+[[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 (*map*/*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.
+
+[[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 does not have a value for the key.
+  * `hasNot(key)`: Remove the traverser if its element has a value for the key.
+  * `has(key, traversal)`: Remove the traverser if its object does not yield a result through the traversal off the property value.
+
+[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>
+g.V().has('name',within('josh','marko')).valueMap() <3>
+g.V().has('name',without('josh','marko')).valueMap() <4>
+g.V().has('name',not(within('josh','marko'))).valueMap() <5>
+----
+
+<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).
+<3> Find all vertices whose names are exact matches to any names in the the collection `[josh,marko]`, display all
+the key,value pairs for those verticies.
+<4> Find all vertices whose names are not in the collection `[josh,marko]`, display all the key,value pairs for those vertices.
+<5> Same as the prior example save using `not` on `within` to yield `without`.
+
+TinkerPop does not support a regular expression predicate, although specific graph databases that leverage TinkerPop
+may provide a partial match extension.
+
+[[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().where(__.in('created').count().is(1)).values('name') <1>
+g.V().where(__.in('created').count().is(gte(2))).values('name') <2>
+g.V().where(__.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()
+----
+
+The `limit()`-step can also be applied with `Scope.local`, in which case it operates on the incoming collection.
+The examples below use the <<the-crew-toy-graph,The Crew>> toy data set.
+
+[gremlin-groovy,theCrew]
+----
+g.V().valueMap().select('location').limit(local,2) <1>
+g.V().valueMap().limit(local, 1) <2>
+----
+
+<1> `List<String>` for each vertex containing the first two locations.
+<2> `Map<String, Object>` for each vertex, but containing only the first property value.
+
+[[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('person','location').by('name').by() <1>
+g.V().as('person').
+      local(properties('location').order().by('startTime',incr).limit(2)).value().as('location').
+      select('person','location').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*) provides a more link:http://en.wikipedia.org/wiki/Declarative_programming[declarative]
+form of graph querying based on the notion of link:http://en.wikipedia.org/wiki/Pattern_matching[pattern matching].
+With `match()`, the user provides a collection of "traversal fragments," called patterns, that have variables defined
+that must hold true throughout the duration of the `match()`. When a traverser is in `match()`, a registered
+`MatchAlgorithm` analyzes the current state of the traverser (i.e. its history based on its
+<<path-data-structure,path data>>), the runtime statistics of the traversal patterns, and returns a traversal-pattern
+that the traverser should try next. The default `MatchAlgorithm` provided is called `CountMatchAlgorithm` and it
+dynamically revises the pattern execution plan by sorting the patterns according to their filtering capabilities
+(i.e. largest set reduction patterns execute first). 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(
+        __.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 standard inner-traversals can
+be arbitrarily defined.
+
+[gremlin-groovy,modern]
+----
+g.V().match(
+        __.as('a').out('created').has('name', 'lop').as('b'),
+        __.as('b').in('created').has('age', 29).as('c')).
+      select('a','c').by('name')
+----
+
+In order to improve readability, `as()`-steps can be given meaningful labels which better reflect your domain. The
+previous query can thus be written in a more expressive way as shown below.
+
+[gremlin-groovy,modern]
+----
+g.V().match(
+        __.as('creators').out('created').has('name', 'lop').as('projects'), <1>
+        __.as('projects').in('created').has('age', 29).as('cocreators')). <2>
+      select('creators','cocreators').by('name') <3>
+----
+
+<1> Find vertices that created something and match them as 'creators', then find out what they created which is
+named 'lop' and match these vertices as 'projects'.
+<2> Using these 'projects' vertices, find out their creators aged 29 and remember these as 'cocreators'.
+<3> Return the name of both 'creators' and 'cocreators'.
+
+[[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(
+        __.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(
+        __.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*: Before and after a `match()`, it is possible to leverage classic Gremlin traversals.
+
+To extend point #3, it is possible to support going from imperative, to declarative, to imperative, ad infinitum.
+
+[gremlin-groovy,modern]
+----
+g.V().match(
+        __.as('a').out('knows').as('b'),
+        __.as('b').out('created').has('name','lop')).
+      select('b').out('created').
+        match(
+          __.as('x').in('created').as('y'),
+          __.as('y').out('knows').as('z')).
+      select('z').values('name')
+----
+
+IMPORTANT: The `match()`-step is stateless. The variable bindings of the traversal patterns are stored in the path
+history of the traverser. As such, the variables used over all `match()`-steps within a traversal are globally unique.
+A benefit of this is that subsequent `where()`, `select()`, `match()`, etc. steps can leverage the same variables in
+their analysis.
+
+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(
+        __.as('a').out('knows').as('b'),
+        __.as('b').out('created').has('name','lop'),
+        __.as('b').match(
+                     __.as('b').out('created').as('c'),
+                     __.as('c').has('name','ripple')).
+                   select('c').as('c')).
+      select('a','c').by('name')
+----
+
+If a step-labeled traversal proceeds the `match()`-step and the traverser entering the `match()` is destined to bind
+to a particular variable, then the previous step should be labeled accordingly.
+
+[gremlin-groovy,modern]
+----
+g.V().as('a').out('knows').as('b').
+  match(
+    __.as('b').out('created').as('c'),
+    __.not(__.as('c').in('created').as('a'))).
+  select('a','b','c').by('name')
+----
+
+There are three types of `match()` traversal patterns.
+
+  . `as('a')...as('b')`: both the start and end of the traversal have a declared variable.
+  . `as('a')...`: only the start of the traversal has a declared variable.
+  . `...`: there are no declared variables.
+
+If a variable is at the start of a traversal pattern it *must* exist as a label in the path history of the traverser
+else the traverser can not go down that path. If a variable is at the end of a traversal pattern then if the variable
+exists in the path history of the traverser, the traverser's current location *must* match (i.e. equal) its historic
+location at that same label. However, if the variable does not exist in the path history of the traverser, then the
+current location is labeled as the variable and thus, becomes a bound variable for subsequent traversal patterns. If a
+traversal pattern does not have an end label, then the traverser must simply "survive" the pattern (i.e. not be
+filtered) to continue to the next pattern. If a traversal pattern does not have a start label, then the traverser
+can go down that path at any point, but will only go down that pattern once as a traversal pattern is executed once
+and only once for the history of the traverser. Typically, traversal patterns that do not have a start and end label
+are used in conjunction with `and()`, `or()`, and `where()`. Once the traverser has "survived" all the patterns (or at
+least one for `or()`), `match()`-step analyzes the traverser's path history and emits a `Map<String,Object>` of the
+variable bindings to the next step in the traversal.
+
+[gremlin-groovy,modern]
+----
+g.V().as('a').out().as('b'). <1>
+    match( <2>
+      __.as('a').out().count().as('c'), <3>
+      __.not(__.as('a').in().as('b')), <4>
+      or( <5>
+        __.as('a').out('knows').as('b'),
+        __.as('b').in().count().as('c').and().as('c').is(gt(2)))).  <6>
+    dedup('a','c'). <7>
+    select('a','b','c').by('name').by('name').by() <8>
+----
+
+<1> A standard, step-labeled traversal can come prior to `match()`.
+<2> If the traverser's path prior to entering `match()` has requisite label values, then those historic values are bound.
+<3> It is possible to use <<a-note-on-barrier-steps,barrier steps>> though they are computed locally to the pattern (as one would expect).
+<4> It is possible to `not()` a pattern.
+<5> It is possible to nest `and()`- and `or()`-steps for conjunction matching.
+<6> Both infix and prefix conjunction notation is supported.
+<7> It is possible to "distinct" the specified label combination.
+<8> The bound values are of different types -- vertex ("a"), vertex ("b"), long ("c").
+
+[[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()`-step allows the user to further constrain the result set provided by `match()`.
+
+[gremlin-groovy,modern]
+----
+g.V().match(
+        __.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 `P`-predicate (example above) or a `Traversal` (example below). Using
+`MatchPredicateStrategy`, `where()`-clauses are automatically folded into `match()` and thus, subject to the query
+optimizer within `match()`-step.
+
+[gremlin-groovy,modern]
+----
+traversal = g.V().match(
+                    __.as('a').has(label,'person'), <1>
+                    __.as('a').out('created').as('b'),
+                    __.as('b').in('created').as('c')).
+                    where(__.as('a').out('knows').as('c')). <2>
+                  select('a','c').by('name'); null <3>
+traversal.toString() <4>
+traversal <5> <6>
+traversal.toString() <7>
+----
+
+<1> Any `has()`-step traversal patterns that start with the match-key are pulled out of `match()` to enable the graph
+system to leverage the filter for index lookups.
+<2> A `where()`-step with a traversal containing variable bindings declared in `match()`.
+<3> A useful trick to ensure that the traversal is not iterated by Gremlin Console.
+<4> The string representation of the traversal prior to its strategies being applied.
+<5> The Gremlin Console will automatically iterate anything that is an iterator or is iterable.
+<6> Both marko and josh are co-developers and marko knows josh.
+<7> The string representation of the traversal after the strategies have been applied (and thus, `where()` is folded into `match()`)
+
+IMPORTANT: A `where()`-step is a filter and thus, variables within a `where()` clause are not globally bound to the
+path of the traverser in `match()`. As such, `where()`-steps in `match()` are used for filtering, not binding.
+
+[[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(1))).
+     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().where(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`.
+
+For traversal compilation information, please see <<explain-step,`explain()`>>-step.
+
+[[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)
+----
+
+The `range()`-step can also be applied with `Scope.local`, in which case it operates on the incoming collection.
+For example, it is possible to produce a `Map<String, String>` for each traversed path, but containing only the second
+property value (the "b" step).
+
+[gremlin-groovy,modern]
+----
+g.V().as('a').out().as('b').in().as('c').select('a','b','c').by('name').range(local,1,2)
+----
+
+The next example uses the <<the-crew-toy-graph,The Crew>> toy data set.  It produces a `List<String>` containing the
+second and third location for each vertex.
+
+[gremlin-groovy,theCrew]
+----
+g.V().valueMap().select('location').range(local, 1, 3)
+----
+
+[[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==1`, the
+traverser repeats. However, because the emit-predicate is declared true, those vertices are emitted. The next time through
+ `repeat()`, the vertices traversed are ripple and lop (Josh's created projects, as lop and vadas have no out edges).
+  Given that `loops==2`, the until-predicate fails and ripple and lop are emitted.
+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(0)).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?,mergeOperator?)`.
+
+* *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.
+* *Merge operator*: A `BinaryOperator` that unites two traverser's sack when they are merged. If no merge operator is
+provided, then traversers with sacks can not be merged.
+
+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).by('weight')`). Note that the <<by-step,`by()`>>-modulator can be any arbitrary traversal.
+
+[gremlin-groovy,modern]
+----
+g.withSack(1.0f).V().repeat(outE().sack(mult).by('weight').inV()).times(2)
+g.withSack(1.0f).V().repeat(outE().sack(mult).by('weight').inV()).times(2).sack()
+g.withSack(1.0f).V().repeat(outE().sack(mult).by('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.
+
+If a *merge operator* is not provided, then traversers with sacks can not be bulked. However, in many situations,
+merging the sacks of two traversers at the same location is algorithmically sound and good to provide so as to gain
+the bulking optimization. In the examples below, the binary merge operator is `Operator.sum`. Thus, when two traverser
+merge, their respective sacks are added together.
+
+[gremlin-groovy,modern]
+----
+g.withSack(1.0f,sum).V(1).local(outE('knows').barrier(normSack).inV()) <1>
+g.withSack(1.0f,sum).V(1).local(outE('knows').barrier(normSack).inV()).sack() <2>
+g.withSack(1.0f,sum).V(1).local(outE('knows').barrier(normSack).inV()).in('knows') <3>
+g.withSack(1.0f,sum).V(1).local(outE('knows').barrier(normSack).inV()).in('knows').sack() <4>
+g.withSack(1.0f,sum).V(1).local(outE('knows').barrier(normSack).inV()).in('knows').barrier().sack() <5>
+g.withBulk(false).withSack(1.0f,sum).V(1).local(outE('knows').barrier(normSack).inV()).in('knows').barrier().sack() <6>
+----
+
+<1> The knows-adjacent vertices of vertex 1 are vertices 2 and 4.
+<2> The `local(...barrier(normSack)...)` ensures that all traversers leaving vertex 1 have an evenly distributed amount of the initial 1.0 "energy" (50-50).
+<3> Going from vertices 2 and 4 yield two traversers at vertex 1.
+<4> Those two traversers each have a sack of 0.5.
+<5> The `barrier()` merges the two traversers at vertex 1 into a single traverser whose sack is 1.0.
+<6> There is now a single traverser with bulk of 2 and sack of 1.0 and thus, setting `withBulk(false)` yields the expected 1.0.
+
+
+[[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('a','b','c')
+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
+----
+
+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.
+
+When the set of keys or values (i.e. columns) of a path or map are needed, use `select(keys)` and `select(values)`,
+respectively. This is especially useful when one is only interested in the top N elements in a `groupCount()`
+ranking.
+
+[gremlin-groovy]
+----
+graph.io(graphml()).readGraph('data/grateful-dead.xml')
+g = graph.traversal()
+g.V().hasLabel('song').out('followedBy').groupCount().by('name').
+      order(local).by(valueDecr).limit(local, 5)
+g.V().hasLabel('song').out('followedBy').groupCount().by('name').
+      order(local).by(valueDecr).limit(local, 5).select(keys)
+g.V().hasLabel('song').out('followedBy').groupCount().by('name').
+      order(local).by(valueDecr).limit(local, 5).select(keys).unfold()
+----
+
+Similarly, for extracting the values from a path or map.
+
+[gremlin-groovy]
+----
+graph.io(graphml()).readGraph('data/grateful-dead.xml')
+g = graph.traversal()
+g.V().hasLabel('song').out('sungBy').groupCount().by('name') <1>
+g.V().hasLabel('song').out('sungBy').groupCount().by('name').select(values) <2>
+g.V().hasLabel('song').out('sungBy').groupCount().by('name').select(values).unfold().
+      groupCount().order(local).by(valueDecr).limit(local, 5) <3>
+----
+
+<1> Which artist sung how many songs?
+<2> Get an anonymized set of song repertoire sizes.
+<3> What are the 5 most common song repertoire sizes?
+
+CAUTION: Note that `by()`-modulation is not supported with `select(keys)` and `select(values)`.
+
+[[using-where-with-select]]
+Using Where with Select
+^^^^^^^^^^^^^^^^^^^^^^^
+
+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('a','b').by('name') <1>
+g.V().as('a').out('created').in('created').as('b').
+      select('a','b').by('name').where('a',neq('b')) <2>
+g.V().as('a').out('created').in('created').as('b').
+      select('a','b'). <3>
+      where('a',neq('b')).
+      where(__.as('a').out('knows').as('b')).
+      select('a','b').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('x').by('weight').cap('x')
+----
+
+[[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.
+
+[[tail-step]]
+Tail Step
+~~~~~~~~~
+
+image::tail-step.png[width=530]
+
+The `tail()`-step is analogous to <<limit-step,`limit()`>>-step, except that it emits the last `n`-objects instead of
+the first `n`-objects.
+
+[gremlin-groovy,modern]
+----
+g.V().values('name').order()
+g.V().values('name').order().tail() <1>
+g.V().values('name').order().tail(1) <2>
+g.V().values('name').order().tail(3) <3>
+----
+
+<1> Last name (alphabetically).
+<2> Same as statement 1.
+<3> Last three names.
+
+The `tail()`-step can also be applied with `Scope.local`, in which case it operates on the incoming collection.
+
+[gremlin-groovy,modern]
+----
+g.V().as('a').out().as('a').out().as('a').select('a').by(tail(local)).values('name') <1>
+g.V().as('a').out().as('a').out().as('a').select('a').by(unfold().values('name').fold()).tail(local) <2>
+g.V().as('a').out().as('a').out().as('a').select('a').by(unfold().values('name').fold()).tail(local, 2) <3>
+g.V().valueMap().tail(local) <4>
+----
+
+<1> Only the most recent name from the "a" step (`List<Vertex>` becomes `Vertex`).
+<2> Same result as statement 1 (`List<String>` becomes `String`).
+<3> `List<String>` for each path containing the last two names from the 'a' step.
+<4> `Map<String, Object>` for each vertex, but containing only the last property value.
+
+[[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 `Tree` JavaDoc).
+
+[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(count(local).is(1)).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 few more examples of filtering an arbitrary object based on a anonymous traversal is provided below.
+
+[gremlin-groovy,modern]
+----
+g.V().where(out('created')).values('name') <1>
+g.V().out('knows').where(out('created')).values('name') <2>
+g.V().where(out('created').count().is(gte(2))).values('name') <3>
+g.V().where(out('knows').where(out('created'))).values('name') <4>
+g.V().where(__.not(out('created'))).where(__.in('knows')).values('name') <5>
+g.V().where(__.not(out('created')).and().in('knows')).values('name') <6>
+----
+
+<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)
+<5> What are the names of the people who have not created anything, but are known by someone?
+<6> The concatenation of `where()`-steps is the same as a single `where()`-step with an and'd clause.
+
+WARNING: The anonymous traversal of `where()` 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. Note that is only a temporary limitation that will be addressed in a future version of TinkerPop3 (see
+link:https://issues.apache.org/jira/browse/TINKERPOP3-693[JIRA#693]).
+
+[[a-note-on-predicates]]
+A Note on Predicates
+--------------------
+
+A `P` is a predicate of the form `Function<Object,Boolean>`. That is, given some object, return true or false. The
+provided predicates are outlined in the table below and are used in various steps such as <<has-step,`has()`>>-step,
+<<where-step,`where()`>>-step, <<is-step,`is()`>>-step, etc.
+
+[width="100%",cols="3,15",options="header"]
+|=========================================================
+| Predicate | Description
+| `eq(object)` | Is the incoming object equal to the provided object?
+| `neq(object)` | Is the incoming object not equal to the provided object?
+| `lt(number)` | Is the incoming number less than the provided number?
+| `lte(number)` | Is the incoming number less than or equal to the provided number?
+| `gt(number)` | Is the incoming number greater than the provided number?
+| `gte(number)` | Is the incoming number greater than or equal to the provided number?
+| `inside(number,number)` | Is the incoming number greater than the first provided number and less than the second?
+| `outside(number,number)` | Is the incoming number less than the first provided number and greater than the second?
+| `between(number,number)` | Is the incoming number greater than or equal to the first provided number and less than the second?
+| `within(objects...)` | Is the incoming object in the array of provided objects?
+| `without(objects...)` | Is the incoming object not in the array of the provided objects?
+|=========================================================
+
+[gremlin-groovy]
+----
+eq(2)
+not(neq(2)) <1>
+not(within('a','b','c'))
+not(within('a','b','c')).test('d') <2>
+not(within('a','b','c')).test('a')
+within(1,2,3).and(not(eq(2))).test(3) <3>
+inside(1,4).or(eq(5)).test(3) <4>
+inside(1,4).or(eq(5)).test(5)
+between(1,2) <5>
+not(between(1,2))
+----
+
+<1> The `not()` of a `P`-predicate is another `P`-predicate.
+<2> `P`-predicates are arguments to various steps which internally `test()` the incoming value.
+<3> `P`-predicates can be and'd together.
+<4> `P`-predicates can be or' together.
+<5> `and()` is a `P`-predicate and thus, a `P`-predicate can be composed of multiple `P`-predicates.
+
+Finally, note that <<where-step,`where()`>>-step takes a `P<String>`. The provided string value refers to a variable
+binding, not to the explicit string value.
+
+[gremlin-groovy,modern]
+----
+g.V().as('a').both().both().as('b').count()
+g.V().as('a').both().both().as('b').where('a',neq('b')).count()
+----
+
+NOTE: It is possible for graph system providers and users to extend `P` and provide new predicates. For instance, a
+`regex(pattern)` could be a graph system specific `P`.
+
+[[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 thre

<TRUNCATED>