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 2018/10/12 23:25:02 UTC

svn commit: r1843716 [2/43] - in /tinkerpop/site: docs/3.2.10-SNAPSHOT/ docs/3.2.10-SNAPSHOT/dev/developer/ docs/3.2.10-SNAPSHOT/dev/io/ docs/3.2.10-SNAPSHOT/dev/provider/ docs/3.2.10-SNAPSHOT/images/ docs/3.2.10-SNAPSHOT/logs/ docs/3.2.10-SNAPSHOT/rec...

Modified: tinkerpop/site/docs/3.2.10-SNAPSHOT/dev/provider/index.html
URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.10-SNAPSHOT/dev/provider/index.html?rev=1843716&r1=1843715&r2=1843716&view=diff
==============================================================================
--- tinkerpop/site/docs/3.2.10-SNAPSHOT/dev/provider/index.html (original)
+++ tinkerpop/site/docs/3.2.10-SNAPSHOT/dev/provider/index.html Fri Oct 12 23:25:00 2018
@@ -805,6 +805,7 @@ table.CodeRay td.code>pre{padding:0}
 <ul class="sectlevel1">
 <li><a href="#graph-system-provider-requirements">Graph System Provider Requirements</a>
 <ul class="sectlevel2">
+<li><a href="#graph-structure-api">Graph Structure API</a></li>
 <li><a href="#_implementing_gremlin_core">Implementing Gremlin-Core</a>
 <ul class="sectlevel3">
 <li><a href="#oltp-implementations">OLTP Implementations</a></li>
@@ -812,6 +813,7 @@ table.CodeRay td.code>pre{padding:0}
 <li><a href="#_hadoop_gremlin_usage">Hadoop-Gremlin Usage</a></li>
 <li><a href="#io-implementations">IO Implementations</a></li>
 <li><a href="#remoteconnection-implementations">RemoteConnection Implementations</a></li>
+<li><a href="#_bulk_import_export">Bulk Import Export</a></li>
 </ul>
 </li>
 <li><a href="#validating-with-gremlin-test">Validating with Gremlin-Test</a></li>
@@ -903,6 +905,103 @@ Gremlin-JS, etc.) will integrate properl
 TinkerPop3 implementation.</p>
 </div>
 <div class="sect2">
