Documentation Updates (Template, Gremlin)

This commit is contained in:
Michael Hunger
2011-07-26 01:30:31 +02:00
parent 522712fbf9
commit fd7250c556
6 changed files with 234 additions and 80 deletions

View File

@@ -2,6 +2,17 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<!-- TODO
* Gremlin @Query on fields
* Gremlin @Query on repository methods
* variables in gremlin queries
* variables in cypher queries
* New Template Query API
* Spring Roo Addon, Intro, Example Session
* Update tutorial to include some of the new features (cypher, gremlin)
*
* more on Gremlin / Cypher over REST
-->
<bookinfo>
<title>Good Relationships</title>
<subtitle>The Spring Data Graph Guide Book</subtitle>
@@ -23,14 +34,6 @@
<firstname>David</firstname>
<surname>Montag</surname>
</author>
<author>
<firstname>Mark</firstname>
<surname>Pollack</surname>
</author>
<author>
<firstname>Thomas</firstname>
<surname>Risberg</surname>
</author>
</authorgroup>
<legalnotice>
@@ -40,6 +43,9 @@
further provided that each copy contains this Copyright Notice, whether
distributed in print or electronically.
</para>
<para>
Copyright 2010-2011 Neo Technology
</para>
</legalnotice>
</bookinfo>

View File

