Author: spmallette Date: Thu Oct 13 15:27:45 2016 New Revision: 1764708 URL: http://svn.apache.org/viewvc?rev=1764708&view=rev Log: Deploy docs for TinkerPop 3.2.3-SNAPSHOT
Added: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/gremlin-recommendation.png (with props) tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-1.png (with props) tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-2.png (with props) tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-3.png (with props) tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-4.png (with props) tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-1.png (with props) tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-2.png (with props) tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-3.png (with props) tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-4.png (with props) Modified: tinkerpop/site/docs/3.2.3-SNAPSHOT/dev/provider/index.html tinkerpop/site/docs/3.2.3-SNAPSHOT/index.html tinkerpop/site/docs/3.2.3-SNAPSHOT/recipes/index.html tinkerpop/site/docs/3.2.3-SNAPSHOT/reference/index.html Modified: tinkerpop/site/docs/3.2.3-SNAPSHOT/dev/provider/index.html URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/dev/provider/index.html?rev=1764708&r1=1764707&r2=1764708&view=diff ============================================================================== --- tinkerpop/site/docs/3.2.3-SNAPSHOT/dev/provider/index.html (original) +++ tinkerpop/site/docs/3.2.3-SNAPSHOT/dev/provider/index.html Thu Oct 13 15:27:45 2016 @@ -2411,9 +2411,9 @@ twenty. Under this model, the amount of <pre class="CodeRay"><code class="groovy language-groovy">gremlin> cluster = Cluster.open() ==>localhost/<span class="float">127.0</span><span class="float">.0</span><span class="float">.1</span>:<span class="integer">8182</span> gremlin> client = cluster.connect() -==>org.apache.tinkerpop.gremlin.driver.Client<span class="error">$</span>ClusteredClient<span class="error">@</span><span class="float">29f</span><span class="integer">95272</span> +==>org.apache.tinkerpop.gremlin.driver.Client<span class="error">$</span>ClusteredClient<span class="annotation">@c754401</span> gremlin> aliased = client.alias(<span class="string"><span class="delimiter">"</span><span class="content">g</span><span class="delimiter">"</span></span>) -==>org.apache.tinkerpop.gremlin.driver.Client<span class="error">$</span>AliasClusteredClient<span class="error">@</span><span class="float">1d</span>bff71c +==>org.apache.tinkerpop.gremlin.driver.Client<span class="error">$</span>AliasClusteredClient<span class="error">@</span><span class="integer">93</span>ce24d gremlin> g = org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph.INSTANCE.traversal() <span class="comment">//</span><b>(1)</b> ==>graphtraversalsource[emptygraph[empty], standard] gremlin> rs = aliased.submit(g.V().both().barrier().both().barrier()).all().get() <span class="comment">//</span><b>(2)</b> @@ -3039,7 +3039,7 @@ to provide a way to dynamically evaluate </div> <div id="footer"> <div id="footer-text"> -Last updated 2016-10-12 14:39:56 -04:00 +Last updated 2016-10-13 10:18:08 -04:00 </div> </div> </body> Added: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/gremlin-recommendation.png URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/images/gremlin-recommendation.png?rev=1764708&view=auto ============================================================================== Binary file - no diff available. Propchange: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/gremlin-recommendation.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-1.png URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-1.png?rev=1764708&view=auto ============================================================================== Binary file - no diff available. Propchange: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-1.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-2.png URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-2.png?rev=1764708&view=auto ============================================================================== Binary file - no diff available. Propchange: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-2.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-3.png URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-3.png?rev=1764708&view=auto ============================================================================== Binary file - no diff available. Propchange: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-3.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-4.png URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-4.png?rev=1764708&view=auto ============================================================================== Binary file - no diff available. Propchange: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommedation-alice-4.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-1.png URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-1.png?rev=1764708&view=auto ============================================================================== Binary file - no diff available. Propchange: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-1.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-2.png URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-2.png?rev=1764708&view=auto ============================================================================== Binary file - no diff available. Propchange: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-2.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-3.png URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-3.png?rev=1764708&view=auto ============================================================================== Binary file - no diff available. Propchange: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-3.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-4.png URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-4.png?rev=1764708&view=auto ============================================================================== Binary file - no diff available. Propchange: tinkerpop/site/docs/3.2.3-SNAPSHOT/images/recommendation-alice-4.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Modified: tinkerpop/site/docs/3.2.3-SNAPSHOT/index.html URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/index.html?rev=1764708&r1=1764707&r2=1764708&view=diff ============================================================================== --- tinkerpop/site/docs/3.2.3-SNAPSHOT/index.html (original) +++ tinkerpop/site/docs/3.2.3-SNAPSHOT/index.html Thu Oct 13 15:27:45 2016 @@ -895,6 +895,12 @@ and an overview of Gremlin. (<strong>ext <div class="ulist"> <ul> <li> +<p>Rodriguez, M.A., <a href="http://www.datastax.com/dev/blog/gremlins-time-machine">"Gremlin’s Time Machine,"</a> DataStax Engineering Blog, September 2016.</p> +</li> +<li> +<p>Rodriguez, M.A., <a href="http://www.slideshare.net/slidarko/gremlins-graph-traversal-machinery">"Gremlin’s Graph Traversal Machinery,"</a> Cassandra Summit, September 2016.</p> +</li> +<li> <p>Rodriguez, M.A., <a href="http://www.datastax.com/dev/blog/the-mechanics-of-gremlin-olap">"The Mechanics of Gremlin OLAP,"</a> DataStax Engineering Blog, April 2016.</p> </li> <li> @@ -956,7 +962,7 @@ Reference Documentation for providers an </div> <div id="footer"> <div id="footer-text"> -Last updated 2016-10-04 11:56:22 -04:00 +Last updated 2016-10-13 11:25:27 -04:00 </div> </div> </body> Modified: tinkerpop/site/docs/3.2.3-SNAPSHOT/recipes/index.html URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.2.3-SNAPSHOT/recipes/index.html?rev=1764708&r1=1764707&r2=1764708&view=diff ============================================================================== --- tinkerpop/site/docs/3.2.3-SNAPSHOT/recipes/index.html (original) +++ tinkerpop/site/docs/3.2.3-SNAPSHOT/recipes/index.html Thu Oct 13 15:27:45 2016 @@ -813,6 +813,7 @@ span.line-numbers { border-right: 1px so <li><a href="#cycle-detection">Cycle 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> <li><a href="#shortest-path">Shortest Path</a></li> <li><a href="#traversal-induced-values">Traversal Induced Values</a></li> </ul> @@ -1530,6 +1531,296 @@ gremlin> t.next(<span class="integer" </div> </div> <div class="sect1"> +<h2 id="recommendation">Recommendation</h2> +<div class="sectionbody"> +<div class="paragraph"> +<p><span class="image" style="float: left"><img src="../images/gremlin-recommendation.png" alt="gremlin-recommendation" width="180"></span>One of the more common use cases for a graph database is the +development of <a href="https://en.wikipedia.org/wiki/Recommender_system">recommendation systems</a> and a simple approach to +doing that is through <a href="https://en.wikipedia.org/wiki/Collaborative_filtering">collaborative filtering</a>. +Collaborative filtering assumes that if a person shares one set of opinions with a different person, they are likely to +have similar taste with respect to other issues. With that basis in mind, it is then possible to make predictions for a +specific person as to what their opinions might be.</p> +</div> +<div class="paragraph"> +<p>As a simple example, consider a graph that contains "person" and "product" vertices connected by "bought" edges. The +following script generates some data for the graph using that basic schema:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.addV(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>).property(<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>). + addV(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>).property(<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">bob</span><span class="delimiter">"</span></span>). + addV(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>).property(<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">jon</span><span class="delimiter">"</span></span>). + addV(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>).property(<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">jack</span><span class="delimiter">"</span></span>). + addV(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>).property(<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">jill</span><span class="delimiter">"</span></span>)iterate() +gremlin> (<span class="integer">1</span>..<span class="integer">10</span>).each { + g.addV(<span class="string"><span class="delimiter">"</span><span class="content">product</span><span class="delimiter">"</span></span>).property(<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">product #</span><span class="inline"><span class="inline-delimiter">${</span><span class="local-variable">it</span><span class="inline-delimiter">}</span></span><span class="delimiter">"</span></span>).iterate() + }; <span class="type">[]</span> +gremlin> (<span class="integer">3</span>..<span class="integer">7</span>).each { + g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">p</span><span class="delimiter">"</span></span>). + V().has(<span class="string"><span class="delimiter">"</span><span class="content">product</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">product #</span><span class="inline"><span class="inline-delimiter">${</span><span class="local-variable">it</span><span class="inline-delimiter">}</span></span><span class="delimiter">"</span></span>).addE(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).from(<span class="string"><span class="delimiter">"</span><span class="content">p</span><span class="delimiter">"</span></span>).iterate() + }; <span class="type">[]</span> +gremlin> (<span class="integer">1</span>..<span class="integer">5</span>).each { + g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">bob</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">p</span><span class="delimiter">"</span></span>). + V().has(<span class="string"><span class="delimiter">"</span><span class="content">product</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">product #</span><span class="inline"><span class="inline-delimiter">${</span><span class="local-variable">it</span><span class="inline-delimiter">}</span></span><span class="delimiter">"</span></span>).addE(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).from(<span class="string"><span class="delimiter">"</span><span class="content">p</span><span class="delimiter">"</span></span>).iterate() + }; <span class="type">[]</span> +gremlin> (<span class="integer">6</span>..<span class="integer">10</span>).each { + g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">jon</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">p</span><span class="delimiter">"</span></span>). + V().has(<span class="string"><span class="delimiter">"</span><span class="content">product</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">product #</span><span class="inline"><span class="inline-delimiter">${</span><span class="local-variable">it</span><span class="inline-delimiter">}</span></span><span class="delimiter">"</span></span>).addE(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).from(<span class="string"><span class="delimiter">"</span><span class="content">p</span><span class="delimiter">"</span></span>).iterate() + }; <span class="type">[]</span> +gremlin> <span class="integer">1</span>.step(<span class="integer">10</span>, <span class="integer">2</span>) { + g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">jack</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">p</span><span class="delimiter">"</span></span>). + V().has(<span class="string"><span class="delimiter">"</span><span class="content">product</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">product #</span><span class="inline"><span class="inline-delimiter">${</span><span class="local-variable">it</span><span class="inline-delimiter">}</span></span><span class="delimiter">"</span></span>).addE(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).from(<span class="string"><span class="delimiter">"</span><span class="content">p</span><span class="delimiter">"</span></span>).iterate() + }; <span class="type">[]</span> +gremlin> <span class="integer">2</span>.step(<span class="integer">10</span>, <span class="integer">2</span>) { + g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">jill</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">p</span><span class="delimiter">"</span></span>). + V().has(<span class="string"><span class="delimiter">"</span><span class="content">product</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">product #</span><span class="inline"><span class="inline-delimiter">${</span><span class="local-variable">it</span><span class="inline-delimiter">}</span></span><span class="delimiter">"</span></span>).addE(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).from(<span class="string"><span class="delimiter">"</span><span class="content">p</span><span class="delimiter">"</span></span>).iterate() + }; <span class="type">[]</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>The first step to making a recommedation to "alice" using collaborative filtering is to understand what she bought:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> 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">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).values(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>) +==>product <span class="error">#</span><span class="integer">5</span> +==>product <span class="error">#</span><span class="integer">6</span> +==>product <span class="error">#</span><span class="integer">7</span> +==>product <span class="error">#</span><span class="integer">3</span> +==>product <span class="error">#</span><span class="integer">4</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>The following diagram depicts one of the edges traversed in the above example between "alice" and "product #5". +Obviously, the other products "alice" bought would have similar relations, but this diagram and those to follow will +focus on the neighborhood around that product.</p> +</div> +<div class="paragraph"> +<p><span class="image"><img src="../images/recommendation-alice-1.png" alt="recommendation-alice-1" width="500"></span></p> +</div> +<div class="paragraph"> +<p>The next step is to determine who else purchased those products:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> 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">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).in(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).dedup().values(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>) +==>alice +==>bob +==>jack +==>jill +==>jon</code></pre> +</div> +</div> +<div class="paragraph"> +<p>It is worth noting that "alice" is in the results above. She should really be excluded from the list as the +interest is in what individuals other than herself purchased:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> 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>).as(<span class="string"><span class="delimiter">'</span><span class="content">her</span><span class="delimiter">'</span></span>). + out(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>). + in(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).where(neq(<span class="string"><span class="delimiter">'</span><span class="content">her</span><span class="delimiter">'</span></span>)). + dedup().values(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>) +==>bob +==>jack +==>jill +==>jon</code></pre> +</div> +</div> +<div class="paragraph"> +<p>The following diagram shows "alice" and those others who purchased "product #5".</p> +</div> +<div class="paragraph"> +<p><span class="image"><img src="../images/recommendation-alice-2.png" alt="recommendation-alice-2" width="600"></span></p> +</div> +<div class="paragraph"> +<p>The knowledge of the people who bought the same things as "alice" can then be used to find the set of products that +they bought:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> 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>).as(<span class="string"><span class="delimiter">'</span><span class="content">her</span><span class="delimiter">'</span></span>). + out(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>). + in(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).where(neq(<span class="string"><span class="delimiter">'</span><span class="content">her</span><span class="delimiter">'</span></span>)). + out(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>). + dedup().values(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>) +==>product <span class="error">#</span><span class="integer">1</span> +==>product <span class="error">#</span><span class="integer">2</span> +==>product <span class="error">#</span><span class="integer">3</span> +==>product <span class="error">#</span><span class="integer">4</span> +==>product <span class="error">#</span><span class="integer">5</span> +==>product <span class="error">#</span><span class="integer">7</span> +==>product <span class="error">#</span><span class="integer">9</span> +==>product <span class="error">#</span><span class="integer">6</span> +==>product <span class="error">#</span><span class="integer">8</span> +==>product <span class="error">#</span><span class="integer">10</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p><span class="image"><img src="../images/recommendation-alice-3.png" alt="recommendation-alice-3" width="800"></span></p> +</div> +<div class="paragraph"> +<p>This set of products could be the basis for recommendation, but it is important to remember that "alice" may have +already purchased some of these products and it would be better to not pester her with recommedations for products +that she already owns. Those products she already purchased can be excluded as follows:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> 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>).as(<span class="string"><span class="delimiter">'</span><span class="content">her</span><span class="delimiter">'</span></span>). + out(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).aggregate(<span class="string"><span class="delimiter">'</span><span class="content">self</span><span class="delimiter">'</span></span>). + in(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).where(neq(<span class="string"><span class="delimiter">'</span><span class="content">her</span><span class="delimiter">'</span></span>)). + out(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).where(without(<span class="string"><span class="delimiter">'</span><span class="content">self</span><span class="delimiter">'</span></span>)). + dedup().values(<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>) +==>product <span class="error">#</span><span class="integer">1</span> +==>product <span class="error">#</span><span class="integer">2</span> +==>product <span class="error">#</span><span class="integer">9</span> +==>product <span class="error">#</span><span class="integer">8</span> +==>product <span class="error">#</span><span class="integer">10</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p><span class="image"><img src="../images/recommendation-alice-4.png" alt="recommendation-alice-4" width="800"></span></p> +</div> +<div class="paragraph"> +<p>The final step would be to group the remaining products (instead of <code>dedup()</code> which was mostly done for demonstration +purposes) to form a ranking:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.V().has(<span class="string"><span class="delimiter">'</span><span class="content">person</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">name</span><span class="delimiter">'</span></span>,<span class="string"><span class="delimiter">'</span><span class="content">alice</span><span class="delimiter">'</span></span>).as(<span class="string"><span class="delimiter">'</span><span class="content">her</span><span class="delimiter">'</span></span>). <span class="comment">//</span><b>(1)</b> + out(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).aggregate(<span class="string"><span class="delimiter">'</span><span class="content">self</span><span class="delimiter">'</span></span>). <span class="comment">//</span><b>(2)</b> + <span class="keyword">in</span>(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).where(neq(<span class="string"><span class="delimiter">'</span><span class="content">her</span><span class="delimiter">'</span></span>)). <span class="comment">//</span><b>(3)</b> + out(<span class="string"><span class="delimiter">'</span><span class="content">bought</span><span class="delimiter">'</span></span>).where(without(<span class="string"><span class="delimiter">'</span><span class="content">self</span><span class="delimiter">'</span></span>)). <span class="comment">//</span><b>(4)</b> + groupCount().order(local).by(values, decr) <span class="comment">//</span><b>(5)</b> +==>[v[<span class="integer">10</span>]:<span class="integer">6</span>,v[<span class="integer">26</span>]:<span class="integer">5</span>,v[<span class="integer">12</span>]:<span class="integer">5</span>,v[<span class="integer">24</span>]:<span class="integer">4</span>,v[<span class="integer">28</span>]:<span class="integer">2</span>]</code></pre> +</div> +</div> +<div class="colist arabic"> +<ol> +<li> +<p>Find "alice" who is the person for whom the product recommendation is being made.</p> +</li> +<li> +<p>Traverse to the products that "alice" bought and gather them for later use in the traversal.</p> +</li> +<li> +<p>Traverse to the "person" vertices who bought the products that "alice" bought and exclude "alice" herself from that list.</p> +</li> +<li> +<p>Given those people who bought similar products to "alice", find the products that they bought and exclude those that she already bought.</p> +</li> +<li> +<p>Group the products and count the number of times they were purchased by others to come up with a ranking of products to recommend to "alice".</p> +</li> +</ol> +</div> +<div class="paragraph"> +<p>The previous example was already described as "basic" and obviously could take into account whatever data is available +to further improve the quality of the recommendation (e.g. product ratings, times of purchase, etc.). One option to +improve the quality of what is recommended (without expanding the previous dataset) might be to choose the person +vertices that make up the recommendation to "alice" who have the largest common set of purchases.</p> +</div> +<div class="paragraph"> +<p>Looking back to the previous code example, consider its more strip down representation that shows those individuals +who have at least one product in common:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>). + out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).aggregate(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>). + in(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).where(neq(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>)).dedup() +==>v[<span class="integer">2</span>] +==>v[<span class="integer">6</span>] +==>v[<span class="integer">8</span>] +==>v[<span class="integer">4</span>]</code></pre> +</div> +</div> +<div class="paragraph"> +<p>Next, do some grouping to find count how many products they have in common:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>). + out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).aggregate(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>). + in(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).where(neq(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>)).dedup(). + group().by().by(out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).where(within(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>)).count()) +==>[v[<span class="integer">2</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">3</span>,v[<span class="integer">8</span>]:<span class="integer">2</span>]</code></pre> +</div> +</div> +<div class="paragraph"> +<p>The above output shows that the best that can be expected is three common products. The traversal needs to be aware of +that maximum:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>). + out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).aggregate(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>). + in(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).where(neq(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>)).dedup(). + group().by().by(out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>). + where(within(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>)).count()). + select(values).order(local).by(decr).limit(local, <span class="integer">1</span>) +==><span class="integer">3</span></code></pre> +</div> +</div> +<div class="paragraph"> +<p>With the maximum value available, it can be used to chose those "person" vertices that have the three products in +common:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>). + out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).aggregate(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>). + in(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).where(neq(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>)).dedup(). + group().by().by(out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>). + where(within(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>)).count()).as(<span class="string"><span class="delimiter">"</span><span class="content">g</span><span class="delimiter">"</span></span>). + select(values).order(local).by(decr).limit(local, <span class="integer">1</span>).as(<span class="string"><span class="delimiter">"</span><span class="content">m</span><span class="delimiter">"</span></span>). + select(<span class="string"><span class="delimiter">"</span><span class="content">g</span><span class="delimiter">"</span></span>).unfold().where(select(values).as(<span class="string"><span class="delimiter">"</span><span class="content">m</span><span class="delimiter">"</span></span>)).select(keys) +==>v[<span class="integer">2</span>] +==>v[<span class="integer">6</span>]</code></pre> +</div> +</div> +<div class="paragraph"> +<p>Now that there is a list of "person" vertices to base the recommendation on, traverse to the products that they +purchased:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>). + out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).aggregate(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>). + in(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).where(neq(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>)).dedup(). + group().by().by(out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>). + where(within(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>)).count()).as(<span class="string"><span class="delimiter">"</span><span class="content">g</span><span class="delimiter">"</span></span>). + select(values).order(local).by(decr).limit(local, <span class="integer">1</span>).as(<span class="string"><span class="delimiter">"</span><span class="content">m</span><span class="delimiter">"</span></span>). + select(<span class="string"><span class="delimiter">"</span><span class="content">g</span><span class="delimiter">"</span></span>).unfold().where(select(values).as(<span class="string"><span class="delimiter">"</span><span class="content">m</span><span class="delimiter">"</span></span>)).select(keys). + out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).where(without(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>)) +==>v[<span class="integer">10</span>] +==>v[<span class="integer">10</span>] +==>v[<span class="integer">12</span>] +==>v[<span class="integer">26</span>]</code></pre> +</div> +</div> +<div class="paragraph"> +<p>The above output shows that one product is held in common making it the top recommendation:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> g.V().has(<span class="string"><span class="delimiter">"</span><span class="content">person</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>,<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>).as(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>). + out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).aggregate(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>). + in(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).where(neq(<span class="string"><span class="delimiter">"</span><span class="content">alice</span><span class="delimiter">"</span></span>)).dedup(). + group().by().by(out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>). + where(within(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>)).count()).as(<span class="string"><span class="delimiter">"</span><span class="content">g</span><span class="delimiter">"</span></span>). + select(values).order(local).by(decr).limit(local, <span class="integer">1</span>).as(<span class="string"><span class="delimiter">"</span><span class="content">m</span><span class="delimiter">"</span></span>). + select(<span class="string"><span class="delimiter">"</span><span class="content">g</span><span class="delimiter">"</span></span>).unfold().where(select(values).as(<span class="string"><span class="delimiter">"</span><span class="content">m</span><span class="delimiter">"</span></span>)).select(keys). + out(<span class="string"><span class="delimiter">"</span><span class="content">bought</span><span class="delimiter">"</span></span>).where(without(<span class="string"><span class="delimiter">"</span><span class="content">self</span><span class="delimiter">"</span></span>)). + groupCount().order(local).by(values, decr).by(select(keys).values(<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>)).unfold().select(keys).values(<span class="string"><span class="delimiter">"</span><span class="content">name</span><span class="delimiter">"</span></span>) +==>product <span class="error">#</span><span class="integer">1</span> +==>product <span class="error">#</span><span class="integer">2</span> +==>product <span class="error">#</span><span class="integer">9</span></code></pre> +</div> +</div> +</div> +</div> +<div class="sect1"> <h2 id="shortest-path">Shortest Path</h2> <div class="sectionbody"> <div class="paragraph"> @@ -1542,9 +1833,7 @@ is a simple example that identifies the </div> <div class="listingblock"> <div class="content"> -<pre class="CodeRay"><code class="groovy language-groovy">gremlin> graph = TinkerGraph.open() -==>tinkergraph[<span class="key">vertices</span>:<span class="integer">0</span> <span class="key">edges</span>:<span class="integer">0</span>] -gremlin> v1 = graph.addVertex(T.id, <span class="integer">1</span>) +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> v1 = graph.addVertex(T.id, <span class="integer">1</span>) ==>v[<span class="integer">1</span>] gremlin> v2 = graph.addVertex(T.id, <span class="integer">2</span>) ==>v[<span class="integer">2</span>] @@ -1601,9 +1890,7 @@ but includes a "weight" on the edges, th </div> <div class="listingblock"> <div class="content"> -<pre class="CodeRay"><code class="groovy language-groovy">gremlin> graph = TinkerGraph.open() -==>tinkergraph[<span class="key">vertices</span>:<span class="integer">0</span> <span class="key">edges</span>:<span class="integer">0</span>] -gremlin> v1 = graph.addVertex(T.id, <span class="integer">1</span>) +<pre class="CodeRay"><code class="groovy language-groovy">gremlin> v1 = graph.addVertex(T.id, <span class="integer">1</span>) ==>v[<span class="integer">1</span>] gremlin> v2 = graph.addVertex(T.id, <span class="integer">2</span>) ==>v[<span class="integer">2</span>] @@ -2064,7 +2351,7 @@ submissions!</p> </div> <div id="footer"> <div id="footer-text"> -Last updated 2016-10-12 14:45:07 -04:00 +Last updated 2016-10-13 11:25:27 -04:00 </div> </div> </body>