+<h3 id="graph-structure-api">Graph Structure API</h3>
+<div class="paragraph">
+<p>The graph structure API of TinkerPop3 provides the interfaces necessary to create a TinkerPop enabled system and
+exposes the basic components of a property graph to include <code>Graph</code>, <code>Vertex</code>, <code>Edge</code>, <code>VertexProperty</code> and <code>Property</code>.
+The structure API can be used directly as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="java">Graph graph = TinkerGraph.open(); <span class="invisible">//</span><b class="conum">1</b>
+Vertex marko = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">1</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">marko</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>, <span class="integer">29</span>); <span class="invisible">//</span><b class="conum">2</b>
+Vertex vadas = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">2</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">vadas</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>, <span class="integer">27</span>);
+Vertex lop = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">software</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">3</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">lop</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">lang</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">java</span><span class="delimiter">&quot;</span></span>);
+Vertex josh = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">4</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">josh</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>, <span class="integer">32</span>);
+Vertex ripple = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">software</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">5</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">ripple</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">lang</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">java</span><span class="delimiter">&quot;</span></span>);
+Vertex peter = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">6</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">peter</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>, <span class="integer">35</span>);
+marko.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">knows</span><span class="delimiter">&quot;</span></span>, vadas, T.id, <span class="integer">7</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">0.5f</span>); <span class="invisible">//</span><b class="conum">3</b>
+marko.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">knows</span><span class="delimiter">&quot;</span></span>, josh, T.id, <span class="integer">8</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">1.0f</span>);
+marko.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>, lop, T.id, <span class="integer">9</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">0.4f</span>);
+josh.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>, ripple, T.id, <span class="integer">10</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">1.0f</span>);
+josh.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>, lop, T.id, <span class="integer">11</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">0.4f</span>);
+peter.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>, lop, T.id, <span class="integer">12</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">0.2f</span>);</code></pre>
+</div>
+</div>
+<div class="colist arabic">
+<ol>
+<li>
+<p>Create a new in-memory <code>TinkerGraph</code> and assign it to the variable <code>graph</code>.</p>
+</li>
+<li>
+<p>Create a vertex along with a set of key/value pairs with <code>T.label</code> being the vertex label and <code>T.id</code> being the vertex id.</p>
+</li>
+<li>
+<p>Create an edge along with a  set of key/value pairs with the edge label being specified as the first argument.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>In the above code all the vertices are created first and then their respective edges. There are two "accessor tokens":
+<code>T.id</code> and <code>T.label</code>. When any of these, along with a set of other key value pairs is provided to
+<code>Graph.addVertex(Object&#8230;&#8203;)</code> or <code>Vertex.addEdge(String,Vertex,Object&#8230;&#8203;)</code>, the respective element is created along
+with the provided key/value pair properties appended to it.</p>
+</div>
+<div class="paragraph">
+<p>Below is a sequence of basic graph mutation operations represented in Java 8. One of the major differences between
+TinkerPop2 and TinkerPop3 is that in TinkerPop3, the Java convention of using setters and getters has been abandoned
+in favor of a syntax that is more aligned with the syntax of Gremlin-Groovy in TinkerPop2. Given that Gremlin-Java8
+and Gremlin-Groovy are nearly identical due to the inclusion of Java 8 lambdas, a big effort was made to ensure that
+both languages are as similar as possible.</p>
+</div>
+<div class="paragraph">
+<p><span class="image" style="float: right"><img src="../../images/basic-mutation.png" alt="basic mutation" width="240"></span></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// create a new graph</span>
+Graph graph = TinkerGraph.open();
+<span class="comment">// add a software vertex with a name property</span>
+Vertex gremlin = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">software</span><span class="delimiter">&quot;</span></span>,
+                             <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">gremlin</span><span class="delimiter">&quot;</span></span>); <span class="invisible">//</span><b class="conum">1</b>
+<span class="comment">// only one vertex should exist</span>
+<span class="keyword">assert</span>(IteratorUtils.count(graph.vertices()) == <span class="integer">1</span>)
+<span class="comment">// no edges should exist as none have been created</span>
+<span class="keyword">assert</span>(IteratorUtils.count(graph.edges()) == <span class="integer">0</span>)
+<span class="comment">// add a new property</span>
+gremlin.property(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>,<span class="integer">2009</span>) <span class="invisible">//</span><b class="conum">2</b>
+<span class="comment">// add a new software vertex to the graph</span>
+Vertex blueprints = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">software</span><span class="delimiter">&quot;</span></span>,
+                                <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">blueprints</span><span class="delimiter">&quot;</span></span>); <span class="invisible">//</span><b class="conum">3</b>
+<span class="comment">// connect gremlin to blueprints via a dependsOn-edge</span>
+gremlin.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">dependsOn</span><span class="delimiter">&quot;</span></span>,blueprints); <span class="invisible">//</span><b class="conum">4</b>
+<span class="comment">// now there are two vertices and one edge</span>
+<span class="keyword">assert</span>(IteratorUtils.count(graph.vertices()) == <span class="integer">2</span>)
+<span class="keyword">assert</span>(IteratorUtils.count(graph.edges()) == <span class="integer">1</span>)
+<span class="comment">// add a property to blueprints</span>
+blueprints.property(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>,<span class="integer">2010</span>) <span class="invisible">//</span><b class="conum">5</b>
+<span class="comment">// remove that property</span>
+blueprints.property(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>).remove() <span class="invisible">//</span><b class="conum">6</b>
+<span class="comment">// connect gremlin to blueprints via encapsulates</span>
+gremlin.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">encapsulates</span><span class="delimiter">&quot;</span></span>,blueprints) <span class="invisible">//</span><b class="conum">7</b>
+<span class="keyword">assert</span>(IteratorUtils.count(graph.vertices()) == <span class="integer">2</span>)
+<span class="keyword">assert</span>(IteratorUtils.count(graph.edges()) == <span class="integer">2</span>)
+<span class="comment">// removing a vertex removes all its incident edges as well</span>
+blueprints.remove() <span class="invisible">//</span><b class="conum">8</b>
+gremlin.remove() <span class="invisible">//</span><b class="conum">9</b>
+<span class="comment">// the graph is now empty</span>
+<span class="keyword">assert</span>(IteratorUtils.count(graph.vertices()) == <span class="integer">0</span>)
+<span class="keyword">assert</span>(IteratorUtils.count(graph.edges()) == <span class="integer">0</span>)
+<span class="comment">// tada!</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The above code samples are just examples of how the structure API can be used to access a graph. Those APIs are then
+used internally by the process API (i.e. Gremlin) to access any graph that implements those structure API interfaces
+to execute queries. Typically, the structure API methods are not used directly by end-users.</p>
+</div>
+</div>
+<div class="sect2">
 <h3 id="_implementing_gremlin_core">Implementing Gremlin-Core</h3>
 <div class="paragraph">
 <p>The classes that a graph system provider should focus on implementing are itemized below. It is a good idea to study
@@ -1599,6 +1698,21 @@ similar to Gremlin Server that can accep
 reason to implement this interface.</p>
 </div>
 </div>
+<div class="sect3">
+<h4 id="_bulk_import_export">Bulk Import Export</h4>
+<div class="paragraph">
+<p>When it comes to doing "bulk" operations, the diverse nature of the available graph databases and their specific
+capabilities, prevents TinkerPop from doing a good job of generalizing that capability well. TinkerPop refers users to
+the bulk import/export facilities of specific graph providers as they tend to be more efficient and easier to use than
+the options TinkerPop has tried to generalize in the past.</p>
+</div>
+<div class="paragraph">
+<p>That said, for graph providers that don&#8217;t have a special bulk loading feature, they can get a basic bulk loader from
+TinkerPop using the <a href="http://tinkerpop.apache.org/docs/3.2.10-SNAPSHOT/reference/#clonevertexprogram">CloneVertexProgram</a>.
+Simply provide a <code>InputFormat</code> and <code>OutputFormat</code> that can be referenced by a <code>HadoopGraph</code> instance as discussed
+in the <a href="http://tinkerpop.apache.org/docs/3.2.10-SNAPSHOT/reference/#clonevertexprogram">Reference Documentation</a>.</p>
+</div>
+</div>
 </div>
 <div class="sect2">
 <h3 id="validating-with-gremlin-test">Validating with Gremlin-Test</h3>
@@ -2525,9 +2639,9 @@ twenty. Under this model, the amount of
 <pre class="CodeRay highlight"><code data-lang="groovy">gremlin&gt; cluster = Cluster.open()
 ==&gt;localhost/<span class="float">127.0</span><span class="float">.0</span><span class="float">.1</span>:<span class="integer">8182</span>
 gremlin&gt; client = cluster.connect()
-==&gt;org.apache.tinkerpop.gremlin.driver.Client<span class="error">$</span>ClusteredClient<span class="error">@</span><span class="integer">7</span>a78d380
+==&gt;org.apache.tinkerpop.gremlin.driver.Client<span class="error">$</span>ClusteredClient<span class="error">@</span><span class="integer">4269</span>aad7
 gremlin&gt; aliased = client.alias(<span class="string"><span class="delimiter">&quot;</span><span class="content">g</span><span class="delimiter">&quot;</span></span>)
-==&gt;org.apache.tinkerpop.gremlin.driver.Client<span class="error">$</span>AliasClusteredClient<span class="error">@</span><span class="integer">7</span>cbf4f8c
+==&gt;org.apache.tinkerpop.gremlin.driver.Client<span class="error">$</span>AliasClusteredClient<span class="error">@</span><span class="integer">2</span>b5f8e61
 gremlin&gt; g = org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph.INSTANCE.traversal() <span class="invisible">//</span><b class="conum">1</b><span class="invisible">\</span>
 ==&gt;graphtraversalsource[emptygraph[empty], standard]
 gremlin&gt; rs = aliased.submit(g.V().both().barrier().both().barrier()).all().get() <span class="invisible">//</span><b class="conum">2</b><span class="invisible">\</span>
@@ -3151,7 +3265,7 @@ to provide a way to dynamically evaluate
 </div>
 <div id="footer">
 <div id="footer-text">
-Last updated 2018-05-11 13:26:52 EDT
+Last updated 2018-10-12 18:37:09 EDT
 </div>
 </div>
 </body>

Added: tinkerpop/site/docs/3.2.10-SNAPSHOT/images/practical-gremlin.png
URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.10-SNAPSHOT/images/practical-gremlin.png?rev=1843716&view=auto
==============================================================================
Binary file - no diff available.

Propchange: tinkerpop/site/docs/3.2.10-SNAPSHOT/images/practical-gremlin.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: tinkerpop/site/docs/3.2.10-SNAPSHOT/images/traversal-mechanics.png
URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.10-SNAPSHOT/images/traversal-mechanics.png?rev=1843716&r1=1843715&r2=1843716&view=diff
==============================================================================
Binary files - no diff available.

Modified: tinkerpop/site/docs/3.2.10-SNAPSHOT/index.html
URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.10-SNAPSHOT/index.html?rev=1843716&r1=1843715&r2=1843716&view=diff
==============================================================================
--- tinkerpop/site/docs/3.2.10-SNAPSHOT/index.html (original)
+++ tinkerpop/site/docs/3.2.10-SNAPSHOT/index.html Fri Oct 12 23:25:00 2018
@@ -913,8 +913,8 @@ and an overview of Gremlin. (<strong>ext
 A series of blog posts that examine the Gremlin language in the context of various graph traversal patterns. (<strong>external</strong>)</p></td>
 </tr>
 <tr>
-<td class="tableblock halign-center valign-top"><p class="tableblock"><span class="image"><img src="images/gremlin-running.png" alt="gremlin running" width="125"></span></p></td>
-<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="http://kelvinlawrence.net/book/Gremlin-Graph-Guide.html">Graph Databases, Gremlin and TinkerPop: A Tutorial</a><br>
+<td class="tableblock halign-center valign-top"><p class="tableblock"><span class="image"><img src="images/practical-gremlin.png" alt="practical gremlin" width="200"></span></p></td>
+<td class="tableblock halign-left valign-middle"><p class="tableblock"><a href="http://kelvinlawrence.net/book/Gremlin-Graph-Guide.html">Practical Gremlin: An Apache TinkerPop Tutorial</a><br>
 A getting started guide for users of graph databases and the Gremlin query language featuring hints, tips and sample queries. (<strong>external</strong>)</p></td>
 </tr>
 </tbody>
@@ -1003,7 +1003,7 @@ Reference Documentation for providers an
 </div>
 <div id="footer">
 <div id="footer-text">
-Last updated 2018-05-11 13:48:50 EDT
+Last updated 2018-10-12 19:20:40 EDT
 </div>
 </div>
 </body>

Modified: tinkerpop/site/docs/3.2.10-SNAPSHOT/recipes/index.html
URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.10-SNAPSHOT/recipes/index.html?rev=1843716&r1=1843715&r2=1843716&view=diff
==============================================================================
--- tinkerpop/site/docs/3.2.10-SNAPSHOT/recipes/index.html (original)
+++ tinkerpop/site/docs/3.2.10-SNAPSHOT/recipes/index.html Fri Oct 12 23:25:00 2018
@@ -820,6 +820,7 @@ table.CodeRay td.code>pre{padding:0}
 <li><a href="#duplicate-edge">Duplicate Edge Detection</a></li>
 <li><a href="#duplicate-vertex">Duplicate Vertex Detection</a></li>
 <li><a href="#edge-move">Moving an Edge</a></li>
+<li><a href="#element-existence">Element Existence</a></li>
 <li><a href="#if-then-based-grouping">If-Then Based Grouping</a></li>
 <li><a href="#pagination">Pagination</a></li>
 <li><a href="#recommendation">Recommendation</a></li>
@@ -923,7 +924,7 @@ gremlin&gt; g.V(<span class="integer">1<
 <p>There are three edges from the vertex with the identifier of "1".</p>
 </li>
 <li>
-<p>Filter those three edges using the <code>where()</code> step using the identifier of the vertex returned by <code>otherV()</code> to
+<p>Filter those three edges using the <code>where()</code>-step using the identifier of the vertex returned by <code>otherV()</code> to
 ensure it matches on the vertex of concern, which is the one with an identifier of "2".</p>
 </li>
 <li>
@@ -944,7 +945,7 @@ two vertices.</p>
 </ol>
 </div>
 <div class="paragraph">
-<p>The basic pattern of using <code>where()</code> step to find the "other" known vertex can be applied in far more complex
+<p>The basic pattern of using <code>where()</code>-step to find the "other" known vertex can be applied in far more complex
 scenarios. For one such example, consider the following traversal that finds all the paths between a group of defined
 vertices:</p>
 </div>
@@ -1034,7 +1035,7 @@ gremlin&gt; g.V(vRexsterJob1, vBlueprint
 </div>
 <div class="paragraph">
 <p>While the traversals above are more complex, the pattern for finding "things" between two vertices is largely the same.
-Note the use of the <code>where()</code> step to terminate the traversers for a specific user. It is embedded in a <code>coalesce()</code>
+Note the use of the <code>where()</code>-step to terminate the traversers for a specific user. It is embedded in a <code>coalesce()</code>
 step to handle situations where the specified user did not complete an application for the specified job and will
 return <code>false</code> in those cases.</p>
 </div>
@@ -1354,12 +1355,12 @@ can shorten the time required to get a r
 <pre class="CodeRay highlight"><code data-lang="groovy">gremlin&gt; g = graph.traversal().withComputer()
 ==&gt;graphtraversalsource[tinkergraph[<span class="key">vertices</span>:<span class="integer">6</span> <span class="key">edges</span>:<span class="integer">6</span>], graphcomputer]
 gremlin&gt; g.V().pageRank().by(<span class="string"><span class="delimiter">'</span><span class="content">pageRank</span><span class="delimiter">'</span></span>).values(<span class="string"><span class="delimiter">'</span><span class="content">pageRank</span><span class="delimiter">'</span></span>)
-==&gt;<span class="float">0.4018125</span>
+==&gt;<span class="float">0.15000000000000002</span>
+==&gt;<span class="float">0.15000000000000002</span>
 ==&gt;<span class="float">0.19250000000000003</span>
 ==&gt;<span class="float">0.19250000000000003</span>
-==&gt;<span class="float">0.23181250000000003</span>
-==&gt;<span class="float">0.15000000000000002</span>
-==&gt;<span class="float">0.15000000000000002</span></code></pre>
+==&gt;<span class="float">0.4018125</span>
+==&gt;<span class="float">0.23181250000000003</span></code></pre>
 </div>
 </div>
 </div>
@@ -1374,7 +1375,7 @@ gremlin&gt; g.V().pageRank().by(<span cl
 <div class="paragraph">
 <p>Lists and maps form the basis for much of the processing in Gremlin traversals. They are core to how side-effects
 are typically held and how results are generally produced. Being able to pick them apart and reformat them is sometimes
-required. This need to shape the date within a traversal may arise both at the
+required. This need to shape the data within a traversal may arise both at the
 <a href="http://tinkerpop.apache.org/docs/current/reference/#terminal-steps">terminal step</a> of the traversal (technically
 just prior to the terminal step) or in the middle of a traversal. Considering the former, a transformation just prior
 to iteration will get the result into the form required by the application which would remove the need for additional
@@ -1478,7 +1479,7 @@ structure of the <code>List</code> trave
 </div>
 <div class="paragraph">
 <p>The call to <code>local()</code> executes its anonymous sub-traversal over each individual <code>List</code> iterator and as the
-sub-traversal ends with a <code>fold()</code> step, the results are reduced back into a <code>List</code> to preserve the original structure,
+sub-traversal ends with a <code>fold()</code>-step, the results are reduced back into a <code>List</code> to preserve the original structure,
 thus maintaining two traverser results.</p>
 </div>
 <div class="paragraph">
@@ -1516,7 +1517,7 @@ gremlin&gt; g.V().union(limit(<span clas
 with the highest degree (i.e. number of edges). By ending with <code>fold()</code> the <code>List</code> traverser structure is preserved
 thus returning two <code>List</code> objects. Consider this a method for choosing a "max" or a highly ranked vertex. In this case
 the rank was determined by the number of edges, but it could have just as easily been determined by a vertex property,
-edge property, a calculated value, etc. - one simply needs to alter the <code>by()</code> step modulator to <code>order()</code>.</p>
+edge property, a calculated value, etc. - one simply needs to alter the <code>by()</code>-step modulator to <code>order()</code>.</p>
 </li>
 <li>
 <p>For each <code>List</code> of vertices, filter that <code>List</code> to only include vertices that have an "age" property with a
@@ -1634,11 +1635,11 @@ iterated up to that point before moving
 complete information required for the production of "b" and "c".</p>
 </li>
 <li>
-<p>Adding <code>fold()</code> step here is a bit of a trick. To see the trick, copy and paste all lines of Gremlin up to but
-not including this <code>fold()</code> step and run them against the "modern" graph. The output is three vertices and if the
-<code>profile()</code> step was added one would also see that the traversal contained three traversers. These three traversers
-with a vertex in each one were produced from the <code>repeat()</code> step (i.e. those vertices that had the "lang" of "java"
-when traversing away from "marko"). The <code>aggregate()</code> steps are side-effects and just allow the traversers to pass
+<p>Adding <code>fold()</code>-step here is a bit of a trick. To see the trick, copy and paste all lines of Gremlin up to but
+not including this <code>fold()</code>-step and run them against the "modern" graph. The output is three vertices and if the
+<code>profile()</code>-step was added one would also see that the traversal contained three traversers. These three traversers
+with a vertex in each one were produced from the <code>repeat()</code>-step (i.e. those vertices that had the "lang" of "java"
+when traversing away from "marko"). The <code>aggregate()</code>-steps are side-effects and just allow the traversers to pass
 through them unchanged. The <code>fold()</code> obviously converts those three traversers to a single <code>List</code> to make one
 traverser with a <code>List</code> inside. That means that the remaining steps following the <code>fold()</code> will only be executed one
 time each instead of three, which, as will be shown, is critical to the proper result.</p>
@@ -1659,7 +1660,7 @@ presents an override to include "c" into
 <p>All of the above code and explanation show that <code>store()</code> can be used to construct <code>List</code> objects as side-effects
 which can then be used as a result. Note that <code>aggregate()</code> can be used to similar effect, should it make sense that
 lazy <code>List</code> creation is not acceptable with respect to the nature of the traversal. An interesting sub-pattern that
-emerges here is that the <code>by()</code> step can modulate its step to completely override the current traverser and ignore its
+emerges here is that the <code>by()</code>-step can modulate its step to completely override the current traverser and ignore its
 contents for purpose of that step. This ability to override a traverser acts as a powerful and flexible tool as it
 means that each traverser can effectively become a completely different object as determined by a sub-traversal.</p>
 </div>
@@ -1863,7 +1864,7 @@ reconstructed as a new <code>Map</code>
 the two traversals that produce that output (both produce <code>Map</code> objects).</p>
 </li>
 <li>
-<p>The <code>unfold()</code> step is used to decompose the <code>Map</code> objects into key/value entries that are then constructed back
+<p>The <code>unfold()</code>-step is used to decompose the <code>Map</code> objects into key/value entries that are then constructed back
 into a single new <code>Map</code> given the patterns shown earlier. The <code>Map</code> objects of both traversals in the <code>union()</code> are
 essentially merged together.</p>
 </li>
@@ -2043,9 +2044,42 @@ and one for <code>C</code>). This next l
 </ol>
 </div>
 <div class="paragraph">
-<p>The above case assumed that the need was to only detect cycles over a path length of three. It also respected the
-directionality of the edges by only considering outgoing ones. What would need to change to detect cycles of
-arbitrary length over both incoming and outgoing edges in the modern graph?</p>
+<p>The above case assumed that the need was to only detect cycles over a path length of three.
+It also respected the directionality of the edges by only considering outgoing ones.</p>
+</div>
+<div class="paragraph">
+<p>Also note that the traversal above won&#8217;t detect self-loops (vertices directly connected to
+themselves). To do so, you would need to <code>.emit()</code> a Traverser before the repeat()-loop.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="groovy">gremlin&gt; g.addV().property(id,<span class="string"><span class="delimiter">'</span><span class="content">a</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">a</span><span class="delimiter">'</span></span>).
+           addV().property(id,<span class="string"><span class="delimiter">'</span><span class="content">b</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">b</span><span class="delimiter">'</span></span>).
+           addV().property(id,<span class="string"><span class="delimiter">'</span><span class="content">c</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">c</span><span class="delimiter">'</span></span>).
+           addV().property(id,<span class="string"><span class="delimiter">'</span><span class="content">d</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">d</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">knows</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">a</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">b</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">knows</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">b</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">c</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">knows</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">c</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">a</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">knows</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">a</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">d</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">knows</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">c</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">d</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">self</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">a</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">a</span><span class="delimiter">'</span></span>).iterate()
+gremlin&gt; g.V().as(<span class="string"><span class="delimiter">'</span><span class="content">a</span><span class="delimiter">'</span></span>).
+           emit().
+             repeat(outE().inV().simplePath()).
+             times(<span class="integer">2</span>).
+           outE().inV().where(eq(<span class="string"><span class="delimiter">'</span><span class="content">a</span><span class="delimiter">'</span></span>)).
+           path().
+             by(id).
+             by(label)
+==&gt;[a,self,a]
+==&gt;[a,knows,b,knows,c,knows,a]
+==&gt;[b,knows,c,knows,a,knows,b]
+==&gt;[c,knows,a,knows,b,knows,c]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>What would need to change to detect cycles of arbitrary length over both incoming and
+outgoing edges, in the modern graph?</p>
 </div>
 <div class="listingblock">
 <div class="content">
@@ -2294,9 +2328,9 @@ demonstration, an additional edge is add
 <pre class="CodeRay highlight"><code data-lang="groovy">gremlin&gt; g.V(<span class="integer">1</span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">a</span><span class="delimiter">&quot;</span></span>).V(<span class="integer">3</span>).addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>).property(<span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>,<span class="float">0.4d</span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">a</span><span class="delimiter">&quot;</span></span>).iterate()
 gremlin&gt; g.V(<span class="integer">1</span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">a</span><span class="delimiter">&quot;</span></span>).V(<span class="integer">3</span>).addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>).property(<span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>,<span class="float">0.5d</span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">a</span><span class="delimiter">&quot;</span></span>).iterate()
 gremlin&gt; g.V(<span class="integer">1</span>).outE(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>).valueMap(<span class="predefined-constant">true</span>)
-==&gt;[<span class="key">id</span>:<span class="integer">9</span>,<span class="key">weight</span>:<span class="float">0.4</span>,<span class="key">label</span>:created]
-==&gt;[<span class="key">id</span>:<span class="integer">13</span>,<span class="key">weight</span>:<span class="float">0.4</span>,<span class="key">label</span>:created]
-==&gt;[<span class="key">id</span>:<span class="integer">14</span>,<span class="key">weight</span>:<span class="float">0.5</span>,<span class="key">label</span>:created]</code></pre>
+==&gt;[<span class="key">label</span>:created,<span class="key">weight</span>:<span class="float">0.4</span>,<span class="key">id</span>:<span class="integer">9</span>]
+==&gt;[<span class="key">label</span>:created,<span class="key">weight</span>:<span class="float">0.4</span>,<span class="key">id</span>:<span class="integer">13</span>]
+==&gt;[<span class="key">label</span>:created,<span class="key">weight</span>:<span class="float">0.5</span>,<span class="key">id</span>:<span class="integer">14</span>]</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -2312,8 +2346,8 @@ gremlin&gt; g.V(<span class="integer">1<
            where(outV().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">ov</span><span class="delimiter">&quot;</span></span>)).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">e2</span><span class="delimiter">&quot;</span></span>).
            where(<span class="string"><span class="delimiter">&quot;</span><span class="content">e1</span><span class="delimiter">&quot;</span></span>, eq(<span class="string"><span class="delimiter">&quot;</span><span class="content">e2</span><span class="delimiter">&quot;</span></span>)).by(label).
            where(<span class="string"><span class="delimiter">&quot;</span><span class="content">e1</span><span class="delimiter">&quot;</span></span>, eq(<span class="string"><span class="delimiter">&quot;</span><span class="content">e2</span><span class="delimiter">&quot;</span></span>)).by(<span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>).valueMap(<span class="predefined-constant">true</span>)
-==&gt;[<span class="key">id</span>:<span class="integer">13</span>,<span class="key">weight</span>:<span class="float">0.4</span>,<span class="key">label</span>:created]
-==&gt;[<span class="key">id</span>:<span class="integer">9</span>,<span class="key">weight</span>:<span class="float">0.4</span>,<span class="key">label</span>:created]</code></pre>
+==&gt;[<span class="key">label</span>:created,<span class="key">weight</span>:<span class="float">0.4</span>,<span class="key">id</span>:<span class="integer">13</span>]
+==&gt;[<span class="key">label</span>:created,<span class="key">weight</span>:<span class="float">0.4</span>,<span class="key">id</span>:<span class="integer">9</span>]</code></pre>
 </div>
 </div>
 </div>
@@ -2435,6 +2469,107 @@ properties to transfer to the new "moved
 </div>
 </div>
 <div class="sect1">
+<h2 id="element-existence">Element Existence</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>Checking for whether or not a graph element is present in the graph is simple:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="groovy">gremlin&gt; g.V().has(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">marko</span><span class="delimiter">'</span></span>).hasNext()
+==&gt;<span class="predefined-constant">true</span>
+gremlin&gt; g.V().has(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">stephen</span><span class="delimiter">'</span></span>).hasNext()
+==&gt;<span class="predefined-constant">false</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Knowing that an element exists or not is usually a common point of decision in determining the appropriate path of code
+to take. In the example above, the check is for vertex existence and a typical reason to check for existence is to
+determine whether or not to add a new vertex or to return the one that exists (i.e. "get or create" pattern). This
+entire operation can occur in a single traversal.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="groovy">gremlin&gt; g.V().has(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">marko</span><span class="delimiter">'</span></span>).
+           fold().
+           coalesce(unfold(),
+                    addV(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>).
+                      property(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">marko</span><span class="delimiter">'</span></span>).
+                      property(<span class="string"><span class="delimiter">'</span><span class="content">age</span><span class="delimiter">'</span></span>,<span class="integer">29</span>))
+==&gt;v[<span class="integer">1</span>]
+gremlin&gt; g.V().has(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">stephen</span><span class="delimiter">'</span></span>).
+           fold().
+           coalesce(unfold(),
+                    addV(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>).
+                      property(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">stephen</span><span class="delimiter">'</span></span>).
+                      property(<span class="string"><span class="delimiter">'</span><span class="content">age</span><span class="delimiter">'</span></span>,<span class="integer">34</span>))
+==&gt;v[<span class="integer">13</span>]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This use of <code>coalesce()</code> shown above is the basis for this pattern. Note that at the end of <code>has()</code>-step there is
+either a vertex or not. By using <code>fold()</code>, "existence" or "not existence" is reduced to a <code>List</code> with the vertex or
+a <code>List</code> with no values. With a <code>List</code> as the traverser flowing into <code>coalesce()</code> the first child traversal to return
+something will execute. If the <code>List</code> has a vertex then it will <code>unfold()</code> and return the existing one. If it is empty,
+then the vertex does not exist and it is added and returned.</p>
+</div>
+<div class="paragraph">
+<p>This "get or create" logic can be expanded to be "upsert" like functionality as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="groovy">gremlin&gt; g.V().has(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">marko</span><span class="delimiter">'</span></span>).
+           fold().
+           coalesce(unfold(),
+                    addV(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>).property(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">marko</span><span class="delimiter">'</span></span>)).
+           property(<span class="string"><span class="delimiter">'</span><span class="content">age</span><span class="delimiter">'</span></span>,<span class="integer">29</span>)
+==&gt;v[<span class="integer">1</span>]
+gremlin&gt; g.V().has(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">stephen</span><span class="delimiter">'</span></span>).
+           fold().
+           coalesce(unfold(),
+                    addV(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>).property(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">stephen</span><span class="delimiter">'</span></span>)).
+           property(<span class="string"><span class="delimiter">'</span><span class="content">age</span><span class="delimiter">'</span></span>,<span class="integer">34</span>)
+==&gt;v[<span class="integer">13</span>]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>By moving the <code>property()</code>-step that set the "age" value outside of <code>coalesce()</code>, the property is then set for both
+newly created vertices and for existing ones.</p>
+</div>
+<div class="admonitionblock warning">
+<table>
+<tr>
+<td class="icon">
+<div class="title">Warning</div>
+</td>
+<td class="content">
+Always consider the specific nature of the graph implementation in use when considering these patterns. Some
+graph databases may not treat these traversals as true "upsert" operations and may do a "read before write" in their
+execution.
+</td>
+</tr>
+</table>
+</div>
+<div class="paragraph">
+<p>It is possible to do similar sorts of operations with edges using the same pattern:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="groovy">gremlin&gt; g.V().has(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">vadas</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">v</span><span class="delimiter">'</span></span>).
+           V().has(<span class="string"><span class="delimiter">'</span><span class="content">software</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">ripple</span><span class="delimiter">'</span></span>).
+           coalesce(__.inE(<span class="string"><span class="delimiter">'</span><span class="content">created</span><span class="delimiter">'</span></span>).where(outV().as(<span class="string"><span class="delimiter">'</span><span class="content">v</span><span class="delimiter">'</span></span>)),
+                    addE(<span class="string"><span class="delimiter">'</span><span class="content">created</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">v</span><span class="delimiter">'</span></span>).property(<span class="string"><span class="delimiter">'</span><span class="content">weight</span><span class="delimiter">'</span></span>,<span class="float">0.5</span>))
+==&gt;e[<span class="integer">13</span>][<span class="integer">2</span>-created-&gt;<span class="integer">5</span>]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>In this case, the adjacent vertices of the edge are retrieved first and within the <code>coalesce()</code>, the existence of
+the edge is checked with <code>where()</code> using a matching pattern on the "v" label and returned if found. If the edge is not
+found between these two vertices, then it is created as part of the second traversal given to <code>coalesce()</code>.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
 <h2 id="if-then-based-grouping">If-Then Based Grouping</h2>
 <div class="sectionbody">
 <div class="paragraph">
@@ -2579,7 +2714,7 @@ The first traversal above could also be
 <p>In this case, there is no way to know the total count so the only way to know if the end of the results have been
 reached is to count the results from each paged result to see if there&#8217;s less than the number expected or simply zero
 results. In that case, further requests for additional pages would be unnecessary. Of course, this approach is not
-free of problems either. Most graph databases will not optimize the <code>range()</code> step, meaning that the second traversal
+free of problems either. Most graph databases will not optimize the <code>range()</code>-step, meaning that the second traversal
 will repeat the iteration of the first two vertices to get to the second set of two vertices. In other words, for the
 second traversal, the graph will still read four vertices even though there was only a request for two.</p>
 </div>
@@ -2597,6 +2732,24 @@ gremlin&gt; t.next(<span class="integer"
 ==&gt;v[<span class="integer">6</span>]</code></pre>
 </div>
 </div>
+<div class="paragraph">
+<p>A further consideration relates to the order in which results are returned. TinkerPop does not guarantee that the
+order of the items returned on the same traversal will be the same order each time the traversal is iterated.
+TinkerPop only guarantees that it does not re-shuffle the order provided by the underlying graph database. This
+guarantee has two implications:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Iteration order is dependent on the underlying graph database. Some graphs may guarantee ordering and some may not
+and still some others may guarantee ordering but only under certain conditions. Consult the documentation of the
+graph database for more information on this.</p>
+</li>
+<li>
+<p>Use <code>order()</code>-step to make iteration order explicit if guarantees are required.</p>
+</li>
+</ol>
+</div>
 </div>
 </div>
 <div class="sect1">
@@ -3487,7 +3640,7 @@ single result.</p>
 <div class="paragraph">
 <p>The previous approaches to calculating the maximum depth use path calculations to achieve the answer. Path calculations
 can be expensive and if possible avoided if they are not needed. Another way to express a traversal that calculates
-the maximum depth is to use the <code>sack()</code> step:</p>
+the maximum depth is to use the <code>sack()</code>-step:</p>
 </div>
 <div class="listingblock">
 <div class="content">
@@ -3717,7 +3870,7 @@ gremlin&gt; archivePath = <span class="s
 gremlin&gt; [<span class="string"><span class="delimiter">'</span><span class="content">bash</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">-c</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">rm -f </span><span class="inline"><span class="inline-delimiter">$</span>archivePath</span><span class="content">; cd ext/spark-gremlin/lib &amp;&amp; zip </span><span class="inline"><span class="inline-delimiter">$</span>archivePath</span><span class="content"> *.jar</span><span class="delimiter">&quot;</span></span>].execute().waitFor()
 ==&gt;<span class="integer">0</span>
 gremlin&gt; conf = <span class="keyword">new</span> PropertiesConfiguration(<span class="string"><span class="delimiter">'</span><span class="content">conf/hadoop/hadoop-gryo.properties</span><span class="delimiter">'</span></span>)
-==&gt;org.apache.commons.configuration.PropertiesConfiguration<span class="error">@</span><span class="integer">138</span>aa3cc
+==&gt;org.apache.commons.configuration.PropertiesConfiguration<span class="error">@</span><span class="integer">521</span>bb1a4
 gremlin&gt; conf.setProperty(<span class="string"><span class="delimiter">'</span><span class="content">spark.master</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">yarn-client</span><span class="delimiter">'</span></span>)
 gremlin&gt; conf.setProperty(<span class="string"><span class="delimiter">'</span><span class="content">spark.yarn.dist.archives</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="inline"><span class="inline-delimiter">$</span>archivePath</span><span class="delimiter">&quot;</span></span>)
 gremlin&gt; conf.setProperty(<span class="string"><span class="delimiter">'</span><span class="content">spark.yarn.appMasterEnv.CLASSPATH</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">./</span><span class="inline"><span class="inline-delimiter">$</span>archive</span><span class="content">/*:</span><span class="inline"><span class="inline-delimiter">$</span>hadoopConfDir</span><span class="delimiter">&quot;</span></span>)
@@ -3911,7 +4064,7 @@ lead to optimal representations. However
 <p>Good software development practices require reuse to keep software maintainable. In Gremlin, there are often bits of
 traversal logic that could be represented as components that might be tested independently and utilized
 as part of other traversals. One approach to doing this would be to extract such logic into an anonymous traversal
-and provide it to a parent traversal through <code>flatMap()</code> step.</p>
+and provide it to a parent traversal through <code>flatMap()</code>-step.</p>
 </div>
 <div class="paragraph">
 <p>Using the modern toy graph as an example, assume that there are number of traversals that are interested in filtering
@@ -3942,7 +4095,7 @@ gremlin&gt; g.V(<span class="integer">1<
 <div class="paragraph">
 <p>The <code>weightFilter</code> is an anonymous traversal and it is created by way <code><em></code> class. The <code></em></code> is omitted above from
 initalization of <code>weightFilter</code> because it is statically imported to the Gremlin Console. The <code>weightFilter</code> gets
-passed to the "full" traversal by way for <code>flatMap()</code> step and the results are the same. Of course, there is a problem.
+passed to the "full" traversal by way for <code>flatMap()</code>-step and the results are the same. Of course, there is a problem.
 If there is an attempt to use that <code>weightFilter</code> a second time, the traversal with thrown an exception because both
 the <code>weightFilter</code> and parent traversal have been "compiled" which prevents their re-use. A simple fix to this would
 be to clone the <code>weightFilter</code>.</p>
@@ -3972,7 +4125,7 @@ the anonymous traversal itself.</p>
 <div class="listingblock">
 <div class="content">
 <pre class="CodeRay highlight"><code data-lang="groovy">gremlin&gt; weightFilter = { w -&gt; outE(<span class="string"><span class="delimiter">&quot;</span><span class="content">knows</span><span class="delimiter">&quot;</span></span>).has(<span class="string"><span class="delimiter">'</span><span class="content">weight</span><span class="delimiter">'</span></span>, P.gt(w)).inV() }
-==&gt;groovysh_evaluate<span class="error">$</span>_run_closure1<span class="error">@</span><span class="integer">7</span>cf78c85
+==&gt;groovysh_evaluate<span class="error">$</span>_run_closure1<span class="error">@</span><span class="integer">7</span>c781c42
 gremlin&gt; g.V(<span class="integer">1</span>).flatMap(weightFilter(<span class="float">0.5d</span>)).both()
 ==&gt;v[<span class="integer">5</span>]
 ==&gt;v[<span class="integer">3</span>]
@@ -4472,7 +4625,7 @@ gremlin&gt;  g.withSack(<span class="flo
 </div>
 <div id="footer">
 <div id="footer-text">
-Last updated 2018-05-11 13:48:50 EDT
+Last updated 2018-10-12 19:20:40 EDT
 </div>
 </div>
 </body>