@@ -3,44 +3,76 @@
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<preface>
<title>About this guide book</title>
<para>
Welcome to the Spring Data Graph Guide Book. Thank you for taking the time to get an in depth look
into <ulink url="https://github.com/SpringSource/spring-data-graph">Spring Data Graph</ulink>.
This project is part of the <ulink url="http://springsource.org/spring-data">Spring Data project</ulink>,
which brings the convenient programming model of the Spring Framework to modern NOSQL databases.
Spring Data Graph, as the name alludes to, aims to provide support for graph databases. It currently
supports <ulink url="http://neo4j.org">Neo4j</ulink>.
</para>
<para>
It was written by developers for developers. Hopefully we've created a document that is well received
by our peers.
</para>
<para>
If you have any feedback on Spring Data Graph or this book, please provide it via the
<ulink url="https://jira.springsource.org/browse/DATAGRAPH">SpringSource JIRA</ulink>, the
<ulink url="http://forum.springsource.org/forumdisplay.php?f=80">SpringSource NOSQL Forum</ulink>,
<ulink url="https://github.com/SpringSource/spring-data-graph/issues">github comments or issues</ulink>,
or the <ulink url="http://neo4j.org/community/list/">Neo4j mailing list</ulink>.
</para>
<para>
This book is presented as a <ulink url="http://martinfowler.com/bliki/DuplexBook.html">duplex book</ulink>,
a term coined by Martin Fowler. A duplex book consists of at least two parts. The first part is an easily
accessible tutorial that gives the reader an overview of the topics contained in the book. It contains lots
of examples and discussion topics. This part of the book is highly suited for cover-to-cover reading.
</para>
<para>
We chose a tutorial describing the creation of a web application that allows movie enthusiasts to
find their favorite movies, rate them, connect with fellow movie geeks, and enjoy social features such as
recommendations. The application is running on Neo4j using Spring Data Graph and the well-known Spring
Web Stack.
</para>
<para>
The second part of the book is the classic reference documentation, containing detailed information about
the library. It discusses the programming model, the underlying assumptions, and internals, as well as the
APIs for the object-graph mapping. The reference documentation is typically used to look up concrete bits of
information, or to drill down into certain topics. For hackers wanting to really delve into Spring Data
Graph, it can of course also be read cover-to-cover.
</para>
<section>
<title>The Spring Data Graph Project</title>
<para>
Welcome to the Spring Data Graph Guide Book. Thank you for taking the time to get an in depth look
into <ulink url="https://github.com/SpringSource/spring-data-graph">Spring Data Graph</ulink>.
This project is part of the <ulink url="http://springsource.org/spring-data">Spring Data project</ulink>,
which brings the convenient programming model of the Spring Framework to modern NOSQL databases.
Spring Data Graph, as the name alludes to, aims to provide support for graph databases. It currently
supports <ulink url="http://neo4j.org">Neo4j</ulink>.
</para>
</section>
<section>
<title>Feedback</title>
<para>
It was written by developers for developers. Hopefully we've created a guide that is well received
by our peers.
</para>
<para>
If you have any feedback on Spring Data Graph or this book, please provide it via the
<ulink url="https://jira.springsource.org/browse/DATAGRAPH">SpringSource JIRA</ulink>, the
<ulink url="http://forum.springsource.org/forumdisplay.php?f=80">SpringSource NOSQL Forum</ulink>,
<ulink url="https://github.com/SpringSource/spring-data-graph/issues">github comments or issues</ulink>,
or the <ulink url="http://neo4j.org/community/list/">Neo4j mailing list</ulink>.
</para>
</section>
<section><title>Format of the Book</title>
<para>
This book is presented as a <ulink url="http://martinfowler.com/bliki/DuplexBook.html">duplex book</ulink>,
a term coined by Martin Fowler. A duplex book consists of at least two parts. The first part is an easily
accessible tutorial that gives the reader an overview of the topics contained in the book. It contains lots
of examples and discussion topics. This part of the book is highly suited for cover-to-cover reading.
</para>
<para>
We chose a tutorial describing the creation of a web application that allows movie enthusiasts to
find their favorite movies, rate them, connect with fellow movie geeks, and enjoy social features such as
recommendations. The application is running on Neo4j using Spring Data Graph and the well-known Spring
Web Stack.
</para>
<para>
The second part of the book is the classic reference documentation, containing detailed information about
the library. It discusses the programming model, the underlying assumptions, and internals, as well as the
APIs for the object-graph mapping. The reference documentation is typically used to look up concrete bits of
information, or to drill down into certain topics. For hackers wanting to really delve into Spring Data
Graph, it can of course also be read cover-to-cover.
</para>
</section>
<section><title>Acknowledgements</title>
<para>
We would like to thank everyone who contributed to this book, especially Mark Pollack and Thomas Risberg,
the leads of the Spring Data Project, who helped a lot during the development of the library as well as sharing
great feedback about the book. Also Oliver Gierke, our local German VMWare/SpringSource engineer, who invested a
lot of time discussing various aspects of the library as well as providing the superb foundations for the Spring
Data Repositories. We tortured Andy Clement, the AspectJ project lead, with many questions and issues around our
advanced AspectJ usage which caused some headaches. He always quickly solved our issues and gave us excellent
answers.
</para>
<para>
We also appreciate very much the foresight of Rod Johnson and Emil Eifrem to initiate the project, and now
also providing great forewords. Their leadership inspired collaboration between the engineering teams at
SpringSource and Neo Technology, a tremendous help during the making of Spring Data Graph.
 
</para>
 
<para>
Last but not least we thank our vibrant community, both in the Spring Forums as well as on the Neo4j
Mailing list and on many other places on the internet for giving us feedback, reporting issues and suggesting
improvements. Without that important feedback we wouldn't be where we are today.
 
</para>
</section>  
<para>
Enjoy the book!
</para>

View File

