Author: spmallette Date: Mon Jun 13 15:25:14 2016 New Revision: 1748261 URL: http://svn.apache.org/viewvc?rev=1748261&view=rev Log: Add centrality recipe to TinkerPop docs.
Added: tinkerpop/site/docs/3.2.1-SNAPSHOT/images/betweeness-example.png (with props) Modified: tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html Added: tinkerpop/site/docs/3.2.1-SNAPSHOT/images/betweeness-example.png URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.1-SNAPSHOT/images/betweeness-example.png?rev=1748261&view=auto ============================================================================== Binary file - no diff available. Propchange: tinkerpop/site/docs/3.2.1-SNAPSHOT/images/betweeness-example.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Modified: tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html?rev=1748261&r1=1748260&r2=1748261&view=diff ============================================================================== --- tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html (original) +++ tinkerpop/site/docs/3.2.1-SNAPSHOT/recipes/index.html Mon Jun 13 15:25:14 2016 @@ -804,6 +804,15 @@ span.line-numbers { border-right: 1px so <li><a href="#shortest-path">Shortest Path</a></li> <li><a href="#if-then-based-grouping">If-Then Based Grouping</a></li> <li><a href="#cycle-detection">Cycle Detection</a></li> +<li><a href="#centrality">Centrality</a></li> +<li> +<ul class="sectlevel2"> +<li><a href="#degree-centrality">Degree Centrality</a></li> +<li><a href="#betweeness-centrality">Betweeness Centrality</a></li> +<li><a href="#closeness-centrality">Closeness Centrality</a></li> +<li><a href="#eigenvector-centrality">Eigenvector Centrality</a></li> +</ul> +</li> </ul> </li> <li><a href="#_implementation_recipes">Implementation Recipes</a></li> @@ -901,7 +910,29 @@ two vertices.</p> </div> <div class="paragraph"> <p>The basic pattern of using <code>where()</code> step to find the "other" known vertex can be applied in far more complex -scenarios. Consider the following schema:</p> +scenarios. For one such example, consider the following traversal that finds all the paths between a group of defined +vertices:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> ids = [<span class="integer">2</span>,<span class="integer">4</span>,<span class="integer">6</span>].toArray() +==><span class="integer">2</span> +==><span class="integer">4</span> +==><span class="integer">6</span> +gremlin> g.V(ids).as(<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>). + repeat(bothE().otherV().simplePath()).times(<span class="integer">5</span>).emit(hasId(within(ids))).as(<span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>). + filter(select(last,<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">b</span><span class="delimiter">"</span></span>).by(id).where(<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, lt(<span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>))). + path().by().by(label) +==>[v[<span class="integer">2</span>], knows, v[<span class="integer">1</span>], knows, v[<span class="integer">4</span>]] +==>[v[<span class="integer">2</span>], knows, v[<span class="integer">1</span>], created, v[<span class="integer">3</span>], created, v[<span class="integer">4</span>]] +==>[v[<span class="integer">2</span>], knows, v[<span class="integer">1</span>], created, v[<span class="integer">3</span>], created, v[<span class="integer">6</span>]] +==>[v[<span class="integer">2</span>], knows, v[<span class="integer">1</span>], knows, v[<span class="integer">4</span>], created, v[<span class="integer">3</span>], created, v[<span class="integer">6</span>]] +==>[v[<span class="integer">4</span>], created, v[<span class="integer">3</span>], created, v[<span class="integer">6</span>]] +==>[v[<span class="integer">4</span>], knows, v[<span class="integer">1</span>], created, v[<span class="integer">3</span>], created, v[<span class="integer">6</span>]]</code></pre> +</div> +</div> +<div class="paragraph"> +<p>For another example, consider the following schema:</p> </div> <div class="paragraph"> <p><span class="image"><img src="../images/recipe-job-schema.png" alt="recipe-job-schema" width="750"></span></p> @@ -1273,6 +1304,230 @@ arbitrary length over both incoming and </div> </div> </div> +<div class="sect1"> +<h2 id="centrality">Centrality</h2> +<div class="sectionbody"> +<div class="paragraph"> +<p>There are many measures of <a href="https://en.wikipedia.org/wiki/Centrality">centrality</a> which are meant to help identify +the most important vertices in a graph. As these measures are common in graph theory, this section attempts to +demonstrate how some of these different indicators can be calculated using Gremlin.</p> +</div> +<div class="sect2"> +<h3 id="degree-centrality">Degree Centrality</h3> +<div class="paragraph"> +<p><a href="https://en.wikipedia.org/wiki/Centrality#Degree_centrality">Degree centrality</a> is a measure of the number of +edges associated to each vertex.</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.V().bothE().group().by(otherV()).by(count()) <span class="comment">//</span><b>(1)</b> +==>[v[<span class="integer">1</span>]:<span class="integer">3</span>, v[<span class="integer">2</span>]:<span class="integer">1</span>, v[<span class="integer">3</span>]:<span class="integer">3</span>, v[<span class="integer">4</span>]:<span class="integer">3</span>, v[<span class="integer">5</span>]:<span class="integer">1</span>, v[<span class="integer">6</span>]:<span class="integer">1</span>] +gremlin> g.V().inE().group().by(inV()).by(count()) <span class="comment">//</span><b>(2)</b> +==>[v[<span class="integer">2</span>]:<span class="integer">1</span>, v[<span class="integer">3</span>]:<span class="integer">3</span>, v[<span class="integer">4</span>]:<span class="integer">1</span>, v[<span class="integer">5</span>]:<span class="integer">1</span>] +gremlin> g.V().outE().group().by(outV()).by(count()) <span class="comment">//</span><b>(3)</b> +==>[v[<span class="integer">1</span>]:<span class="integer">3</span>, v[<span class="integer">4</span>]:<span class="integer">2</span>, v[<span class="integer">6</span>]:<span class="integer">1</span>] +gremlin> g.V().group().by().by(outE().count()) <span class="comment">//</span><b>(4)</b> +==>[v[<span class="integer">1</span>]:<span class="integer">3</span>, v[<span class="integer">2</span>]:<span class="integer">0</span>, v[<span class="integer">3</span>]:<span class="integer">0</span>, v[<span class="integer">4</span>]:<span class="integer">2</span>, v[<span class="integer">5</span>]:<span class="integer">0</span>, v[<span class="integer">6</span>]:<span class="integer">1</span>] +gremlin> g.V().project(<span class="string"><span class="delimiter">"</span><span class="content">v</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">degree</span><span class="delimiter">"</span></span>).by().by(bothE().count()) <span class="comment">//</span><b>(5)</b> +==>[<span class="key">v</span>:v[<span class="integer">1</span>], <span class="key">degree</span>:<span class="integer">3</span>] +==>[<span class="key">v</span>:v[<span class="integer">2</span>], <span class="key">degree</span>:<span class="integer">1</span>] +==>[<span class="key">v</span>:v[<span class="integer">3</span>], <span class="key">degree</span>:<span class="integer">3</span>] +==>[<span class="key">v</span>:v[<span class="integer">4</span>], <span class="key">degree</span>:<span class="integer">3</span>] +==>[<span class="key">v</span>:v[<span class="integer">5</span>], <span class="key">degree</span>:<span class="integer">1</span>] +==>[<span class="key">v</span>:v[<span class="integer">6</span>], <span class="key">degree</span>:<span class="integer">1</span>] +gremlin> g.V().project(<span class="string"><span class="delimiter">"</span><span class="content">v</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">degree</span><span class="delimiter">"</span></span>).by().by(bothE().count()). <span class="comment">//</span><b>(6)</b> + order().by(select(<span class="string"><span class="delimiter">"</span><span class="content">degree</span><span class="delimiter">"</span></span>), decr). + limit(<span class="integer">4</span>) +==>[<span class="key">v</span>:v[<span class="integer">1</span>], <span class="key">degree</span>:<span class="integer">3</span>] +==>[<span class="key">v</span>:v[<span class="integer">3</span>], <span class="key">degree</span>:<span class="integer">3</span>] +==>[<span class="key">v</span>:v[<span class="integer">4</span>], <span class="key">degree</span>:<span class="integer">3</span>] +==>[<span class="key">v</span>:v[<span class="integer">2</span>], <span class="key">degree</span>:<span class="integer">1</span>]</code></pre> +</div> +</div> +<div class="colist arabic"> +<ol> +<li> +<p>Calculation of degree centrality which counts all incident edges on each vertex to include those that are both +incoming and outgoing.</p> +</li> +<li> +<p>Calculation of in-degree centrality which only counts incoming edges to a vertex.</p> +</li> +<li> +<p>Calculation of out-degree centrality which only counts outgoing edges from a vertex.</p> +</li> +<li> +<p>Same calculation as the previous traversal, but includes all vertices, even those with a zero</p> +</li> +<li> +<p>The previous examples all produce a single <code>Map</code> as their output. While that is a desireable output, producing a +stream of <code>Map</code> objects can allow some greater flexibility.</p> +</li> +<li> +<p>For example, use of a stream enables use of an ordered limit that can be executed in a distributed fashion in +OLAP traversals.</p> +</li> +</ol> +</div> +</div> +<div class="sect2"> +<h3 id="betweeness-centrality">Betweeness Centrality</h3> +<div class="paragraph"> +<p><a href="https://en.wikipedia.org/wiki/Betweenness_centrality">Betweeness centrality</a> is a measure of the number of times +a vertex is found between the <a href="#shortest-path">shortest path</a> of each vertex pair in a graph. Consider the following +graph for demonstration purposes:</p> +</div> +<div class="paragraph"> +<p><span class="image"><img src="../images/betweeness-example.png" alt="betweeness-example" width="600"></span></p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> a = graph.addVertex(<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>) +==>v[<span class="integer">0</span>] +gremlin> b = graph.addVertex(<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>) +==>v[<span class="integer">2</span>] +gremlin> c = graph.addVertex(<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>) +==>v[<span class="integer">4</span>] +gremlin> d = graph.addVertex(<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">d</span><span class="delimiter">'</span></span>) +==>v[<span class="integer">6</span>] +gremlin> e = graph.addVertex(<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">e</span><span class="delimiter">'</span></span>) +==>v[<span class="integer">8</span>] +gremlin> a.addEdge(<span class="string"><span class="delimiter">'</span><span class="content">next</span><span class="delimiter">'</span></span>,b) +==>e[<span class="integer">10</span>][<span class="integer">0</span>-next-><span class="integer">2</span>] +gremlin> b.addEdge(<span class="string"><span class="delimiter">'</span><span class="content">next</span><span class="delimiter">'</span></span>,c) +==>e[<span class="integer">11</span>][<span class="integer">2</span>-next-><span class="integer">4</span>] +gremlin> c.addEdge(<span class="string"><span class="delimiter">'</span><span class="content">next</span><span class="delimiter">'</span></span>,d) +==>e[<span class="integer">12</span>][<span class="integer">4</span>-next-><span class="integer">6</span>] +gremlin> d.addEdge(<span class="string"><span class="delimiter">'</span><span class="content">next</span><span class="delimiter">'</span></span>,e) +==>e[<span class="integer">13</span>][<span class="integer">6</span>-next-><span class="integer">8</span>] +gremlin> g.withSack(<span class="integer">0</span>).V().store(<span class="string"><span class="delimiter">"</span><span class="content">x</span><span class="delimiter">"</span></span>).repeat(both().simplePath()).emit().path(). <span class="comment">//</span><b>(1)</b> + group().by(project(<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">b</span><span class="delimiter">"</span></span>).by(limit(local, <span class="integer">1</span>)). <span class="comment">//</span><b>(2)</b> + by(tail(local, <span class="integer">1</span>))). + by(order().by(count(local))). <span class="comment">//</span><b>(3)</b> + select(values).as(<span class="string"><span class="delimiter">"</span><span class="content">shortestPaths</span><span class="delimiter">"</span></span>). <span class="comment">//</span><b>(4)</b> + select(<span class="string"><span class="delimiter">"</span><span class="content">x</span><span class="delimiter">"</span></span>).unfold().as(<span class="string"><span class="delimiter">"</span><span class="content">v</span><span class="delimiter">"</span></span>). <span class="comment">//</span><b>(5)</b> + select(<span class="string"><span class="delimiter">"</span><span class="content">shortestPaths</span><span class="delimiter">"</span></span>). <span class="comment">//</span><b>(6)</b> + map(unfold().filter(unfold().where(eq(<span class="string"><span class="delimiter">"</span><span class="content">v</span><span class="delimiter">"</span></span>))).count()). <span class="comment">//</span><b>(7)</b> + sack(sum).sack().as(<span class="string"><span class="delimiter">"</span><span class="content">betweeness</span><span class="delimiter">"</span></span>). <span class="comment">//</span><b>(8)</b> + select(<span class="string"><span class="delimiter">"</span><span class="content">v</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">betweeness</span><span class="delimiter">"</span></span>) +==>[<span class="key">v</span>:v[<span class="integer">0</span>], <span class="key">betweeness</span>:<span class="integer">8</span>] +==>[<span class="key">v</span>:v[<span class="integer">2</span>], <span class="key">betweeness</span>:<span class="integer">14</span>] +==>[<span class="key">v</span>:v[<span class="integer">4</span>], <span class="key">betweeness</span>:<span class="integer">16</span>] +==>[<span class="key">v</span>:v[<span class="integer">6</span>], <span class="key">betweeness</span>:<span class="integer">14</span>] +==>[<span class="key">v</span>:v[<span class="integer">8</span>], <span class="key">betweeness</span>:<span class="integer">8</span>]</code></pre> +</div> +</div> +<div class="colist arabic"> +<ol> +<li> +<p>Defines a Gremlin <a href="http://tinkerpop.apache.org/docs/3.2.1-SNAPSHOT/reference/#sack-step">sack</a> with a value of zero, +which represents the initial betweeness score for each vertex, and traverses on both incoming and outgoing edges +avoiding <a href="#cycle-detection">cyclic paths</a>.</p> +</li> +<li> +<p>Group each path by the first and last vertex.</p> +</li> +<li> +<p>Reduce the list of paths to the shortest path between the first and last vertex by ordering on their lengths.</p> +</li> +<li> +<p>Recall that at this point, there is a <code>Map</code> keyed by first and last vertex and with a value of just the shortest +path. Extract the shortest path with <code>select(values)</code>, since that’s the only portion required for the remainder of +the traversal.</p> +</li> +<li> +<p>The "x" key contains the list of vertices stored from step 1 - unfold that list into "v" for later use. This step +will unwrap the vertex that is stored in the <code>Traverser</code> as +<a href="http://tinkerpop.apache.org/javadocs/3.2.1-SNAPSHOT/full/org/apache/tinkerpop/gremlin/process/traversal/step/util/BulkSet.html">BulkSet</a> +so that it can be used directly in the <code>Traversal</code>.</p> +</li> +<li> +<p>Iterate the set of shortest paths. At this point, it is worth noting that the traversal is iterating each vertex +in "v" and for each vertex in "v" it is iterating each <code>Path</code> in "shortestpaths".</p> +</li> +<li> +<p>For each path, transform it to a count of the number of times that "v" from step 5 is encountered.</p> +</li> +<li> +<p>Sum the counts for each vertex using <code>sack()</code>, normalize the value and label it as the "betweeness" to be the score.</p> +</li> +</ol> +</div> +</div> +<div class="sect2"> +<h3 id="closeness-centrality">Closeness Centrality</h3> +<div class="paragraph"> +<p><a href="https://en.wikipedia.org/wiki/Centrality">Closeness centrality</a> is a measure of the distance of one vertex to all +other reachable vertices in the graph.</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.withSack(<span class="float">1f</span>).V().repeat(both().simplePath()).emit().path(). <span class="comment">//</span><b>(1)</b> + group().by(project(<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">b</span><span class="delimiter">"</span></span>).by(limit(local, <span class="integer">1</span>)). <span class="comment">//</span><b>(2)</b> + by(tail(local, <span class="integer">1</span>))). + by(order().by(count(local))). <span class="comment">//</span><b>(3)</b> + select(values).unfold(). <span class="comment">//</span><b>(4)</b> + project(<span class="string"><span class="delimiter">"</span><span class="content">v</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">length</span><span class="delimiter">"</span></span>). + by(limit(local, <span class="integer">1</span>)). <span class="comment">//</span><b>(5)</b> + by(count(local).sack(div).sack()). <span class="comment">//</span><b>(6)</b> + group().by(select(<span class="string"><span class="delimiter">"</span><span class="content">v</span><span class="delimiter">"</span></span>)).by(select(<span class="string"><span class="delimiter">"</span><span class="content">length</span><span class="delimiter">"</span></span>).sum()) <span class="comment">//</span><b>(7)</b> +==>[v[<span class="integer">1</span>]:<span class="float">2.1666666666666665</span>, v[<span class="integer">2</span>]:<span class="float">1.6666666666666665</span>, v[<span class="integer">3</span>]:<span class="float">2.1666666666666665</span>, v[<span class="integer">4</span>]:<span class="float">2.1666666666666665</span>, v[<span class="integer">5</span>]:<span class="float">1.6666666666666665</span>, v[<span class="integer">6</span>]:<span class="float">1.6666666666666665</span>]</code></pre> +</div> +</div> +<div class="colist arabic"> +<ol> +<li> +<p>Defines a Gremlin <a href="http://tinkerpop.apache.org/docs/3.2.1-SNAPSHOT/reference/#sack-step">sack</a> with a value of one, +and traverses on both incoming and outgoing edges avoiding <a href="#cycle-detection">cyclic paths</a>.</p> +</li> +<li> +<p>Group each path by the first and last vertex.</p> +</li> +<li> +<p>Reduce the list of paths to the shortest path between the first and last vertex by ordering on their lengths.</p> +</li> +<li> +<p>Recall that at this point, there is a <code>Map</code> keyed by first and last vertex and with a value of just the shortest +path. Extract the shortest path with <code>select(values)</code>, since that’s the only portion required for the remainder of +the traversal.</p> +</li> +<li> +<p>The first <code>by()</code> modulator for <code>project()</code> extracts the first vertex in the path.</p> +</li> +<li> +<p>The second <code>by()</code> modulator for <code>project()</code> extracts the path length and divides that distance by the value of +the <code>sack()</code> which was initialized to 1 at the start of the traversal.</p> +</li> +<li> +<p>Group the resulting <code>Map</code> objects on "v" and sum their lengths to get the centrality score for each.</p> +</li> +</ol> +</div> +</div> +<div class="sect2"> +<h3 id="eigenvector-centrality">Eigenvector Centrality</h3> +<div class="paragraph"> +<p>A calculation of <a href="https://en.wikipedia.org/wiki/Centrality#Eigenvector_centrality">eigenvector centrality</a> uses the +relative importance of adjacent vertices to help determine their centrality. In other words, unlike +<a href="#degree-centrality">degree centrality</a> the vertex with the greatest number of incident edges does not necessarily +give it the highest rank.</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.V().repeat(groupCount(<span class="string"><span class="delimiter">'</span><span class="content">m</span><span class="delimiter">'</span></span>).out()).times(<span class="integer">30</span>).cap(<span class="string"><span class="delimiter">'</span><span class="content">m</span><span class="delimiter">'</span></span>) +==>[v[<span class="integer">1</span>]:<span class="integer">1</span>, v[<span class="integer">2</span>]:<span class="integer">2</span>, v[<span class="integer">3</span>]:<span class="integer">5</span>, v[<span class="integer">4</span>]:<span class="integer">2</span>, v[<span class="integer">5</span>]:<span class="integer">3</span>, v[<span class="integer">6</span>]:<span class="integer">1</span>]</code></pre> +</div> +</div> +<div class="paragraph"> +<p>The traversal iterates through each vertex in the graph and for each one repeatedly group counts each vertex that +passes through using the vertex as the key. The <code>Map</code> of this group count is stored in a variable named "m". The +<code>out()</code> traversal is repeated thirty times or until the paths are exhausted. Thirty iterations should provide enough +time to converge on a solution. Calling <code>cap('m')</code> at the end simply extracts the <code>Map</code> side-effect stored in "m" +and returns it from the traversal as the result.</p> +</div> +</div> +</div> +</div> <h1 id="_implementation_recipes" class="sect0">Implementation Recipes</h1> <div class="sect1"> <h2 id="style-guide">Style Guide</h2> @@ -1454,7 +1709,7 @@ the anonymous traversal itself.</p> <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">4f</span>dca00a +==>groovysh_evaluate<span class="error">$</span>_run_closure1<span class="error">@</span><span class="float">656f</span><span class="float">62d</span>c 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>] @@ -1474,7 +1729,7 @@ gremlin> g.V(<span class="integer">1< <p>Recipes are generated under the same system as all TinkerPop documentation and is stored directly in the source code repository. TinkerPop documentation is all <a href="http://asciidoc.org/">asciidoc</a> based and can be generated locally with either <a href="http://tinkerpop.apache.org/docs/3.2.1-SNAPSHOT/dev/developer/#building-testing">shell script/Maven</a> or -<a href="http://tinkerpop.apache.org/docs/3.2.0-incubating/dev/developer/#docker-integration">Docker</a> build commands. Once +<a href="http://tinkerpop.apache.org/docs/3.2.1-SNAPSHOT/dev/developer/#docker-integration">Docker</a> build commands. Once changes are complete, submit a pull request for review by TinkerPop committers.</p> </div> <div class="admonitionblock note"> @@ -1574,7 +1829,7 @@ submissions!</p> </div> <div id="footer"> <div id="footer-text"> -Last updated 2016-05-31 18:32:07 -04:00 +Last updated 2016-06-13 10:59:51 -04:00 </div> </div> </body>