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 2017/01/10 18:47:51 UTC

svn commit: r1778175 [2/22] - in /tinkerpop/site: docs/3.2.4-SNAPSHOT/dev/provider/ docs/3.2.4-SNAPSHOT/images/ docs/3.2.4-SNAPSHOT/recipes/ docs/3.2.4-SNAPSHOT/reference/ docs/3.2.4-SNAPSHOT/tutorials/the-gremlin-console/ javadocs/3.2.4-SNAPSHOT/core/...

Modified: tinkerpop/site/docs/3.2.4-SNAPSHOT/recipes/index.html
URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.4-SNAPSHOT/recipes/index.html?rev=1778175&r1=1778174&r2=1778175&view=diff
==============================================================================
--- tinkerpop/site/docs/3.2.4-SNAPSHOT/recipes/index.html (original)
+++ tinkerpop/site/docs/3.2.4-SNAPSHOT/recipes/index.html Tue Jan 10 18:47:50 2017
@@ -810,7 +810,10 @@ span.line-numbers { border-right: 1px so
 <li><a href="#eigenvector-centrality">Eigenvector Centrality</a></li>
 </ul>
 </li>
+<li><a href="#connected-components">Connected Components</a></li>
 <li><a href="#cycle-detection">Cycle Detection</a></li>
+<li><a href="#duplicate-edge">Duplicate Edge Detection</a></li>
+<li><a href="#duplicate-vertex">Duplicate Vertex Detection</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>
@@ -839,6 +842,7 @@ span.line-numbers { border-right: 1px so
 </ul>
 </li>
 <li><a href="#contributing">How to Contribute a Recipe</a></li>
+<li><a href="#_appendix">Appendix</a></li>
 </ul>
 </div>
 </div>
@@ -1245,7 +1249,6 @@ give it the highest rank. Consider the f
 <div class="listingblock">
 <div class="content">
 <pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; graph.io(graphml()).readGraph(<span class="string"><span class="delimiter">'</span><span class="content">data/grateful-dead.xml</span><span class="delimiter">'</span></span>)
-==&gt;<span class="predefined-constant">null</span>
 gremlin&gt; g.V().repeat(groupCount(<span class="string"><span class="delimiter">'</span><span class="content">m</span><span class="delimiter">'</span></span>).by(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>).out()).times(<span class="integer">5</span>).cap(<span class="string"><span class="delimiter">'</span><span class="content">m</span><span class="delimiter">'</span></span>). <span class="comment">//</span><b>(1)</b>
            order(local).by(values, decr).limit(local, <span class="integer">10</span>).next() <span class="comment">//</span><b>(2)</b>
 ==&gt;PLAYING IN THE BAND=<span class="integer">8758598</span>
@@ -1297,6 +1300,107 @@ can shorten the time required to get a r
 </div>
 </div>
 <div class="sect1">
+<h2 id="connected-components">Connected Components</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>Gremlin can be used to find <a href="https://en.wikipedia.org/wiki/Connected_component_(graph_theory)">connected components</a>
+in a graph. Consider the following graph which has three connected components:</p>
+</div>
+<div class="paragraph">
+<p><span class="image"><img src="../images/connected-components.png" alt="connected-components" width="600"></span></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.addV(id, <span class="string"><span class="delimiter">&quot;</span><span class="content">A</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">a</span><span class="delimiter">&quot;</span></span>).
+           addV(id, <span class="string"><span class="delimiter">&quot;</span><span class="content">B</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">b</span><span class="delimiter">&quot;</span></span>).
+           addV(id, <span class="string"><span class="delimiter">&quot;</span><span class="content">C</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">c</span><span class="delimiter">&quot;</span></span>).
+           addV(id, <span class="string"><span class="delimiter">&quot;</span><span class="content">D</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">d</span><span class="delimiter">&quot;</span></span>).
+           addV(id, <span class="string"><span class="delimiter">&quot;</span><span class="content">E</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">e</span><span class="delimiter">&quot;</span></span>).
+           addV(id, <span class="string"><span class="delimiter">&quot;</span><span class="content">F</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">link</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">a</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">b</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">link</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">b</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">c</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">link</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">d</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">e</span><span class="delimiter">&quot;</span></span>).iterate()</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>One way to detect the various subgraphs would be to do something like this:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.V().emit(cyclicPath().or().not(both())).repeat(both()).until(cyclicPath()). <span class="comment">//</span><b>(1)</b>
+           aggregate(<span class="string"><span class="delimiter">&quot;</span><span class="content">p</span><span class="delimiter">&quot;</span></span>).by(path()).cap(<span class="string"><span class="delimiter">&quot;</span><span class="content">p</span><span class="delimiter">&quot;</span></span>). <span class="comment">//</span><b>(2)</b>
+           unfold().limit(local, <span class="integer">1</span>).dedup(). <span class="comment">//</span><b>(3)</b>
+           map(__.as(<span class="string"><span class="delimiter">&quot;</span><span class="content">v</span><span class="delimiter">&quot;</span></span>).select(<span class="string"><span class="delimiter">&quot;</span><span class="content">p</span><span class="delimiter">&quot;</span></span>).unfold(). <span class="comment">//</span><b>(4)</b>
+                  filter(unfold().where(eq(<span class="string"><span class="delimiter">&quot;</span><span class="content">v</span><span class="delimiter">&quot;</span></span>))).
+                  unfold().dedup().order().by(id).fold()
+           ).dedup() <span class="comment">//</span><b>(5)</b>
+==&gt;[v[A],v[B],v[C]]
+==&gt;[v[D],v[E]]
+==&gt;[v[F]]</code></pre>
+</div>
+</div>
+<div class="colist arabic">
+<ol>
+<li>
+<p>Iterate all vertices and repeatedly traverse over both incoming and outgoing edges (TinkerPop doesn&#8217;t support
+unidirectional graphs directly so it must be simulated by ignoring the direction with <code>both</code>). Note the use of <code>emit</code>
+prior to <code>repeat</code> as this allows for return of a single length path.</p>
+</li>
+<li>
+<p>Aggregate the emitted vertices to "p" and get their path information. Calling <code>cap</code> at the end will push the
+aggregate path list into the traversal. It is within these paths that the list of connected components will be
+identified. Obviously the paths list are duplicative in the sense that they contains different paths travelled over
+the same vertices.</p>
+</li>
+<li>
+<p>Unroll the elements in the path list with <code>unfold</code> and grab the first vertex in each path and <code>dedup</code>.</p>
+</li>
+<li>
+<p>Use the first vertex in each path to filter against the paths stored in "p". When a path is found that has the
+vertex in it, dedup the vertices in the path, order it by the identifier. Each path output from this <code>map</code> step
+represents a connected component.</p>
+</li>
+<li>
+<p>The connected component list is duplicative given the nature of the paths in "p", but now that the vertices within
+the paths are ordered, a final <code>dedup</code> will make the list of connective components unique.</p>
+</li>
+</ol>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<div class="title">Note</div>
+</td>
+<td class="content">
+This is a nice example of where running smaller pieces of a large Gremlin statement make it easier to see what
+is happening at each step. Consider running this example one line at a time (or perhaps even in a step at a time) to
+see the output at each point.
+</td>
+</tr>
+</table>
+</div>
+<div class="paragraph">
+<p>While the above approach returns results nicely, the traversal doesn&#8217;t appear to work with OLAP. A less efficient
+approach, but one more suited for OLAP execution looks quite similar but does not use <code>dedup</code> as heavily (thus
+<code>GraphComputer</code> is forced to analyze far more paths):</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.withComputer().V().emit(cyclicPath().or().not(both())).repeat(both()).until(cyclicPath()).
+           aggregate(<span class="string"><span class="delimiter">&quot;</span><span class="content">p</span><span class="delimiter">&quot;</span></span>).by(path()).cap(<span class="string"><span class="delimiter">&quot;</span><span class="content">p</span><span class="delimiter">&quot;</span></span>).unfold().limit(local, <span class="integer">1</span>).
+           map(__.as(<span class="string"><span class="delimiter">&quot;</span><span class="content">v</span><span class="delimiter">&quot;</span></span>).select(<span class="string"><span class="delimiter">&quot;</span><span class="content">p</span><span class="delimiter">&quot;</span></span>).unfold().
+                  filter(unfold().where(eq(<span class="string"><span class="delimiter">&quot;</span><span class="content">v</span><span class="delimiter">&quot;</span></span>))).
+                  unfold().dedup().order().by(id).fold()
+           ).toSet()
+==&gt;[v[A],v[B],v[C]]
+==&gt;[v[D],v[E]]
+==&gt;[v[F]]</code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
 <h2 id="cycle-detection">Cycle Detection</h2>
 <div class="sectionbody">
 <div class="paragraph">
@@ -1356,6 +1460,310 @@ arbitrary length over both incoming and
 ==&gt;[v[<span class="integer">1</span>],v[<span class="integer">3</span>],v[<span class="integer">4</span>],v[<span class="integer">1</span>]]</code></pre>
 </div>
 </div>
+<div class="paragraph">
+<p>An interesting type of cycle is known as the Eulerian circuit which is a path taken in a graph where each edge is
+visited once and the path starts and ends with the same vertex. Consider the following graph, representative of an
+imaginary but geographically similar <a href="https://en.wikipedia.org/wiki/Seven_Bridges_of_K%C3%B6nigsberg">Königsberg</a>
+that happens to have an eighth bridge (the diagram depicts edge direction but direction won&#8217;t be considered in the traversal):</p>
+</div>
+<div class="paragraph">
+<p><span class="image"><img src="../images/eulerian-circuit.png" alt="eulerian-circuit" width="500"></span></p>
+</div>
+<div class="paragraph">
+<p>Gremlin can detect if such a cycle exists with:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.addV().property(id, <span class="string"><span class="delimiter">'</span><span class="content">blue</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">orange</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">o</span><span class="delimiter">'</span></span>).
+           addV().property(id, <span class="string"><span class="delimiter">'</span><span class="content">red</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">r</span><span class="delimiter">'</span></span>).
+           addV().property(id, <span class="string"><span class="delimiter">'</span><span class="content">green</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">g</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">bridge</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">g</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">bridge</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">g</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">o</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">bridge</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">g</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">r</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">bridge</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">g</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">r</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">bridge</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">o</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">bridge</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">o</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">bridge</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">o</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">r</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">bridge</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">o</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">r</span><span class="delimiter">'</span></span>).iterate()
+gremlin&gt; g.V().sideEffect(outE(<span class="string"><span class="delimiter">&quot;</span><span class="content">bridge</span><span class="delimiter">&quot;</span></span>).aggregate(<span class="string"><span class="delimiter">&quot;</span><span class="content">bridges</span><span class="delimiter">&quot;</span></span>)).barrier(). <span class="comment">//</span><b>(1)</b>
+           repeat(bothE(). <span class="comment">//</span><b>(2)</b>
+                  or(__.not(select(<span class="string"><span class="delimiter">'</span><span class="content">e</span><span class="delimiter">'</span></span>)),
+                     __.not(filter(__.as(<span class="string"><span class="delimiter">'</span><span class="content">x</span><span class="delimiter">'</span></span>).select(all, <span class="string"><span class="delimiter">'</span><span class="content">e</span><span class="delimiter">'</span></span>).unfold(). <span class="comment">//</span><b>(3)</b>
+                            where(eq(<span class="string"><span class="delimiter">'</span><span class="content">x</span><span class="delimiter">'</span></span>))))).as(<span class="string"><span class="delimiter">'</span><span class="content">e</span><span class="delimiter">'</span></span>).
+                  otherV()).
+             until(select(all, <span class="string"><span class="delimiter">'</span><span class="content">e</span><span class="delimiter">'</span></span>).count(local).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">c</span><span class="delimiter">&quot;</span></span>). <span class="comment">//</span><b>(4)</b>
+                   select(<span class="string"><span class="delimiter">&quot;</span><span class="content">bridges</span><span class="delimiter">&quot;</span></span>).count(local).where(eq(<span class="string"><span class="delimiter">&quot;</span><span class="content">c</span><span class="delimiter">&quot;</span></span>))).hasNext()
+==&gt;<span class="predefined-constant">true</span></code></pre>
+</div>
+</div>
+<div class="colist arabic">
+<ol>
+<li>
+<p>Gather all the edges in a "bridges" side effect.</p>
+</li>
+<li>
+<p>As mentioned earlier with the diagram, directionality is ignored as the traversal uses <code>bothE</code> and, later, <code>otherV</code>.</p>
+</li>
+<li>
+<p>In continually traversing over both incoming and outgoing edges, this path is only worth continuing if the edges
+traversed thus far are only traversed once. That set of edges is maintained in "e".</p>
+</li>
+<li>
+<p>The traversal should repeat until the number of edges traversed in "e" is equal to the total number gathered in
+the first step above, which would mean that the complete circuit has been made.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>Unlike Königsberg, with just seven bridges, a Eulerian circuit exists in the case with an eighth bridge. The first
+detected circuit can be displayed with:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.V().sideEffect(outE(<span class="string"><span class="delimiter">&quot;</span><span class="content">bridge</span><span class="delimiter">&quot;</span></span>).aggregate(<span class="string"><span class="delimiter">&quot;</span><span class="content">bridges</span><span class="delimiter">&quot;</span></span>)).barrier().
+           repeat(bothE().or(__.not(select(<span class="string"><span class="delimiter">'</span><span class="content">e</span><span class="delimiter">'</span></span>)),
+                             __.not(filter(__.as(<span class="string"><span class="delimiter">'</span><span class="content">x</span><span class="delimiter">'</span></span>).select(all, <span class="string"><span class="delimiter">'</span><span class="content">e</span><span class="delimiter">'</span></span>).unfold().
+                                    where(eq(<span class="string"><span class="delimiter">'</span><span class="content">x</span><span class="delimiter">'</span></span>))))).as(<span class="string"><span class="delimiter">'</span><span class="content">e</span><span class="delimiter">'</span></span>).otherV()).
+             until(select(all, <span class="string"><span class="delimiter">'</span><span class="content">e</span><span class="delimiter">'</span></span>).count(local).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">c</span><span class="delimiter">&quot;</span></span>).
+                   select(<span class="string"><span class="delimiter">&quot;</span><span class="content">bridges</span><span class="delimiter">&quot;</span></span>).count(local).where(eq(<span class="string"><span class="delimiter">&quot;</span><span class="content">c</span><span class="delimiter">&quot;</span></span>))).limit(<span class="integer">1</span>).
+           path().by(id).by(constant(<span class="string"><span class="delimiter">&quot;</span><span class="content"> -&gt; </span><span class="delimiter">&quot;</span></span>)).
+           map {<span class="predefined-type">String</span>.join(<span class="string"><span class="delimiter">&quot;</span><span class="delimiter">&quot;</span></span>, <span class="local-variable">it</span>.get().objects())}
+==&gt;orange -&gt; blue -&gt; green -&gt; orange -&gt; red -&gt; green -&gt; red -&gt; orange -&gt; blue</code></pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="duplicate-edge">Duplicate Edge Detection</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>Whether part of a graph maintenance process or for some other analysis need, it is sometimes necessary to detect
+if there is more than one edge between two vertices. The following examples will assume that an edge with the same
+label and direction will be considered "duplicate".</p>
+</div>
+<div class="paragraph">
+<p>The "modern" graph does not have any duplicate edges that fit that definition, so the following example adds one
+that is duplicative of the "created" edge between vertex "1" and "3".</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-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>).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>)
+==&gt;e[<span class="integer">9</span>][<span class="integer">1</span>-created-&gt;<span class="integer">3</span>]
+==&gt;e[<span class="integer">12</span>][<span class="integer">1</span>-created-&gt;<span class="integer">3</span>]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>One way to find the duplicate edges would be to do something like this:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.V().outE().
+           project(<span class="string"><span class="delimiter">&quot;</span><span class="content">a</span><span class="delimiter">&quot;</span></span>,<span class="string"><span class="delimiter">&quot;</span><span class="content">b</span><span class="delimiter">&quot;</span></span>). <span class="comment">//</span><b>(1)</b>
+             by().by(inV().path().by().by(label)).
+           group(). <span class="comment">//</span><b>(2)</b>
+             by(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">b</span><span class="delimiter">&quot;</span></span>)).
+             by(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">a</span><span class="delimiter">&quot;</span></span>).fold()).
+           unfold(). <span class="comment">//</span><b>(3)</b>
+           select(values). <span class="comment">//</span><b>(4)</b>
+           where(count(local).is(gt(<span class="integer">1</span>)))
+==&gt;[e[<span class="integer">9</span>][<span class="integer">1</span>-created-&gt;<span class="integer">3</span>],e[<span class="integer">12</span>][<span class="integer">1</span>-created-&gt;<span class="integer">3</span>]]</code></pre>
+</div>
+</div>
+<div class="colist arabic">
+<ol>
+<li>
+<p>The "a" and "b" from the <code>project</code> contain the edge and the path respectively. The path consists of a the outgoing
+vertex, an edge, and the incoming vertex. The use of <code>by().by(label))</code> converts the edge to its label (recall that <code>by</code>
+are applied in round-robin fashion), so the path will look something like: <code>[v[1],created,v[3]]</code>.</p>
+</li>
+<li>
+<p>Group by the path from "b" and construct a list of edges from "a". Any value in this <code>Map</code> that has a list of edges
+greater than one means that there is more than one edge for that edge label between those two vertices (i.e. the <code>Map</code>
+key).</p>
+</li>
+<li>
+<p>Unroll the key-value pairs in the <code>Map</code> of paths-edges.</p>
+</li>
+<li>
+<p>Only the values from the <code>Map</code> are needed and as mentioned earlier, those lists with more than one edge would
+containa  duplicate.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>This method find the duplicates, but does require more memory than other approaches. A slightly more complex approach
+that uses less memory might look like this:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.V().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">ov</span><span class="delimiter">&quot;</span></span>).
+           outE().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">e</span><span class="delimiter">&quot;</span></span>).
+           inV().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">iv</span><span class="delimiter">&quot;</span></span>).
+           inE(). <span class="comment">//</span><b>(1)</b>
+           where(neq(<span class="string"><span class="delimiter">&quot;</span><span class="content">e</span><span class="delimiter">&quot;</span></span>)). <span class="comment">//</span><b>(2)</b>
+           where(eq(<span class="string"><span class="delimiter">&quot;</span><span class="content">e</span><span class="delimiter">&quot;</span></span>)).by(label).
+           where(outV().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">ov</span><span class="delimiter">&quot;</span></span>)).
+           group().
+             by(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">ov</span><span class="delimiter">&quot;</span></span>,<span class="string"><span class="delimiter">&quot;</span><span class="content">e</span><span class="delimiter">&quot;</span></span>,<span class="string"><span class="delimiter">&quot;</span><span class="content">iv</span><span class="delimiter">&quot;</span></span>).by().by(label)). <span class="comment">//</span><b>(3)</b>
+           unfold(). <span class="comment">//</span><b>(4)</b>
+           select(values).
+           where(count(local).is(gt(<span class="integer">1</span>)))
+==&gt;[e[<span class="integer">12</span>][<span class="integer">1</span>-created-&gt;<span class="integer">3</span>],e[<span class="integer">9</span>][<span class="integer">1</span>-created-&gt;<span class="integer">3</span>]]</code></pre>
+</div>
+</div>
+<div class="colist arabic">
+<ol>
+<li>
+<p>To this point in the traversal, the outgoing edges of a vertex are being iterated with the current edge labelled
+as "e". For "e", Gremlin traverses to the incoming vertex and back on in edges of that vertex.</p>
+</li>
+<li>
+<p>Those incoming edges are filtered with the following <code>where</code> steps. The first ensures that it does not traverse
+back over "e" (i.e. the current edge). The second determines if the edge label is equivalent (i.e. the test for the
+working definition of "duplicate"). The third determines if the outgoing vertex matches the one that started the
+path labelled as "ov".</p>
+</li>
+<li>
+<p>This line is quite similar to the output achieved in the previous example at step 2. A <code>Map</code> is produced that uses
+the outgoing vertex, the edge label, and the incoming vertex as the key, with the list of edges for that path as the
+value.</p>
+</li>
+<li>
+<p>The rest of the traversal is the same as the previous one.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>A third way to approach this problem would be to force a <a href="https://en.wikipedia.org/wiki/Depth-first_search">depth-first search</a>.
+The previous examples invoke traversal strategies that force a <a href="https://en.wikipedia.org/wiki/Breadth-first_search">breadth first search</a>
+as a performance optimization.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.withoutStrategies(LazyBarrierStrategy, PathRetractionStrategy).V().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">ov</span><span class="delimiter">&quot;</span></span>). <span class="comment">//</span><b>(1)</b>
+           outE().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">e1</span><span class="delimiter">&quot;</span></span>).
+           inV().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">iv</span><span class="delimiter">&quot;</span></span>).
+           inE().
+           where(neq(<span class="string"><span class="delimiter">&quot;</span><span class="content">e1</span><span class="delimiter">&quot;</span></span>)).
+           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>). <span class="comment">//</span><b>(2)</b>
+           filter(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">e1</span><span class="delimiter">&quot;</span></span>,<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>))) <span class="comment">//</span><b>(3)</b>
+==&gt;e[<span class="integer">12</span>][<span class="integer">1</span>-created-&gt;<span class="integer">3</span>]
+==&gt;e[<span class="integer">9</span>][<span class="integer">1</span>-created-&gt;<span class="integer">3</span>]</code></pre>
+</div>
+</div>
+<div class="colist arabic">
+<ol>
+<li>
+<p>Remove strategies that will optimize for breadth first searches and thus allow Gremlin to go depth first.</p>
+</li>
+<li>
+<p>To this point, the traversal is very much like the previous one. Review step 2 in the previous example to see the
+parallels here.</p>
+</li>
+<li>
+<p>The final <code>filter</code> simply looks for edges that match on label, which would then meet the working definition of
+"duplicate".</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>The basic pattern at play here is to compare the path of the outgoing vertex, its outgoing edge label and the incoming
+vertex. This model can obviously be contracted or expanded as needed to fit different definitions of "duplicate" For
+example, if the definition of "duplicate" was just two vertices with more than one edge of any label between them, then
+the approach might look something like this:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy"></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Alternatively, a "duplicate" definition could extended to the label and properties of the edge. For purposes of
+demonstration, an additional edge is added to the "modern" graph:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g = TinkerFactory.createModern().traversal()
+==&gt;graphtraversalsource[tinkergraph[<span class="key">vertices</span>:<span class="integer">6</span> <span class="key">edges</span>:<span class="integer">6</span>], standard]
+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">12</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.5</span>,<span class="key">label</span>:created]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>To identify the duplicate with this revised definition, the previous traversal can be modified to:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.withoutStrategies(LazyBarrierStrategy, PathRetractionStrategy).V().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">ov</span><span class="delimiter">&quot;</span></span>).
+           outE().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">e1</span><span class="delimiter">&quot;</span></span>).
+           inV().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">iv</span><span class="delimiter">&quot;</span></span>).
+           inE().
+           where(neq(<span class="string"><span class="delimiter">&quot;</span><span class="content">e1</span><span class="delimiter">&quot;</span></span>)).
+           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>).
+           filter(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">e1</span><span class="delimiter">&quot;</span></span>,<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>))).
+           filter(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">e1</span><span class="delimiter">&quot;</span></span>,<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>).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>))).valueMap(<span class="predefined-constant">true</span>)
+==&gt;[<span class="key">id</span>:<span class="integer">12</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>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="duplicate-vertex">Duplicate Vertex Detection</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>The pattern for finding duplicate vertices is quite similar to the pattern defined in the <a href="#duplicate-edge">Duplicate Edge</a>
+section. The idea is to extract the relevant features of the vertex into a comparable list that can then be used to
+group for duplicates.</p>
+</div>
+<div class="paragraph">
+<p>Consider the following example with some duplicate vertices added to the "modern" graph:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.addV(label, <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>, <span class="string"><span class="delimiter">'</span><span class="content">age</span><span class="delimiter">'</span></span>, <span class="integer">27</span>)
+==&gt;v[<span class="integer">12</span>]
+gremlin&gt; g.addV(label, <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>, <span class="string"><span class="delimiter">'</span><span class="content">age</span><span class="delimiter">'</span></span>, <span class="integer">22</span>) <span class="comment">// not a duplicate because &quot;age&quot; value</span>
+==&gt;v[<span class="integer">15</span>]
+gremlin&gt; g.addV(label, <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>, <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">18</span>]
+gremlin&gt; g.V().hasLabel(<span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>).
+           group().
+             by(values(<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">age</span><span class="delimiter">&quot;</span></span>).fold()).
+           unfold()
+==&gt;[marko, <span class="integer">29</span>]=[v[<span class="integer">1</span>], v[<span class="integer">18</span>]]
+==&gt;[vadas, <span class="integer">27</span>]=[v[<span class="integer">2</span>], v[<span class="integer">12</span>]]
+==&gt;[peter, <span class="integer">35</span>]=[v[<span class="integer">6</span>]]
+==&gt;[vadas, <span class="integer">22</span>]=[v[<span class="integer">15</span>]]
+==&gt;[josh, <span class="integer">32</span>]=[v[<span class="integer">4</span>]]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>In the above case, the "name" and "age" properties are the relevant features for identifying duplication. The key in
+the <code>Map</code> provided by the <code>group</code> is the list of features for comparison and the value is the list of vertices that
+match the feature. To extract just those vertices that contain duplicates an additional filter can be added:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.V().hasLabel(<span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>).
+           group().
+             by(values(<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">age</span><span class="delimiter">&quot;</span></span>).fold()).
+           unfold().
+           filter(select(values).count(local).is(gt(<span class="integer">1</span>)))
+==&gt;[marko, <span class="integer">29</span>]=[v[<span class="integer">1</span>], v[<span class="integer">18</span>]]
+==&gt;[vadas, <span class="integer">27</span>]=[v[<span class="integer">2</span>], v[<span class="integer">12</span>]]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>That filter, extracts the values of the <code>Map</code> and counts the vertices within each list. If that list contains more than
+one vertex then it is a duplicate.</p>
+</div>
 </div>
 </div>
 <div class="sect1">
@@ -2015,6 +2423,75 @@ itself.</p>
 </ol>
 </div>
 <div class="paragraph">
+<p>As another example of how traversal induced values can be used, consider a scenario where there was a graph that
+contained people, their friendship relationships, and the movies that they liked.</p>
+</div>
+<div class="paragraph">
+<p><span class="image"><img src="../images/traversal-induced-values-3.png" alt="traversal-induced-values-3" width="600"></span></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.addV(<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">alice</span><span class="delimiter">&quot;</span></span>, label, <span class="string"><span class="delimiter">&quot;</span><span class="content">user</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">u1</span><span class="delimiter">&quot;</span></span>).
+           addV(<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">jen</span><span class="delimiter">&quot;</span></span>, label, <span class="string"><span class="delimiter">&quot;</span><span class="content">user</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">u2</span><span class="delimiter">&quot;</span></span>).
+           addV(<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">dave</span><span class="delimiter">&quot;</span></span>, label, <span class="string"><span class="delimiter">&quot;</span><span class="content">user</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">u3</span><span class="delimiter">&quot;</span></span>).
+           addV(<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">the wild bunch</span><span class="delimiter">&quot;</span></span>, label, <span class="string"><span class="delimiter">&quot;</span><span class="content">movie</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">m1</span><span class="delimiter">&quot;</span></span>).
+           addV(<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">young guns</span><span class="delimiter">&quot;</span></span>, label, <span class="string"><span class="delimiter">&quot;</span><span class="content">movie</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">m2</span><span class="delimiter">&quot;</span></span>).
+           addV(<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">unforgiven</span><span class="delimiter">&quot;</span></span>, label, <span class="string"><span class="delimiter">&quot;</span><span class="content">movie</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">m3</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">friend</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">u1</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">u2</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">friend</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">u1</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">u3</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">like</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">u2</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">m1</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">like</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">u2</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">m2</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">like</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">u3</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">m2</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">like</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">u3</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">m3</span><span class="delimiter">&quot;</span></span>).iterate()</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Getting a list of all the movies that Alice&#8217;s friends like could be done like this:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.V().has(<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">alice</span><span class="delimiter">'</span></span>).out(<span class="string"><span class="delimiter">&quot;</span><span class="content">friend</span><span class="delimiter">&quot;</span></span>).out(<span class="string"><span class="delimiter">&quot;</span><span class="content">like</span><span class="delimiter">&quot;</span></span>).values(<span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>)
+==&gt;the wild bunch
+==&gt;young guns
+==&gt;young guns
+==&gt;unforgiven</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>but what if there was a need to get a list of movies that <strong>all</strong> her Alice&#8217;s friends liked. In this case, that would
+mean filtering out "the wild bunch" and "unforgiven".</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.V().has(<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">alice</span><span class="delimiter">&quot;</span></span>).
+           out(<span class="string"><span class="delimiter">&quot;</span><span class="content">friend</span><span class="delimiter">&quot;</span></span>).aggregate(<span class="string"><span class="delimiter">&quot;</span><span class="content">friends</span><span class="delimiter">&quot;</span></span>). <span class="comment">//</span><b>(1)</b>
+           out(<span class="string"><span class="delimiter">&quot;</span><span class="content">like</span><span class="delimiter">&quot;</span></span>).dedup(). <span class="comment">//</span><b>(2)</b>
+           filter(__.in(<span class="string"><span class="delimiter">&quot;</span><span class="content">like</span><span class="delimiter">&quot;</span></span>).where(within(<span class="string"><span class="delimiter">&quot;</span><span class="content">friends</span><span class="delimiter">&quot;</span></span>)).count().as(<span class="string"><span class="delimiter">&quot;</span><span class="content">a</span><span class="delimiter">&quot;</span></span>). <span class="comment">//</span><b>(3)</b>
+                     select(<span class="string"><span class="delimiter">&quot;</span><span class="content">friends</span><span class="delimiter">&quot;</span></span>).count(local).where(eq(<span class="string"><span class="delimiter">&quot;</span><span class="content">a</span><span class="delimiter">&quot;</span></span>))). <span class="comment">//</span><b>(4)</b>
+           values(<span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>)
+==&gt;young guns</code></pre>
+</div>
+</div>
+<div class="colist arabic">
+<ol>
+<li>
+<p>Gather Alice&#8217;s list of friends to a list called "friends".</p>
+</li>
+<li>
+<p>Traverse to the unique list of movies that Alice&#8217;s friends like.</p>
+</li>
+<li>
+<p>Remove movies that weren&#8217;t liked by all friends. This starts by taking each movie and traversing back in on the
+"like" edges to friends who liked the movie (note the use of <code>where(within("friends"))</code> to limit those likes to only
+Alice&#8217;s friends as aggregated in step one) and count them up into "a".</p>
+</li>
+<li>
+<p>Count the aggregated friends and see if the number matches what was stored in "a" which would mean that all friends
+like the movie.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
 <p>Traversal induced values are not just for filtering. They can also be used when writing the values of the properties
 of one <code>Vertex</code> to another:</p>
 </div>
@@ -2027,6 +2504,87 @@ gremlin&gt; g.V().has(<span class="strin
 ==&gt;[<span class="key">creator</span>:[marko],<span class="key">name</span>:[lop],<span class="key">lang</span>:[java]]</code></pre>
 </div>
 </div>
+<div class="paragraph">
+<p>In a more complex example of how this might work, consider a situation where the goal is to propagate a value stored on
+a particular vertex through one of more additional connected vertices using some value on the connecting edges to
+determine the value to assign. For example, the following graph depicts three "tank" vertices where the edges represent
+the direction a particular "tank" should drain and the "factor" by which it should do it:</p>
+</div>
+<div class="paragraph">
+<p><span class="image"><img src="../images/traversal-induced-values-1.png" alt="traversal-induced-values-1" width="700"></span></p>
+</div>
+<div class="paragraph">
+<p>If the traversal started at tank "a", then the value of "amount" on that tank would be used to calculate what the value
+of tank "b" was by multiplying it by the value of the "factor" property on the edge between vertices "a" and "b". In
+this case the amount of tank "b" would then be 50. Following this pattern, when going from tank "b" to tank "c", the
+value of the "amount" of tank "c" would be 5.</p>
+</div>
+<div class="paragraph">
+<p><span class="image"><img src="../images/traversal-induced-values-2.png" alt="traversal-induced-values-2" width="700"></span></p>
+</div>
+<div class="paragraph">
+<p>Using Gremlin <code>sack()</code>, this kind of operation could be specified as a single traversal:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.addV(label, <span class="string"><span class="delimiter">'</span><span class="content">tank</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">a</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">amount</span><span class="delimiter">'</span></span>, <span class="float">100.0</span>).as(<span class="string"><span class="delimiter">'</span><span class="content">a</span><span class="delimiter">'</span></span>).
+           addV(label, <span class="string"><span class="delimiter">'</span><span class="content">tank</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">b</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">amount</span><span class="delimiter">'</span></span>, <span class="float">0.0</span>).as(<span class="string"><span class="delimiter">'</span><span class="content">b</span><span class="delimiter">'</span></span>).
+           addV(label, <span class="string"><span class="delimiter">'</span><span class="content">tank</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">c</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">amount</span><span class="delimiter">'</span></span>, <span class="float">0.0</span>).as(<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">drain</span><span class="delimiter">'</span></span>).property(<span class="string"><span class="delimiter">'</span><span class="content">factor</span><span class="delimiter">'</span></span>, <span class="float">0.5</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">drain</span><span class="delimiter">'</span></span>).property(<span class="string"><span class="delimiter">'</span><span class="content">factor</span><span class="delimiter">'</span></span>, <span class="float">0.1</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>).iterate()
+gremlin&gt; a = g.V().has(<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">a</span><span class="delimiter">'</span></span>).next()
+==&gt;v[<span class="integer">0</span>]
+gremlin&gt; g.withSack(a.value(<span class="string"><span class="delimiter">'</span><span class="content">amount</span><span class="delimiter">'</span></span>)).
+           V(a).repeat(outE(<span class="string"><span class="delimiter">'</span><span class="content">drain</span><span class="delimiter">'</span></span>).sack(mult).by(<span class="string"><span class="delimiter">'</span><span class="content">factor</span><span class="delimiter">'</span></span>).
+                       inV().property(<span class="string"><span class="delimiter">'</span><span class="content">amount</span><span class="delimiter">'</span></span>, sack())).
+                until(__.outE(<span class="string"><span class="delimiter">'</span><span class="content">drain</span><span class="delimiter">'</span></span>).count().is(<span class="integer">0</span>)).iterate()
+gremlin&gt; g.V().valueMap()
+==&gt;[<span class="key">amount</span>:[<span class="float">100.0</span>],<span class="key">name</span>:[a]]
+==&gt;[<span class="key">amount</span>:[<span class="float">50.00</span>],<span class="key">name</span>:[b]]
+==&gt;[<span class="key">amount</span>:[<span class="float">5.000</span>],<span class="key">name</span>:[c]]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The "sack value" gets initialized to the value of tank "a". The traversal iteratively traverses out on the "drain"
+edges and uses <code>mult</code> to multiply the sack value by the value of "factor". The sack value at that point is then
+written to the "amount" of the current vertex.</p>
+</div>
+<div class="paragraph">
+<p>As shown in the previous example, <code>sack()</code> is a useful way to "carry" and manipulate a value that can be later used
+elsewhere in the traversal. Here is another example of its usage where it is utilized to increment all the "age" values
+in the modern toy graph by 10:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.withSack(<span class="integer">0</span>).V().has(<span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>).
+           sack(assign).by(<span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>).sack(sum).by(constant(<span class="integer">10</span>)).
+           property(<span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>, sack()).valueMap()
+==&gt;[<span class="key">name</span>:[marko],<span class="key">age</span>:[<span class="integer">39</span>]]
+==&gt;[<span class="key">name</span>:[vadas],<span class="key">age</span>:[<span class="integer">37</span>]]
+==&gt;[<span class="key">name</span>:[josh],<span class="key">age</span>:[<span class="integer">42</span>]]
+==&gt;[<span class="key">name</span>:[peter],<span class="key">age</span>:[<span class="integer">45</span>]]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>In the above case, the sack is initialized to zero and as each vertex is iterated, the "age" is assigned to the sack
+with <code>sack(assign).by('age')</code>. That value in the sack is then incremented by the value <code>constant(10)</code> and assigned to
+the "age" property of the same vertex.</p>
+</div>
+<div class="paragraph">
+<p>This value the sack is incremented by need not be a constant. It could also be derived from the traversal itself.
+Using the same example, the "weight" property on the incident edges will be used as the value to add to the sack:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.withSack(<span class="integer">0</span>).V().has(<span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>).
+           sack(assign).by(<span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>).sack(sum).by(bothE().values(<span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>).sum()).
+           property(<span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>, sack()).valueMap()
+==&gt;[<span class="key">name</span>:[marko],<span class="key">age</span>:[<span class="float">30.9</span>]]
+==&gt;[<span class="key">name</span>:[vadas],<span class="key">age</span>:[<span class="float">27.5</span>]]
+==&gt;[<span class="key">name</span>:[josh],<span class="key">age</span>:[<span class="float">34.4</span>]]
+==&gt;[<span class="key">name</span>:[peter],<span class="key">age</span>:[<span class="float">35.2</span>]]</code></pre>
+</div>
+</div>
 </div>
 </div>
 <div class="sect1">
@@ -2503,7 +3061,7 @@ the anonymous traversal itself.</p>
 <div class="listingblock">
 <div class="content">
 <pre class="CodeRay"><code class="groovy language-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="float">235d</span><span class="integer">659</span>c
+==&gt;groovysh_evaluate<span class="error">$</span>_run_closure1<span class="error">@</span><span class="integer">751</span>ae8a4
 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>]
@@ -2633,10 +3191,275 @@ GitHub and JIRA are linked.  As mentione
 committers prior to merging. This process may take several days to complete. We look forward to receiving your
 submissions!</p>
 </div>
+<h1 id="_appendix" class="sect0">Appendix</h1>
+<div class="paragraph">
+<p>Many of the recipes are based on questions and answers provided on the gremlin-users mailing list. This section
+contains a number of traversals from the mailing list that do not easily fit any particular pattern (i.e. a recipe),
+but are nonetheless interesting and thus remain good tools for learning Gremlin.</p>
+</div>
+<div id="appendix-a" class="paragraph">
+<p><em>For each person in a "follows" graph, determine the number of followers and list their names.</em></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.addV(<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>).as(<span class="string"><span class="delimiter">'</span><span class="content">marko</span><span class="delimiter">'</span></span>).
+           addV(<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">josh</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">josh</span><span class="delimiter">'</span></span>).
+           addV(<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">daniel</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">daniel</span><span class="delimiter">'</span></span>).
+           addV(<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">matthias</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">matthias</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">follows</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">josh</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">marko</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">follows</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">matthias</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">josh</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">follows</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">daniel</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">josh</span><span class="delimiter">'</span></span>).
+           addE(<span class="string"><span class="delimiter">'</span><span class="content">follows</span><span class="delimiter">'</span></span>).from(<span class="string"><span class="delimiter">'</span><span class="content">daniel</span><span class="delimiter">'</span></span>).to(<span class="string"><span class="delimiter">'</span><span class="content">marko</span><span class="delimiter">'</span></span>).iterate()
+gremlin&gt; g.V().as(<span class="string"><span class="delimiter">'</span><span class="content">p</span><span class="delimiter">'</span></span>).
+           map(__.in(<span class="string"><span class="delimiter">'</span><span class="content">follows</span><span class="delimiter">'</span></span>).values(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>).fold()).
+           group().by(select(<span class="string"><span class="delimiter">'</span><span class="content">p</span><span class="delimiter">'</span></span>).by(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>)).
+                   by(project(<span class="string"><span class="delimiter">'</span><span class="content">numFollowers</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">followers</span><span class="delimiter">'</span></span>).
+                        by(count(local)).by()).next()
+==&gt;daniel={numFollowers=<span class="integer">0</span>, followers=<span class="type">[]</span>}
+==&gt;matthias={numFollowers=<span class="integer">0</span>, followers=<span class="type">[]</span>}
+==&gt;josh={numFollowers=<span class="integer">2</span>, followers=[matthias, daniel]}
+==&gt;marko={numFollowers=<span class="integer">2</span>, followers=[josh, daniel]}</code></pre>
+</div>
+</div>
+<div id="appendix-b" class="paragraph">
+<p><em>In the "modern" graph, show each person, the software they worked on and the co-worker count for the software and
+the names of those co-workers.</em></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.V().hasLabel(<span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">p</span><span class="delimiter">&quot;</span></span>).
+           out(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">s</span><span class="delimiter">&quot;</span></span>).
+           map(__.in(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>).
+             where(neq(<span class="string"><span class="delimiter">&quot;</span><span class="content">p</span><span class="delimiter">&quot;</span></span>)).values(<span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>).fold()).
+           group().by(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">p</span><span class="delimiter">&quot;</span></span>).by(<span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>)).
+             by(group().by(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">s</span><span class="delimiter">&quot;</span></span>).by(<span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>)).
+             by(project(<span class="string"><span class="delimiter">&quot;</span><span class="content">numCoworkers</span><span class="delimiter">&quot;</span></span>,<span class="string"><span class="delimiter">&quot;</span><span class="content">coworkers</span><span class="delimiter">&quot;</span></span>).
+                  by(count(local)).by())).next()
+==&gt;peter={lop={numCoworkers=<span class="integer">2</span>, coworkers=[marko, josh]}}
+==&gt;josh={ripple={numCoworkers=<span class="integer">0</span>, coworkers=<span class="type">[]</span>}, lop={numCoworkers=<span class="integer">2</span>, coworkers=[marko, peter]}}
+==&gt;marko={lop={numCoworkers=<span class="integer">2</span>, coworkers=[josh, peter]}}</code></pre>
+</div>
+</div>
+<div id="appendix-c" class="paragraph">
+<p><em>Assuming a graph of students, classes and times, detect students who have a conflicting schedule.</em></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin&gt; g.addV(label, <span class="string"><span class="delimiter">&quot;</span><span class="content">student</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">Pete</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">s1</span><span class="delimiter">&quot;</span></span>).
+           addV(label, <span class="string"><span class="delimiter">&quot;</span><span class="content">student</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">Joe</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">s2</span><span class="delimiter">&quot;</span></span>).
+           addV(label, <span class="string"><span class="delimiter">&quot;</span><span class="content">class</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">Java's GC</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">c1</span><span class="delimiter">&quot;</span></span>).
+           addV(label, <span class="string"><span class="delimiter">&quot;</span><span class="content">class</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">FP Principles</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">c2</span><span class="delimiter">&quot;</span></span>).
+           addV(label, <span class="string"><span class="delimiter">&quot;</span><span class="content">class</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">Memory Management in C</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">c3</span><span class="delimiter">&quot;</span></span>).
+           addV(label, <span class="string"><span class="delimiter">&quot;</span><span class="content">class</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">Memory Management in C++</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">c4</span><span class="delimiter">&quot;</span></span>).
+           addV(label, <span class="string"><span class="delimiter">&quot;</span><span class="content">timeslot</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">date</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">11/25/2016</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">fromTime</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">10:00</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">toTime</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">11:00</span><span class="delimiter">&quot;</span></span
 >).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">t1</span><span class="delimiter">&quot;</span></span>).
+           addV(label, <span class="string"><span class="delimiter">&quot;</span><span class="content">timeslot</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">date</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">11/25/2016</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">fromTime</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">11:00</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">toTime</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">12:00</span><span class="delimiter">&quot;</span></span
 >).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">t2</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">attends</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">s1</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">c1</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">attends</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">s1</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">c2</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">attends</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">s1</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">c3</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">attends</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">s1</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">c4</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">attends</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">s2</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">c2</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">attends</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">s2</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">c3</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">allocated</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">c1</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">t1</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">allocated</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">c1</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">t2</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">allocated</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">c2</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">t1</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">allocated</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">c3</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">t2</span><span class="delimiter">&quot;</span></span>).
+           addE(<span class="string"><span class="delimiter">&quot;</span><span class="content">allocated</span><span class="delimiter">&quot;</span></span>).from(<span class="string"><span class="delimiter">&quot;</span><span class="content">c4</span><span class="delimiter">&quot;</span></span>).to(<span class="string"><span class="delimiter">&quot;</span><span class="content">t2</span><span class="delimiter">&quot;</span></span>).iterate()
+gremlin&gt; g.V().hasLabel(<span class="string"><span class="delimiter">&quot;</span><span class="content">student</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">s</span><span class="delimiter">&quot;</span></span>).
+           out(<span class="string"><span class="delimiter">&quot;</span><span class="content">attends</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">c</span><span class="delimiter">&quot;</span></span>).
+           out(<span class="string"><span class="delimiter">&quot;</span><span class="content">allocated</span><span class="delimiter">&quot;</span></span>).as(<span class="string"><span class="delimiter">&quot;</span><span class="content">t</span><span class="delimiter">&quot;</span></span>).
+           select(<span class="string"><span class="delimiter">&quot;</span><span class="content">s</span><span class="delimiter">&quot;</span></span>).
+           out(<span class="string"><span class="delimiter">&quot;</span><span class="content">attends</span><span class="delimiter">&quot;</span></span>).
+           where(neq(<span class="string"><span class="delimiter">&quot;</span><span class="content">c</span><span class="delimiter">&quot;</span></span>)).
+           out(<span class="string"><span class="delimiter">&quot;</span><span class="content">allocated</span><span class="delimiter">&quot;</span></span>).
+           where(eq(<span class="string"><span class="delimiter">&quot;</span><span class="content">t</span><span class="delimiter">&quot;</span></span>)).
+           group().
+             by(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">s</span><span class="delimiter">&quot;</span></span>).by(<span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>)).
+             by(group().by(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">t</span><span class="delimiter">&quot;</span></span>).by(valueMap(<span class="string"><span class="delimiter">&quot;</span><span class="content">fromTime</span><span class="delimiter">&quot;</span></span>,<span class="string"><span class="delimiter">&quot;</span><span class="content">toTime</span><span class="delimiter">&quot;</span></span>))).
+                        by(select(<span class="string"><span class="delimiter">&quot;</span><span class="content">c</span><span class="delimiter">&quot;</span></span>).dedup().values(<span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>).fold())).next()
+==&gt;Pete={{fromTime=[<span class="integer">10</span>:<span class="octal">00</span>], toTime=[<span class="integer">11</span>:<span class="octal">00</span>]}=[Java<span class="string"><span class="delimiter">'</span><span class="content">s GC, FP Principles], {fromTime=[11:00], toTime=[12:00]}=[Java</span><span class="delimiter">'</span></span>s GC, Memory Management <span class="keyword">in</span> C, Memory Management <span class="keyword">in</span> C++]}</code></pre>
+</div>
+</div>
+<div id="appendix-d" class="paragraph">
+<p><em>In the "modern" graph, with a duplicate edge added, find the vertex pairs that have more than one edge between them.</em></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-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()

[... 180 lines stripped ...]