@@ -88,8 +88,8 @@ public void foo( @Context WorldRepository repo ) {
</note>
<para>
Please also keep in mind that performing graph operations via the REST-API is about one order of
magnitude slower than location operations. Try to use the Neo4j-Query-Language or
server-side traversals whenever possible (<code>RestTraversal</code>) for retrieving large sets of data.
magnitude slower than location operations. Try to use the Neo4j Cypher query language,
server-side traversals (<code>RestTraversal</code>) or Gremlin expressions whenever possible for retrieving large sets of data.
Future versions of Spring Data Graph will use the more performant batching as well as a binary protocol.
</para>
<para>
@@ -124,5 +124,8 @@ public void foo( @Context WorldRepository repo ) {
to the remote instance. (e.g. <code>queryEngineFor(), index() and createTraversalDescription()</code>).
Please use those methods when interacting with a remote server for optimal performance.
</para>
<para>
</para>
</section>
</chapter>

View File

@@ -150,6 +150,91 @@ try {
for (Node foundNode : nodeIndex.get("property","value")) {
// found node
}
]]></programlisting>
</example>
</section>
<section>
<title>Querying with Cypher</title>
<para>
With version 1.4.M04 Neo4j introduced a textual query language called
<ulink url="http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html">"Cypher"</ulink> which draws from many
sources. From graph matching like in SPARQL, some keywords and query structure that reminds of SQL and
some iconic representation. A screencast presenting cypher queries on the cineasts.net dataset is available
at <ulink url="http://video.neo4j.org/U2Y/introduction-to-cypher">video.neo4j.org</ulink>. Cypher was written
in Scala to leverage the high expressiveness for lazy sequence operations of the language and the great
parser combinator library.
</para>
<para>
Cypher queries always begin with a <code>start</code> set of nodes. Those can be either expressed by their
id's or by a index lookup expression. Those start-nodes are then related to other nodes in the
<code>match</code> clause to other nodes. Start and match clause can introduce new identifiers for nodes and
relationships. In the <code>where</code> clause additional filtering of the result set is applied by evaluating
boolean expressions. The <code>return</code> clause defines which part of the query result will be available.
Aggregation also happens in the return clause by using aggregation functions on some of the values.
Sorting can happen in the <code>order by</code> clause and the <code>skip</code> and <code>limit</code> parts
restrict the result set to a certain window.
</para>
<para>
Cypher can be executed on an embedded graph db using <code>ExecutionEngine</code> and
<code>CypherParser</code>. This is encapsulated in Spring Data Graph with
<code>CypherQueryEngine</code>. The Neo4j-REST-Server comes with a Cypher-Plugin that is accessible remotely and is
available in the Spring Data Graph REST-Binding.
</para>
<example>
<title>Cypher Examples on the Cineasts.net Dataset</title>
<programlisting><![CDATA[
// Actors of Forrest Gump:
start movie=(Movie,id,'13') match (movie)<-[:ACTS_IN]-(actor)
return actor.name, actor.birthplace?
// User-Ratings:
start user=(User,login,'micha') match (user)-[r,:RATED]->(movie) where r.stars > 3
return movie.title, r.stars, r.comment
// Mutual Friend recommendations:
start user=(User,login,'micha') match (user)-[:FRIEND]-(friend)-[r,:RATED]->(movie) where r.stars > 3
return friend.name, movie.title, r.stars, r.comment?
// Movie suggestions based on a movie:
start movie=(Movie,id,'13') match (movie)<-[:ACTS_IN]-()-[:ACTS_IN]->(suggestion)
return suggestion.title, count(*) order by count(*) desc limit 5
// Co-Actors, sorted by count and name of Lucy Liu
start lucy=(1000) match (lucy)-[:ACTS_IN]->(movie)<-[:ACTS_IN]-(co_actor)
return count(*), co_actor.name order by count(*) desc,co_actor.name limit 20
// recommendations including counts, grouping and sorting
start user=(User,login,'micha') match (user)-[:FRIEND]-(friend)-[r,:RATED]->(movie)
return movie.title, AVG(r.stars), count(*) order by AVG(r.stars) desc, count(*) desc
]]></programlisting>
</example>
</section>
<section>
<title>Gremlin a Graph Traversal DSL</title>
<para>
Gremlin is an expressive Groovy DSL developed by <ulink url="http://markorodriguez.com">Marko Rodriguez</ulink>
as part of the <ulink url="http://tinkerpop.com">tinkerpop</ulink> stack. It builds on top of a pipe implementation
(Blueprints Pipes) that uses connected operations to traverse a graph. Gremlin has a concise syntax but is
turing complete.
</para>
<para>Gremlin can be executed by including the tinkerpop and blueprints dependencies and then requesting a <code>ScriptEngine</code>
of type "gremlin" from the <code>javax.Script*</code> facilities. In Spring Data Graph this is encapsulated in
<code>GremlinQueryEngine</code>. The Neo4j-REST-Server also comes with a Gremlin-Plugin that is accessible remotely and is
available in the Spring Data Graph REST-Binding.
</para>
<example>
<title>Sample Gremlin Queries</title>
<programlisting><![CDATA[
// Vertex with id 1
v = g.v(1)
// determine the name of the vertices that vertex 1 knows and that are older than 30 years of age
v.outE{it.label=='knows'}.inV{it.age > 30}.name
// calculate basic collaborative filtering for vertex 1
m = [:]
g.v(1).out('likes').in('likes').out('likes').groupCount(m)
m.sort{a,b -> a.value <=> b.value}
]]></programlisting>
</example>
</section>

View File

@@ -59,7 +59,7 @@
</note>
<para>
The AspectJ support in IntelliJ IDEA lacks some of the features. JetBrains is working on improving
the situation in their upcoming 10.5 release of their popular IDE. Their latest work is available
the situation in their upcoming 11 release of their popular IDE. Their latest work is available
under their early access program (EAP). Building the project with the AspectJ compiler
<code>ajc</code> works in IDEA (Options -> Compiler -> Java Compiler should show ajc). Make sure to
give the compiler at least 512 MB of RAM.

View File

@@ -14,68 +14,89 @@
</para>
<para>
There are methods (<code>createNode()</code> and <code>createRelationship()</code>) for creating nodes and
relationships that automatically set provided properties and optionally index certain fields.
relationships that automatically set provided properties.
</para>
<example>
<title>Neo4j template</title>
<programlisting language="java"><![CDATA[<![CDATA[import static org.springframework.data.neo4j.core.Property._;
<programlisting language="java"><![CDATA[<![CDATA[import static org.neo4j.helpers.collection.MapUtil.map;
Neo4jOperations neo = new Neo4jTemplate(graphDatabaseService);
Node michael = neo.createNode(_("name","Michael"));
Node mark = neo.createNode(_("name","Mark"));
Node thomas = neo.createNode(_("name","Thomas"));
Node michael = neo.createNode(map("name","Michael"));
Node mark = neo.createNode(map("name","Mark"));
Node thomas = neo.createNode(map("name","Thomas"));
neo.createRelationship(mark,thomas, WORKS_WITH, _("project","spring-data"));
neo.createRelationship(mark,thomas, WORKS_WITH, map("project","spring-data"));
neo.index("devs",thomas, "name","Thomas");
assert "Mark".equals(neo.query("devs","name","Mark",new NodeNamePathMapper()));
]]></programlisting>
// Cypher
assert "Mark".equals(neo.query("start p=(%person) match p<-[:WORKS_WITH]-other return other.name",
map("person",thomas)).to(String.class).single());
// Gremlin
assert thomas.equals(neo.execute("g.v(person).out('WORKS_WITH')",
map("person",mark)).to(Node.class).single());
// Index lookup
assert mark.equals(neo.lookup("devs","name","Mark").single());
// Index lookup with Result Converter
assert "Mark".equals(neo.lookup("devs","name","Mark").to(String.class, new ResultConverter<PropertyContainer, String> {
public String convert(PropertyContainer element, Class<String> type) {
return (String) element.getProperty("name");
}}));]]></programlisting>
</example>
</section>
<section>
<title>QueryResult</title>
<para>
All querying methods of the template return a uniform result type: <code>QueryResult&lt;T&gt;</code>
which is also an <code>Iterable&lt;T&gt;</code>. The query result offers methods of converting each
element to a target type <code>queryResult.to(Type.class)</code> optionally supplying a
<code>ResultConverter&lt;FROM,TO&gt;</code> which takes care of custom conversions. By default most
query methods can already handle conversions from and to: Paths, Nodes, Relationship and GraphEntities
as well as conversions backed by registered ConversionServices. A converted <code>QueryResult&lt;FROM&gt;</code> is an
<code>Iterable&lt;TO&gt;</code>. QueryResults can be limited to a single value using the <code>queryResult.single()</code>
method. It also offers support for a pure callback function using a <code>Handler&lt;T&gt;</code>.
</para>
</section>
<section>
<title>Indexing</title>
<para>
Adding nodes and relationships to an index is done with the <code>index()</code> method.
</para>
<para>
The <code>query()</code> methods either take a field/value combination to look for exact matches in the
index, or a Lucene query object or string to handle more complex queries. All <code>query()</code>
methods provide <code>Path</code> results to a PathMapper.
The <code>lookup()</code> methods either take a field/value combination to look for exact matches in the
index, or a Lucene query object or string to handle more complex queries. All <code>lookup()</code>
methods return a <code>QueryResult&lt;PropertyContainer&gt;</code> to be used or transformed.
</para>
</section>
<section>
<title>Graph traversal</title>
<para>
The traversal methods are at the core of graph operations. As such, they are fully supported in the
<code>Neo4jTemplate</code>. The <code>traverseNext()</code> method traverses to the direct neighbors
of the start node, filtering the relationships according to the parameters.
</para>
<para>
The traversal methods are at the core of graph operations.
The <code>traverse()</code> method covers the full traversal operation that takes a
<code>TraversalDescription</code> (typically built with the <code>Traversal.description()</code>
DSL) and runs it from the start node. Each path that is returned by the traversal is passed to the
<code>PathMapper</code> to be converted into the desired type.
DSL) and runs it from the given start node. <code>traverse</code> returns a <code>QueryResult&lt;Path&gt;</code>
to be used or transformed.
</para>
</section>
<section>
<title>Path abstraction and PathMapper</title>
<title>Cypher Queries</title>
<para>
For the querying operations Neo4jTemplate unifies the result with the <code>Path</code> abstraction that
comes from Neo4j. Much like a result set, a path contains a chain of <code>nodes()</code> connected by
<code>relationships()</code>, starting at a <code>startNode()</code> and ending at a
<code>endNode()</code>. The <code>lastRelationship()</code> is also available separately. The
<code>Path</code> abstraction also wraps results that contain just nodes or relationships.
The <code>Neo4jTemplate</code> also allows execution of arbitrary Cypher queries. Via the <code>query</code>
methods the statement and parameter-Map are provided. Cypher Queries return tabular results, so the
<code>QueryResult&lt;Map&lt;String,Object&gt;&gt;</code> contains the rows which can be either used as they are
or converted as needed.
</para>
</section>
<section>
<title>Gremlin Scripts</title>
<para>
Using implementations of <code>PathMapper&lt;T&gt;</code> and <code>PathMapper.WithoutResult</code>
(comparable with <code>RowMapper</code> and <code>RowCallbackHandler</code>), the paths can be converted
to arbitrary Java objects.
</para>
<para>
With <code>EntityPath</code> and <code>EntityMapper</code> there is also support for using
node entities within the <code>Path</code> and <code>PathMapper</code> constructs.
Gremlin Scripts can run with the <code>execute</code> method, which also takes the parameters that will be
available as variables inside the script. The result of the executions is a generic
<code>QueryResult&lt;Object&gt;</code> fit for conversion or usage.
</para>
</section>
<section>
@@ -88,4 +109,11 @@ assert "Mark".equals(neo.query("devs","name","Mark",new NodeNamePathMapper()));
or the <code>TransactionTemplate</code>.
</para>
</section>
<section>
<title>Neo4j REST Server</title>
<para>If the template is configured to use a <code>RestGraphDatabase</code> the expensive operations
like traversals and querying are executed efficiently on the server side by using the REST API to forward
those calls. All the other template methods require single network operations.
</para>
</section>
</chapter>