Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Oliver Gierke and Michael Hunger on Spring Data...

Oliver Gierke and Michael Hunger on Spring Data JPA and Neo4J

More Decks by Enterprise Java User Group Austria

Other Decks in Technology

Transcript

  1. Who are we? ๏Oliver Gierke - SpringSource, a division of

    VMware •SpringSource engineer •Spring Data JPA / MongoDB project lead •[email protected] / @olivergierke ๏Michael Hunger - Neo Technology •passionate software developer / Neo4j German Division •Spring Data Graph Project Lead / Neo4j Cloud Hosting •[email protected] / @mesirii
  2. Spring Data projects ๏Code is in SpringSource git repository: •http://springsource.org/spring-data

    •https://github.com/SpringSource/spring-data-* ๏Includes: •data-commons •spring-data-neoj •spring-data-{redis,riak} •spring-data-mongo •spring-data-jdbc •spring-data-jpa
  3. What is Spring Data 6 ๏VMWare/SpringSource initiative to give Spring

    developers easy access to data access: •Non-relational databases •MapReduce •Grails NOSQL support •Cross-store persistence •Object Persistence Mapping Infrastructure •Generic Repository Infrastructure •upcoming Spring Roo add-ons
  4. What does NOSQL stand for? It’s not “No to SQL”

    It’s not “Never SQL” It’s “Not Only SQL” NOSQL \no-seek-wool\ n. Describes ongoing trend where developers increasingly opt for non-relational databases to help solve their problems, in an effort to use the right tool for the right job.
  5. Kategorie 1: Key-Value Datenbanken 10 ๏Herkunft: •“Dynamo: Amazon’s Highly Available

    Key-Value Store” (2007) ๏Datenmodell: •Globale HashMap - Key-Value Paare ๏Beispiele: •Project Voldemort •Tokyo {Cabinet, Tyrant, etc} •Riak
  6. Kategorie II: Column (BigTable) Datenbanken 11 ๏Herkunft: •“Bigtable: A Distributed

    Storage System for Structured Data” (2006) ๏Datenmodell: •Große Tabelle mit Spalten Familien ๏Beispiele: •HBase •HyperTable •Cassandra
  7. Kategorie III: Dokumentendatenbanken 12 ๏Herkunft: •Lotus Notes ๏Datenmodell: •Sammlung von

    Dokumenten •Ein Dokument ist eine Key-Value Menge ๏Beispiele: •CouchDB •MongoDB •Terrastore
  8. Kategorie IV: Graphendatenbanken 13 ๏Herkunft: •Graphentheory, Euler ๏Datenmodell: •Knoten mit

    Attributen •Gerichtete Kanten •Kanten mit Identität, Typ und Attributen •Hyperedges
  9. Scaling to size vs. Scaling to complexity 14 Size Complexity

    Key/Value stores Bigtable clones Document databases Graph databases > 90% of use cases Billions of nodes and relationships
  10. Polyglot Persistence 16 ๏Ein System, mehrere Datenbanken - das beste

    Tool für das Problem nutzen ๏Beispiele: •RDBMS für strukturierte Daten und eine Graphendatenbank für die Relationen zwischen den Entitäten •Domänenmodell in der Graphendatenbank und große Dokumente in einer Dokumenten Datenbank
  11. 18

  12. Willkommen in der Matrix - die Welt - ein Netz

    20 Google Bildersuche: „graph OR network“
  13. Willkommen in der Matrix - die Welt - ein Netz

    ๏Zusammenhänge in •Politik, Wirtschaft, Geschichte, Wissenschaft, Verkehr ๏Biologie, Chemie, Physik, Soziologie •Körper, Ökosphere, Reaktionen, Interaktionen ๏Internet •Hardware, Software, Interaktion ๏Soziale Netzwerke •Familie, Freunde •Arbeit, Communities •Nachbarn, Städte, Lebensräume, Gesellschaft 21
  14. 22 Informationswachstum Datenmenge Geräte Vernetzung aktive Nutzer 1990 2000 2011

    Text Hypertext RSS Blogs Wikis user generated tagging RDF Ontologien Semantic Web Giant Global Graph web 1.0 web 2.0 web 3.0 Application Applications Services / Applications
  15. Gute Beziehungen ๏die Welt besteht aus Dingen und deren Beziehungen

    ๏Beziehungen sind oft genauso wichtig wie die Dinge ๏Netze = Ganzes > Summe der Teile ๏komplexe Zusammenhänge ๏ständiger Wandel, Veränderung auch von Strukturen ๏Graph: Beziehungen sind Teil der Daten ๏RDBMS: Beziehungen sind Teil des starren Schemas 23
  16. Fragen und Antworten ๏Komplexe Fragen ๏Antworten liegen zwischen den Zeilen

    (Dingen) ๏Lokalität der Informationen ๏Globale Suchen sind sehr teuer ๏Antwortzeiten sollten konstant sein, unabhängig von Datenmenge 24
  17. Kategorien ? ๏Kategorien == Klassen, Bäume ? ๏Was ist wenn

    mehr als eine Kategorie passt? ๏Tags ๏Kategorie über Beziehungen „IS_A“ ๏beliebig viele, schnelle Änderung ๏„virtuelle“ Beziehungen - Traversals ๏Kategorie dynamisch aus den Fragestellungen 25
  18. Deb Roy - MIT & Bluefin Labs 28 „Birth of

    a Word“ TED Talk Researches Social Reactions to (Media) Events
  19. The Property Graph data model 29 LIVES WITH LOVES OWNS

    DRIVES LOVES name: “James” age: 32 twitter: “@spam” name: “Mary” age: 35 brand: “Volvo” model: “V70” item type: “car” •Nodes •Relationships between Nodes •Relationships have Labels •Relationships are directed, but traversed at equal speed in both directions •The semantics of the direction is up to the application (LIVES WITH is reflexive, LOVES is not) •Nodes have key-value properties •Relationships have key-value properties
  20. Anwendungsgebiete ๏Stark vernetzte Domänen ๏Beziehungen zwischen Entitäten sind ein wichtiger

    Aspekt ๏Komplexe Fragestellungen ๏Lokale Antworten, durch mehrstufige Traversierung 30
  21. ungeeignete Anwendungsgebiete ๏Datenmengen > Pentabyte ๏viele parallele simple lookup Anfragen

    (KV) ๏massive Setoperationen auf großen, gleich strukturierten Daten (RDBMS) ๏viele große Binärdaten (BLOB) 35
  22. Neo4j is a Graph Database 36 IS_A Neo4j Graph Database

    Graph databases FOCUS on the interconnection between entities.
  23. Ein kleines soziales Netz Knoten haben verschiedene Eigenschaften Matrix Charaktere:

    Menschen vs. Programme Strukturen und Eigenschaften nach und nach aufbauen Fragestellungen: Gegner von Neo
  24. Neo4j API: Creating a social graph 39 GraphDatabaseService graphDb =

    new EmbeddedGraphDatabase( GRAPH_STORAGE_LOCATION ); Transaction tx = graphDb.beginTx(); try { Node mrAnderson = graphDb.createNode(); mrAnderson.setProperty( "name", "Thomas Anderson" ); mrAnderson.setProperty( "age", 29 ); Node morpheus = graphDb.createNode(); morpheus.setProperty( "name", "Morpheus" ); morpheus.setProperty( "rank", "Captain" ); Relationship friendship = mrAnderson.createRelationshipTo( morpheus, SocialGraphTypes.FRIENDSHIP ); tx.success(); } finally { tx.finish(); }
  25. Neo4j SDG API: Creating a social graph 40 @NodeEntity class

    Person { @Indexed String name; @Min(0) @Max(120) int age; Rank rank; @RelatedTo(elementClass= Person.class, type = "FRIENDSHIP") Set<Person> friends; } Person mrAnderson = new Person("Thomas Anderson"); mrAnderson.setAge( 29 ); Person morpheus = new Person("Morpheus" ); morpheus.setRank( Rank.Captain ); mrAnderson.getFriends().add(morpheus); mrAnderson.relateTo(morpheus, "FRIENDSHIP");
  26. Neo4j Ruby API: Creating a social graph 41 gem install

    neo4j require ”rubygems” require 'neo4j' class Person include Neo4j::NodeMixin property :name, :age, :rank index :name has_n :friends end Neo4j::Transactoin.run do neo = Person.new :name=>'Neo', :age=>29 morpheus = Person.new :name=>'Morpheus', :rank=>'Captain' neo.friends << morpheus end neo.friends.each {|p|...}
  27. Neo4j API: Recommend new friends Node person = ... TraversalDescription

    friendsOfFriends = Traversal.description() .relationships( SocialGraphTypes.FRIENDSHIP ) .breadthFirst() .evaluator( Evaluators.atDepth( 2 ) ); for ( Node recommendation : friendsOfFriends.traverse( person ).nodes() ) { System.out.println( recommendedFriend.getProperty("name") ); } 42
  28. Neo4j API: How do I know this person? Node me

    = ... Node you = ... PathFinder shortestPathFinder = GraphAlgoFactory.shortestPath( Traversals.expanderForTypes( SocialGraphTypes.FRIENDSHIP, Direction.BOTH ), /* maximum depth: */ 4 ); Path shortestPath = shortestPathFinder.findSinglePath(me, you); for ( Node friend : shortestPath.nodes() ) { System.out.println( friend.getProperty( "name" ) ); } 43
  29. Gibt es eine Verbindung im sozialen Netz ๏Jeder hat durchschnittlich

    50 Freunde 44 Database # persons query time Relational database Neo4j Graph Database Neo4j Graph Database 1 000 2 000 ms 1 000 2 ms 1 000 000 2 ms Tobias Emil Johan Peter
  30. Mehr über Neo4j ๏Neo4j läuft produktiv •In 24/7 Betrieb seit

    2003 ๏Neo4j wird aktiv entwickelt •Neo Technology - neue 10.6M US$ Finanzierung •Rod Johnson Aufsichtsratsvorsitzender ๏Neo4j erbringt hochperformante Graphen-Operationen •32 Mrd Knoten/Relationships & 64 Mrd Properties •traversiert 1’000’000+ Relationships / Sekunde auf Standardhardware 46
  31. Features ๏ACID (JTA/JTS, XA, 2PC, Tx recovery, deadlock detection, MVCC)

    ๏Treiber (nativ, REST) für viele Programmiersprachen ๏Property Graph Model ๏hochperformante Traversals ๏Data Size / Short Strings ๏eigenes binäres Storage-Format (NIO / memory mapping) ๏Integration externer Transaction Manager ๏verschiedene Indexing Provider (Lucene, Redis, Berkeley DB) 47
  32. Neo4j ist Open Source - Produkte & Lizenzen 49 ๏Community

    Edition •alle Features, Embedded und Server •GPL ๏Advanced •+ Monitoring & Support •AGPL oder Commercial ๏Enterprise •HA •Online Backup •AGPL oder Commercial
  33. Aktive Community 50 ๏Open Source & Engagement ist Grundlage für

    Erfolg ๏durch GPL noch einmal verstärkt ๏sehr aktive Mailingliste (700 / Monat) ๏GitHub •http://github.com/neo4j •http://github.com/neo4j-examples ๏Wiki •http://wiki.neo4j.org ๏Alle Bindings / Driver von der Community entwickelt •http://neo4j.org/community/languages/
  34. Spring Data Graph ๏Focus on Spring Data Graph ๏VMWare is

    collaborating with Neo Technology, the company behind the Neo4j graph database. ๏Improved programming model: Annotation-based programming model for graph applications ๏Cross-store persistence: Extend existing JPA application with NOSQL persistence ๏Spring Roo support: Add graph persistence with Roo add-on
  35. public class Actor { private final Node underlyingNode; Actor( final

    Node node ) { underlyingNode = node; } public Node getUnderlyingNode() { return underlyingNode; } public final String getName() { return (String) underlyingNode.getProperty( “name” ); } public void setName( final String name ) { underlyingNode.setProperty( “name”, name ); } } Classic Neo4j domain class
  36. Spring Data Graph domain class @NodeEntity public class Actor {

    @Indexed private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Advised field
  37. Fields in node entities (@NodeEntity) •Primitive types and strings are

    directly persisted •For all other types, Spring conversion support can be used • Enum and Date conversion is provided out-of-the-box •Transient fields not persisted 55 @NodeEntity public class Actor { private String name; private int age; private HairColor hairColor; private transient String nickname; }
  38. Fields in node entities (@NodeEntity) •Fields of types that represent

    a node (@NodeEntity) 56 @NodeEntity public class Movie {} @NodeEntity public class Person { private Movie favoriteMovie; } @NodeEntity public class Movie { private Actor topActor; } @NodeEntity public class Actor { // Mirrors topActor in Movie @RelatedTo(type = ”topActor”, direction = Direction.INCOMING) private Movie wasTopActorIn; }
  39. What about relationships public Iterable<Movie> getMovies() { final List<Movie> movies

    = new LinkedList<Movie>(); for ( Relationship rel : underlyingNode.getRelationships( RelTypes.ACTS_IN, Direction.OUTGOING ) ) { movies.add( new Movie( rel.getEndNode() ) ); } return movies; } @NodeEntity class Actor { ... Old @RelatedTo(type="ACTS_IN", elementClass = Movie.class) private Set<Movie> movies; public Iterable<Movie> getMovies() { return movies; } New
  40. Fields in node entities (@NodeEntity) ๏Fields of collections of relationship

    entities: @RelatedToVia ๏Read only view of relationship entities 58 @RelationshipEntity public class Role { @StartNode private Actor actor; @EndNode private Movie movie; private String roleName; } @NodeEntity public class Actor { @RelatedToVia(type = “ACTS_IN”) private Iterable<Role> roles; }
  41. Indexing @NodeEntity public class Actor { @Indexed private String name;

    @Indexed private HairColor hairColor; GraphRepository<Actor> actorRepo = repoFactory.createGraphRepository(Actor.class); Actor kevin = actorRepo.findByPropertyValue(“name”, “Kevin Bacon”); Iterable<Actor> allBlondActors = actorRepo.findAllByPropertyValue(“hairColor”, “blond”); It can then be looked up: By annotating an entity field with @Indexed it becomes searchable:
  42. Indexing @NodeEntity public class Actor { @Indexed(fulltext = true) private

    String name; ๏Index name defaults to domain class name ๏Index key defaults to field name ๏Fulltext indices are possible with @Indexed(fulltext = true) ๏Repository query methods for any Lucene query, including ranges: Iterable<Actor> allKevinsOlderThan32 = actorRepo.findAllByQuery(“name:Kevin* AND age>32”); Iterable<Actor> youngActors = actorRepo.findAllByRange(“age”, 3, 18);
  43. Traversal 61 @NodeEntity public class Actor { @GraphTraversal( traversalBuilder =

    CoactorsTraversalDescriptionBuilder.class) private Iterable<Actor> coactors; } public class CoactorsTraversalDescriptionBuilder implements FieldTraversalDescriptionBuilder { public TraversalDescription build(...) { return Traversal.description() .evaluator(Evaluators.atDepth(2)) .relationships(RelTypes.ACTS_IN); } } Example for dynamic field computation
  44. Cypher query language 62 @NodeEntity public class Actor { @Query(“START

    actor=(%start) ” + “MATCH (actor)-[:ACTS_IN]->(movie)<-[:ACTS_IN]-(coactor) ” + “RETURN coactor”) private Iterable<Actor> coactors; } @NodeEntity public class Actor { @Query(“START actor=(%start) ” + “MATCH (actor)-[:ACTS_IN]->(movie)<-[:ACTS_IN]-(coactor) ” + “RETURN movie.title, coactor.name”) private Iterable<Map<String, Object>> movieCoactorPairs; }
  45. AspectJ 63 ๏Introduces interface to entities: •NodeBacked into @NodeEntity classes

    •RelationshipBacked into @RelationshipEntity classes ๏NodeBacked introduces methods such as: •relateTo •findByQuery •findAllByTraversal •...
  46. AspectJ - Tooling 64 ๏IDE‘s •latest versions of STS /

    Eclipse with current AJDT plugin •IntelliJ IDEA 10.5 compile + run, some editor quirks ‣full AspectJ support in IDEA 11 ๏Build Systems •Maven •Gradle •Ant / Ivy •...
  47. AspectJ - NodeBacked.relateTo 65 <T extends RelationshipBacked> T NodeBacked.relateTo( NodeBacked

    node, Class<T> relationshipEntityType, String relationshipType ); @NodeEntity public class Actor { public Role actsIn(Movie movie, String roleName) { Role role = relateTo(movie, Role.class, “ACTS_IN”); role.setName(roleName); return role; } } usage:
  48. AspectJ - NodeBacked.findByQuery 66 <T> T NodeBacked.findByQuery( String query, Class<T>

    targetType, Map<String, Object> params ); @NodeEntity public class Actor { public Iterable<Movie> getMoviesInCommon(Actor other) { return findByQuery(“START actor=(%start), other=(%other) ” + “MATCH actor-[:ACTS_IN]->movie<-[:ACTS_IN]-other ” + “RETURN movie”, Movie.class, MapUtil.map(“other”, other)); } } usage:
  49. Detached entities 67 •Detached •In transaction •Attached •Outside transaction •Attached

    •In transaction •Detached •Outside transaction entity.persist() entity.persist() beginTx() modify entity / data stored in mem beginTx() Create new entity create outside tx create in tx modify entity / data written through tx.commit() tx.commit() modify entity / data stored in mem Detached Attached
  50. Neo4j-Template (I) ๏well known Spring Template Pattern ๏Resource / Transaction

    Management ๏Convenience Methods ๏Execution Callbacks ๏Fluent Query Result Handling ๏Works also via REST with Neo4j-Server ๏Exception Translation 68
  51. Neo4j-Template (II) 69 template.exec(new GraphCallback.WithoutResult() { public void doWithGraphWithoutResult(GraphDatabase g)

    throws Exception { g.createRelationship(g.createNode(map("name","David")), g.createNode(map("name","Michael")), WORKS_WITH, map("project","SDG")); }}) template.lookup("node", "name", "David") .to(String.class, new PropertyContainerNameConverter()).single() template.traverse(node, traversal) .to(Integer.class,new ResultConverter<Path,Integer>() { public Integer convert(Path path, Class<String> type) { return path.length(); }}) template.query("start movie=(Movies,title, %m) match movie-->actor return actor", map("m","Matrix")).to(Actor.class) template.execute("g.v(ref).outE", map("ref",0)).to(Relationship.class)
  52. REST-Client-Support 70 <bean id="restGraphDatabaseService" class="org.springframework.data.neo4j.rest.RestGraphDatabase"> <constructor-arg value="http://localhost:7473/db/data" /> </bean> <datagraph:config

    graphDatabaseService="restGraphDatabaseService"/> ๏drop-in replacement for the embedded GraphDatabase ๏works transparently with POJO-Entity-Mapping and Neo4j-Template
  53. REST-Server-Support 71 public class HelloWorldInitializer extends SpringPluginInitializer { public HelloWorldInitializer()

    { super(new String[]{"spring/helloWorldServer-Context.xml"}, Pair.of("worldRepository", WorldRepository.class), Pair.of("graphRepositoryFactory", GraphRepositoryFactory.class)); } } ๏integrate Spring Data Graph config with already running Graph-Database in Neo4j-Server ๏expose Spring Beans as Jersey Injectables
  54. Spring Data Graph Roo add-on 73 ๏Roo adding support for

    non-JPA persistence providers ๏Spring Data Graph was the first NOSQL persistence Roo Add-On ๏See the chapter on Spring Data Graph in the latest O’Reilly Roo book, Getting Started with Roo.
  55. Spring Data Graph Roo add-on 74 roo> project --topLevelPackage org.neo4j.imdb

    roo> graph setup --provider NEO4J --databaseLocation target/imdb roo> graph entity --class ~.model.Movie roo> field string title roo> field number --fieldName year --type java.lang.Integer --permitReservedWords --primitive 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> graph relationship --via ~.model.Role --to Movie --from Actor --fieldName roles --type ACTS_IN --cardinality ONE_TO_MANY roo> graph relationship --from Movie --to Actor --type ACTS_IN --fieldName actors --direction INCOMING --cardinality MANY_TO_ONE roo> field string --fieldName title --class ~.model.Role roo> controller scaffold --class ~.web.ActorController --entity ~.model.Actor roo> controller scaffold --class ~.web.MovieController --entity ~.model.Movie
  56. Spring Data Graph Guidebook “Good Relationships” ๏Spring Data Graph comes

    with a great Guide Book, featuring: •Forewords by Rod Johnson and Emil Eifrem •An easy to read, narrative tutorial walkthrough for cineasts.net •A comprehensive reference for all the details •Check it out here: http://bit.ly/sdg-book 76 “I’m excited about Spring Data Graph.... Spring Data Graph makes working with Neo4j amazingly easy, and therefore has the potential to make you more successful as a developer.” Rod Johnson, founder of Spring
  57. The end (and the beginning!) ๏See the Spring Data Neo4j

    site for more info: http://bit.ly/sdg-home ๏Check out the 5 minute intro at GitHub: http://bit.ly/sdg-repo ๏Again, don’t miss our fantastic e-book on Spring Data Graph: http://bit.ly/sdg-book ๏Spring Data Forum at http://bit.ly/sd-forum ๏All about Neo4j: http://neo4j.org ๏Neo4j videos and webinars: http://video.neo4j.org
  58. Repository-Query-Support 79 interface MovieRepository extends GraphRepository<Movie> { @Query("start m=(%movie) match

    m-[ACTS_IN]-actor return actor") Iterable<Actor> getActorsCypher(@Param("movie") Movie m); @Query("start movie =(%movie) match (movie)<-[role:ACTS_IN]-(actor) return actor.name, role.title") Iterable<Map<String,Object>> getCast(@Param("movie") Movie m); @Query(value = "g.v(movie).out('ACTS_IN')", type = QueryType.Gremlin) Iterable<Person> getActorsGremlin(@Param("movie") Movie m); }
  59. Repositories 80 interface MovieRepository extends GraphRepository<Movie> {} <datagraph:repositories base-package=“com.example.repositories„/> @Controller

    public class MovieController { @Autowired MovieRepository moviesRepository; @RequestMapping(value = "/movies/{movieId}",...) public String show(Model model, @PathVariable String movieId) { Movie movie = moviesRepository.findByPropertyValue("id", movieId); model.addAttribute("movie", movie); return "/movies/show"; }}
  60. Other repository query methods Iterable<Actor> allActors = actorRepo.findAll(); long numberOfActors

    = actorRepo.count(); Actor jeffGoldblum = actorRepo.findOne(42); boolean actorExists = actorRepo.exists(42); Iterable<Actor> actors = actorRepo.findAllByTraversal(movie,traversal); Page<Actor> actors = actorRepo.findAll(new PageRequest(page, PAGE_SIZE)); Iterable<Actor> actorsByNameAndAge = actorRepo.findAll(new Sort(„name“,“age“));
  61. A scenario... You have a traditional web app using JPA

    to persist data to a relational database
  62. Adding social networking ... You would like to add some

    social networking features by using a NOSQL database - what are your options? A. Complete re-write of the app •Costly and time consuming •Upside: remove JPA and build it all on a NOSQL database B. Bolt on some social networking features with a completely separate data model •No integration between the JPA and NOSQL data models •Harder to maintain code due to this split C. Extend JPA data model with cross-store persistence, creating a unified data model ๏What would you choose?
  63. Option C: Introducing cross-store persistence ๏JPA data and NOSQL data

    can share a data model ๏Could be the entire entity, or some fields of an entity ๏We call this cross-store persistence •One transaction manager to coordinate the NOSQL database with the JPA relational database •AspectJ support to manage the NOSQL entities and fields
  64. The JPA data model Restaurant @Entity public class Restaurant {

    @Id @GeneratedValue private Long id; private String name; private String city; private String state; private String zipCode; UserAccount @Entity @Table(name = "user_account") public class UserAccount { @Id @GeneratedValue private Long id; private String userName; private String firstName; private String lastName; @Temporal(TemporalType.TIMESTAMP) private Date birthDate; @ManyToMany(cascade = CascadeType.ALL) private Set<Restaurant> favorites;
  65. Adding to the data model Recommendation @RelationshipEntity public class Recommendation

    { @StartNode private UserAccount user; @EndNode private Restaurant restaurant; private int stars; private String comment; Restaurant @Entity @NodeEntity(partial = true) public class Restaurant { @Id @GeneratedValue private Long id; private String name; private String city; private String state; private String zipCode; UserAccount @Entity @Table(name = "user_account") @NodeEntity(partial = true) public class UserAccount { @Id @GeneratedValue private Long id; private String userName; private String firstName; private String lastName; @Temporal(TemporalType.TIMESTAMP) private Date birthDate; @ManyToMany(cascade = CascadeType.ALL) private Set<Restaurant> favorites; @GraphProperty String nickname; @RelatedTo(type = "friends", elementClass = UserAccount.class) Set<UserAccount> friends; @RelatedToVia(type = "recommends", elementClass = Recommendation.class) Iterable<Recommendation> recommendations;