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 2016/05/11 20:18:39 UTC
svn commit: r1743420 -
/incubator/tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html
Author: spmallette
Date: Wed May 11 20:18:39 2016
New Revision: 1743420
URL: http://svn.apache.org/viewvc?rev=1743420&view=rev
Log:
Added traversal component reuse recipe to TinkerPop docs.
Modified:
incubator/tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html
Modified: incubator/tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html
URL: http://svn.apache.org/viewvc/incubator/tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html?rev=1743420&r1=1743419&r2=1743420&view=diff
==============================================================================
--- incubator/tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html (original)
+++ incubator/tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html Wed May 11 20:18:39 2016
@@ -797,12 +797,19 @@ span.line-numbers { border-right: 1px so
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel0">
<li><a href="#_recipes">Recipes</a></li>
+<li><a href="#_traversal_recipes">Traversal Recipes</a></li>
<li>
<ul class="sectlevel1">
<li><a href="#shortest-path">Shortest Path</a></li>
<li><a href="#if-then-based-grouping">If-Then Based Grouping</a></li>
</ul>
</li>
+<li><a href="#_implementation_recipes">Implementation Recipes</a></li>
+<li>
+<ul class="sectlevel1">
+<li><a href="#traversal-component-reuse">Traversal Component Reuse</a></li>
+</ul>
+</li>
<li><a href="#contributing">How to Contribute a Recipe</a></li>
</ul>
</div>
@@ -829,6 +836,7 @@ provide some basic building blocks for v
<a href="http://tinkerpop.apache.org/docs/3.2.1-SNAPSHOT/tutorials/getting-started">Getting Started</a> tutorial and the
<a href="http://tinkerpop.apache.org/docs/3.2.1-SNAPSHOT/tutorials/the-gremlin-console/">The Gremlin Console</a> tutorial.</p>
</div>
+<h1 id="_traversal_recipes" class="sect0">Traversal Recipes</h1>
<div class="sect1">
<h2 id="shortest-path">Shortest Path</h2>
<div class="sectionbody">
@@ -1035,6 +1043,90 @@ there is another option to consider with
</div>
</div>
</div>
+<h1 id="_implementation_recipes" class="sect0">Implementation Recipes</h1>
+<div class="sect1">
+<h2 id="traversal-component-reuse">Traversal Component Reuse</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<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>
+</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
+on edges where the "weight" property is greater than "0.5". A query like that might look like this:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.V(<span class="integer">1</span>).outE(<span class="string"><span class="delimiter">"</span><span class="content">knows</span><span class="delimiter">"</span></span>).has(<span class="string"><span class="delimiter">'</span><span class="content">weight</span><span class="delimiter">'</span></span>, P.gt(<span class="float">0.5d</span>)).inV().both()
+==>v[<span class="integer">5</span>]
+==>v[<span class="integer">3</span>]
+==>v[<span class="integer">1</span>]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Repeatedly requiring that filter on "weight" could lead to a lot of duplicate code, which becomes difficult to
+maintain. It would be nice to extract that logic so as to centralize it for reuse in all places where needed. An
+anonymous traversal allows that to happen and can be created as follows.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin> weightFilter = outE(<span class="string"><span class="delimiter">"</span><span class="content">knows</span><span class="delimiter">"</span></span>).has(<span class="string"><span class="delimiter">'</span><span class="content">weight</span><span class="delimiter">'</span></span>, P.gt(<span class="float">0.5d</span>)).inV();<span class="type">[]</span>
+gremlin> g.V(<span class="integer">1</span>).flatMap(weightFilter).both()
+==>v[<span class="integer">5</span>]
+==>v[<span class="integer">3</span>]
+==>v[<span class="integer">1</span>]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The <code>weightFilter</code> is an anonymous traversal and it is created by way <code>__</code> class. The <code>__</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.
+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>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin> weightFilter = outE(<span class="string"><span class="delimiter">"</span><span class="content">knows</span><span class="delimiter">"</span></span>).has(<span class="string"><span class="delimiter">'</span><span class="content">weight</span><span class="delimiter">'</span></span>, P.gt(<span class="float">0.5d</span>)).inV();<span class="type">[]</span>
+gremlin> g.V(<span class="integer">1</span>).flatMap(weightFilter.clone()).both()
+==>v[<span class="integer">5</span>]
+==>v[<span class="integer">3</span>]
+==>v[<span class="integer">1</span>]
+gremlin> g.V(<span class="integer">1</span>).flatMap(weightFilter.clone()).bothE().otherV()
+==>v[<span class="integer">5</span>]
+==>v[<span class="integer">3</span>]
+==>v[<span class="integer">1</span>]
+gremlin> g.V(<span class="integer">1</span>).flatMap(weightFilter.clone()).groupCount()
+==>[v[<span class="integer">4</span>]:<span class="integer">1</span>]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Now the <code>weightFilter</code> can be reused over and over again. Remembering to <code>clone()</code> might lead to yet another maintenance
+issue in that failing to recall that step would likely result in a bug. One option might be to wrap the <code>weightFilter</code>
+creation in a function that returns the clone. Another approach might be to parameterize that function to construct
+a new anonymous traversal each time with the idea being that this might gain even more flexibility in parameterizing
+the anonymous traversal itself.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay"><code class="groovy language-groovy">gremlin> weightFilter = { w -> outE(<span class="string"><span class="delimiter">"</span><span class="content">knows</span><span class="delimiter">"</span></span>).has(<span class="string"><span class="delimiter">'</span><span class="content">weight</span><span class="delimiter">'</span></span>, P.gt(w)).inV() }
+==>groovysh_evaluate<span class="error">$</span>_run_closure1<span class="error">@</span><span class="float">3d</span><span class="float">19d</span><span class="integer">85</span>
+gremlin> g.V(<span class="integer">1</span>).flatMap(weightFilter(<span class="float">0.5d</span>)).both()
+==>v[<span class="integer">5</span>]
+==>v[<span class="integer">3</span>]
+==>v[<span class="integer">1</span>]
+gremlin> g.V(<span class="integer">1</span>).flatMap(weightFilter(<span class="float">0.5d</span>)).bothE().otherV()
+==>v[<span class="integer">5</span>]
+==>v[<span class="integer">3</span>]
+==>v[<span class="integer">1</span>]
+gremlin> g.V(<span class="integer">1</span>).flatMap(weightFilter(<span class="float">0.5d</span>)).groupCount()
+==>[v[<span class="integer">4</span>]:<span class="integer">1</span>]</code></pre>
+</div>
+</div>
+</div>
+</div>
<h1 id="contributing" class="sect0">How to Contribute a Recipe</h1>
<div class="paragraph">
<p>Recipes are generated under the same system as all TinkerPop documentation and is stored directly in the source code
@@ -1140,7 +1232,7 @@ submissions!</p>
</div>
<div id="footer">
<div id="footer-text">
-Last updated 2016-05-06 09:34:47 -04:00
+Last updated 2016-05-11 16:10:20 -04:00
</div>
</div>
</body>