## Exploring Graph Data with Neo4j and Spring Boot ### Java Vienna Meetup April 2018
### Bio ![daja pic](daja.jpg) - Daniel Jahre (* 1977) - Linux and Open Source User since 1997 - Software Developer in Vienna - Part of ***Linuxwochen*** Organizing Team since 2008 - Joined ***Java Vienna*** in 2014
### Agenda - Why modelling Data as Graphs? - Neo4j - Cypher Query Language - Exploring Pet Clinic Example from Spring - Integrate everything into Spring Boot
# Why?
![whiteboard](whiteboard1.jpg)
![whiteboard clipart](Tableau-blanc-300px.png)
![network graph](Network-Management-Model.svg)
### Why? - Graphs are everywhere - We draw relations all the time - We have all sorts of diagrams
### Joe's Network ![Joe's Network](joes_network.png)
### Real World Examples - Facebook, Twitter, all social media - Routing problems - Recommendation Engines (e.g. Amazon) - [Analyzing the Panama Paper Leak (dzone)](https://dzone.com/articles/analyzing-the-panama-papers-with-Neo4j-data-models) - [The Story behind Russian Twitter Trolls](https://neo4j.com/blog/story-behind-russian-twitter-trolls/)
### Basics - A Graph is a ***set of vertices and edges*** - We use a directed property Graph - We call vertices ***nodes*** and edges ***relations*** - We put ***labels*** on nodes to identify special kind of nodes
![Neo4j Logo](neo4j_logo.png)
### Neo4j - built in 2007 on top of ***MySQL*** - rebuilt now with own backend to handle the graph models better - index-free adjacency (traveling neighbouring nodes is cheap) - ACID
### Neo4j - Licensing - Community Edition * GPLv3 - Enterprise Edition * AGPL or Commercial Licensing * Features clustering and load balancing etc.
### Neo4j - Installing - Packages for various platforms including instructions - Docker images - Cloud deployments
### Trying it out online - Neo4j Sandboxes https://neo4j.com/sandbox-v2/ - Small Cloud Hosting for free https://www.graphenedb.com/pricing.html
# CYPHER
### CYPHER - Query Language developed for ***Neo4j*** - Optimized to be human readable - Looks a bit like ascii art - ***openCYPHER*** project to open the Language to other databases
### CYPHER - Nodes, Relations and Connections - (node) - [:relation] - (node1)-[:related_to]->(node2)
### CYPHER - Adding data - ***CREATE*** * to create ***nodes*** and ***relations*** - ***MERGE*** * adds new ***nodes*** and ***relations*** if they not are already existing
### CYPHER - adding Joe and John ```CYPHER CREATE (joe:PERSON {firstname: "Joe", age: 42}) CREATE (john:PERSON {firstname: "John", age: 32}) CREATE (joe)-[:FRIEND_OF]->(john) CREATE (joe)-[:COLLEAGUE_OF]->(john) ```
### CYPHER - Query data - ***MATCH*** - ***WHERE*** (optional) - ***RETURN***
### CYPHER - querying Joe ```CYPHER MATCH (joe:PERSON) WHERE joe.firstname = "Joe" RETURN joe ```
### CYPHER - querying Joe's friends ```CYPHER MATCH (joe:PERSON) WHERE joe.firstname = "Joe" WITH joe MATCH (joe)-[:FRIEND_OF]->(fJoe:PERSON) RETURN fJoe, joe ```
### CYPHER - querying John's friends - by ignoring the direction of the relation ```CYPHER MATCH (john:PERSON) WHERE john.firstname = "John" WITH john MATCH (john)-[:FRIEND_OF]-(fJohn:PERSON) RETURN fJohn ```
### CYPHER - shorting last query ```CYPHER MATCH(john:PERSON {firstname: "John"})-[:FRIEND_OF]-() RETURN * ```
### Learning CYPHER ![Graph Databases book](graph_databases.png)
### Learning CYPHER - [Neo4j Website](https://Neo4j.com/docs/) - [CYPHER Refcard](https://Neo4j.com/docs/cypher-refcard/current/) - Learning Neo4j 3.x by Jérôme Baton (Pakt) - YouTube presentations
# PetClinic ![blue cat](Blue-Cat-300px.png)
### PetClinic - well known example for Spring - uses relational databases - We will port that model to Neo4j
### PetClinic - relational model ![PetClinic relational model](petclinic_relational.png)
### PetClinic - Listing Vets with Professions ```SQL SELECT v.FIRST_NAME, v.LAST_NAME, s.NAME from VETS v, SPECIALTIES s, VET_SPECIALTIES vs WHERE s.ID = vs.SPECIALTY_ID and v.ID = vs.VET_ID and s.NAME = 'surgery'; ```
### PetClinic - Vet Result ![Vet Results](result_sql_surgery.png)
### PetClinic - Insert Vets with CYPHER ```CYPHER CREATE(linda:Vet:Surgeon:Dentist {firstname: "Linda", lastname: "Douglas"}) CREATE(raf:Vet:Surgeon {firstname: "Rafael", lastname: "Ortega"}) CREATE(helen:Vet:Radiologist {firstname: "Helen", lastname: "Leary"}) CREATE(henry:Vet:Radiologist {firstname: "Henry", lastname: "Stevens"}) CREATE(sharon:Vet {firstname: "Sharon", lastname: "Jenkins"}) CREATE(james:Vet {firstname: "James", lastname: "Carter"}) ```
### PetClinic - List all Surgeons again ```CYPHER MATCH (n:Surgeon) RETURN n; ```
### Small Changes to the model - renamed Owners to Person - Created Cities as extra nodes instead of a property of Person - added MEDICATED_ON relation between Vets and Visits
### PetClinic - A marketing question - salesman calling - they invented a new dog food - they want to know in which area the most dogs live, so that they start their campaign there
### PetClinic - Query to get that answer ``` MATCH (c:City)-[*2]-(d:Dog) RETURN c, count(d) as count ORDER BY count DESC ```
# Neo4j and Spring Boot
### Basics - Neo4j OGM (Object Graph Mapper) - Spring Data on top of it - Spring Boot and the Spring Boot Starter for Neo4j
### The pom file ```
org.springframework.boot
spring-boot-starter-data-neo4j
org.springframework.data
spring-data-neo4j
org.neo4j
neo4j-ogm
```
### The configuration ``` @Configuration @EnableTransactionManagement @ComponentScan("org.springframework.samples.petclinic") @EnableNeo4jRepositories("org.springframework.samples.petclinic.repository") public class PersistenceContext { @Bean public SessionFactory getSessionFactory() { return new SessionFactory(configuration(), "org.springframework.samples.petclinic.model"); } @Bean public Neo4jTransactionManager transactionManager() throws Exception { return new Neo4jTransactionManager(getSessionFactory()); } @Bean public org.neo4j.ogm.config.Configuration configuration() { ConfigurationSource properties = new ClasspathConfigurationSource("db.properties"); return new org.neo4j.ogm.config.Configuration.Builder(properties).build(); } } ```
### Entity types - Node Entities - Relationship Entities (only needed for rich relationships) - PetClinic example only uses Node Entities
### BaseEntity ``` public class BaseEntity { @Id @GeneratedValue protected Long id; public Long getId() { return id; } public void setId(Long id) { this.id = id; } } ```
### Vet Entity ``` @NodeEntity public class Vet extends BaseEntity{ @Labels private List
labels = new ArrayList<>(); @Property(name = "firstname") private String firstName; @Property(name = "lastname") private String lastName; ... public String getSpecialties() { return StringUtils.join(labels, ", "); } ```
### Person Entity ``` @NodeEntity public class Person extends BaseEntity{ @Property(name = "firstname") String firstName; @Property(name = "lastname") String lastName; String address; String telephone; @Relationship(type="OWNS") Set
pets = new HashSet<>(); @Relationship(type="LIVES_IN") City city; ```
### Pet Entity ``` @NodeEntity public class Pet extends BaseEntity { @JsonIgnore @Labels List
labels = new ArrayList<>(); String name; @Property(name = "birthdate") LocalDate birthDate; @JsonIgnore @Relationship(type="OWNS", direction = Relationship.INCOMING) private Person owner; @Relationship(type = "WAS_ON") private Set
visits = new HashSet<>(); ```
### Example Relationship Entity ``` @RelationshipEntity(type="PLAYED_IN") public class Role { @Id @GeneratedValue private Long relationshipId; @Property private String title; @StartNode private Actor actor; @EndNode private Movie movie; } ```
### City Repository ``` public interface CityRepository extends Neo4jRepository
{ City findByName(String name); } ```
### Pet Repository ``` public interface PetRepository extends Neo4jRepository
{ /** * Retrieve all Pet types from the data store. * @return a Collection of pet types. */ @Query("MATCH (n:Pet) return distinct labels(n)") List
> getPetTypes(); Pet findById(long id); Pet save(Pet pet); } ```
### ClinicService ``` public Collection
getPetTypes() throws DataAccessException { HashMap
petTypes = new HashMap(); for (Collection
c : petRepository.getPetTypes()) { for (String entry : c) { if("BaseEntity".equals(entry) || "Pet".equals(entry)) { continue; } petTypes.put(entry, new PetType(entry)); } } return petTypes.values(); } ```
# Demo
### There is more (APOC) - A Package Of Components - Awesome Procedures On Cypher - Can be called from CYPHER queries - e.g. PageRank, Dijkstra, etc.
### There is more (GraphQL) - Query language for the API - database agnostic - used by Facebook, GitHub, Pinterest and others - can be combined with REST - http://graphql.org/
### How to convince your managers? ![manager](maninoffice-dictate-300px-2.png)
### How to convince your managers? - import data from csv or existing data source into Neo4j - try to adopt the model to your questions - integrate it into a spring boot application if that is your platform of choice - commercial support is available - you do not lose anything, but you can gain new insights
### Links - https://github.com/daja77/spring-petclinic-angularjs - https://github.com/daja77/neo4j-talk-2018 - https://neo4j.com/developer/graph-db-vs-rdbms/
# Thank you!