Developer Notes

Spring Data Neo4j Logo

Neo4j - [IS_A] -> Property Graph

Nodes with key-value properties are connected by typed, directed relationships with properties.

TODO put in a pretty picture

Cypher is a query language:

start movie=(id) match movie<-[:ACTS_IN]-actor
where actor.age > 20 return movie, actor.name
order by movie.title 

Traversals walk the graph in the prescribed way

TraversalDescription actors = Traversal.description()
  .relationships("ACTS_IN").filter(returnAllButStartNode());

for (Node actor : actors.traverse(movie))
 ...

Transactional: TX needed for write operations

try (Transaction tx=graphDatabaseService.beginTx()) {
  ... graph operations ...
  tx.success();
} catch(Exception e) {
  tx.failure();
}
       

Maven Dependency

   <dependency>
       <groupId>org.springframework.data</groupId>
       <artifactId>spring-data-neo4j[-aspects]</artifactId>
       <version>2.0.0.RC1</version>
   </dependency>

Spring-Config

<beans ...
 xmlns:neo4j="http://www.swf.org/schema/data/neo4j"
   xsi:schemaLocation=
   "http://www.sfw.org/schema/data/neo4j" ...>

...
<neo4j:config store-dir="graph.db"/>
<neo4j:repositories base-package="com.example.repositories"/>
...
</beans>

Testing

<neo4j:config graphDatabaseService="gds"/>
<bean id="gds" class="...ImpermanentGraphDatabase"/>

REST

<neo4j:config graphDatabaseService="rds"/>
<bean id="rds" class="...SpringRestGraphDatabase"/>

Entity - Annotations

Example

@NodeEntity
public class Movie {

   @GraphId Long id;

   @Indexed(fulltext = true, indexName = "search")
   String title;

   Person director;

   @RelatedTo(type="ACTS_IN", direction = INCOMING)
   Set<Person> actors;

   @RelatedToVia(type = "RATED")
   Iterable<Rating> ratings;
   
   @Query("start movie=node({self}) match
           movie-->genre<--similar return similar")
   Iterable<Movie> similarMovies;
}

Repositories

interface MovieRepository extends GraphRepository<Movie> {
 @Query("start movie={0} match m<-[rating:RATED]-user
       return rating")
 Iterable<Rating> getRatings(Movie movie);
 // Co-Actors
 Iterable<Person> findByActorsMoviesActorName(name)
}

<neo4j:repositories base-package="com.example.dao"/>

Neo4jTemplate

AspectJ - ActiveRecordMixin

adds the following methods, when implementing the NodeBacked interface
getPersistentState()
relateTo(target, ...),
getRelationshipTo(...)
persist(),
remove(),
detach()
...

Roo Add-on

roo> addon search graph
roo> addon install id --searchResultId 01
roo> project --topLevelPackage net.cineasts
roo> graph setup --provider NEO4J --databaseLocation cineasts
roo> graph entity --class ~.model.Movie
roo> field string title
roo> graph entity --class ~.model.Actor
roo> field string name
roo> graph relationship --to Movie --from Actor
  --fieldName movies --type ACTS_IN --cardinality ONE_TO_MANY
roo> controller all --package ~.web

Libraries

spring-data-neo4j

Provides Repository based Object <-> Graph Mapping that copies data from and to the graph database.

spring-data-neo4j-aspects

Provides transparent property and relationship mapping inside of transactions with live read- and write-through to the graph database.

spring-data-neo4j-cross-store

Allows to partially store properties and relationships of JPA entities in the graph database.

spring-data-neo4j-rest

Provides transparent remote access to Neo4j-Server via its REST Api (uses org.neo4j:neo4j-rest-graphdb)

AspectJ - STS / eclipse setup

Links