Slide 1

Slide 1 text

Spice up Your Graph Gerrit Meier and Michael Simons introducing the all new Spring Data Neo4j (SDN 6) SpringOne 2020 Spring

Slide 2

Slide 2 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 2

Slide 3

Slide 3 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 4 Label Type

Slide 4

Slide 4 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 5 Person KNOWS { name: "Mr. X" dob: 26.02.1982 } { met: "Spring One" contact: 03.09.2020 }

Slide 5

Slide 5 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 6 Person KNOWS Person Topic INTERESTED_IN INTERESTED_IN { term: "Spring Data" description: " … " } Graph Databases

Slide 6

Slide 6 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 7 Spring Data Neo4j Team @meistermeier @rotnroll666

Slide 7

Slide 7 text

What would you do if you could create yet another object mapper from scratch?

Slide 8

Slide 8 text

What would you do if you could create yet another object mapper from scratch? Why

Slide 9

Slide 9 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 9 Current Spring Data Neoj4 + Neo4j-OGM • start.spring.io gives you SDN and Neo4j-OGM • 3 different modes available (Embedded, HTTP and native) • Makes usage of Cypher harder than necessary • Custom queries are possible but go all through the Neo4j-OGM abstraction • Some building parts stack vertically, some horizontally ➡ Confusing options for beginners

Slide 10

Slide 10 text

Spring Data Neo4j 6

Slide 11

Slide 11 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 11 What do we want? • A composable stack • Nicely integrated in Spring Boot • Access at all abstraction levels • Raw queries (outside application level transactions) • Raw queries (inside application level transactions) • Plus ad-hoc mapping • Mapping • Repository abstraction • Reactive (and imperative) database access

Slide 12

Slide 12 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 • Java Driver • Direct usage • Simple Client • RowMapper-like • Neo4jTemplate • Entity-Metadata aware • Repositories • DDD way of accessing your data Multiple, ordered levels of Abstraction

Slide 13

Slide 13 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 13 Spring Data Repositories Neo4j Template Neo4j Client Neo4j Java Driver spring-boot-starter-data-neo4j spring-boot-autoconfigure SDN 6 provides configures A composable stack

Slide 14

Slide 14 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 • Imperative and reactive on par • New: Reactive transactions Reactive support

Slide 15

Slide 15 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 • Bolt protocol • Driver type system 100%-based on Neo4j Java Driver

Slide 16

Slide 16 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 18 @Autowired org.neo4j.driver.Driver @RestController public class MoviesController { private final Driver driver; public MoviesController(Driver driver) { this.driver = driver; } @GetMapping(path = "/movies", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux getMovieTitles() { /# Using an implicit, driver managed transaction return Flux.usingWhen( Mono.fromSupplier(driver:%rxSession), s -' Flux.from(s.run("MATCH (m:Movie) RETURN m ORDER BY m.name ASC").records()), RxSession:%close ).map(r -' r.get("m").asNode().get("title").asString()); } } Based on open standards: Reactive Streams. Can be used with RxJava2, too.

Slide 17

Slide 17 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 @Service public class MovieService { private final ReactiveNeo4jClient client; public MovieService(ReactiveNeo4jClient client) { this.client = client; } /# Fully integrated with Springs declarative /# or explicit transactions (via TransactionalOperator or TransactionTemplate) @Transactional public Flux getMovieTitles() { return client.query("MATCH (m:Movie) RETURN m ORDER BY m.name ASC") .fetchAs(String.class) .mappedBy((typeSystem, record) -' record.get("m").asNode().get("title").asString()) .all(); } } 19 @Autowired org.springframework.data.neo4j.core.ReactiveNeo4jClient

Slide 18

Slide 18 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 20 @Autowired org.springframework.data.neo4j.core.ReactiveNeo4jTemplate @Service public class MovieService { private final ReactiveNeo4jTemplate template; public MovieService(ReactiveNeo4jTemplate template) { this.template = template; } @Transactional public Flux getMovieTitles() { /# Overload with custom query available return template.findAll(MovieEntity.class) .map(MovieEntity:%getTitle); } } @Node("Movie") class MovieEntity { private @Id final String title; private @Property("tagline") final String description; @Relationship(type = "ACTED_IN", direction = INCOMING) private final Map actorsAndRoles; /# Full immutable class, works also with @Data, /# Kotlin and JDK 14 records public MovieEntity(String title, String description, Map actorsAndRoles ) { this.title = title; this.description = description; this.actorsAndRoles = actorsAndRoles; } }

Slide 19

Slide 19 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 public interface MovieRepository extends ReactiveNeo4jRepository {} @Service public class MovieService { private final MovieRepository repository; public MovieService(MovieRepository repository) { this.repository = repository; } @Transactional public Flux getMovieTitles() { /# Custom query via @Query on a method /# For simple cases, use derived query methods /# repository.findAllByOrderByTitle return repository.findAll() .map(MovieEntity:%getTitle); /# For the first time with Spring Data and Neo4j, query by Example /# return repository.findAll(Example.of(new MovieEntity("The Matrix", null))); } } 21 @Autowired org.springframework.data.neo4j.core.ReactiveNeo4jRepository

Slide 20

Slide 20 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 • Instances via • (persistent) constructor • wither • setter • No reflection violating the contract Immutable Mapping

Slide 21

Slide 21 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 • Neo4j Driver Java auto-config • Properties where they belong • Updated SDN starter • Getting you up to speed in a blink • Health Checks • Based on the Java Driver Spring Boot integration

Slide 22

Slide 22 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 @ConfigurationProperties(prefix = "spring.neo4j") public class Neo4jProperties { public static class Authentication { /** The login of the user connecting to the database.** private String username; /** The password of the user connecting to the database. ** private String password; /** The realm to connect to.** private String realm; } /** The uri this driver should connect to. The driver supports bolt or neo4j as schemes.** private URI uri; /** The authentication the driver is supposed to use. Maybe null. ** private Authentication authentication = new Authentication(); } 24 Access to all configuration settings Consistent across frameworks!

Slide 23

Slide 23 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 Less Surprises

Slide 24

Slide 24 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 Cypher DSL • Zero dependency library • Compile-time checked query construction • Re-usable instances

Slide 25

Slide 25 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 27 var tom = node("Person").named("tom").properties("name", literalOf("Tom Hanks")); var coActors = anyNode("coActors"); var cocoActors = anyNode("cocoActors"); var strength = count(asterisk()).as("Strength"); var statement = Cypher .match( tom.relationshipTo(anyNode("m"), "ACTED_IN").relationshipFrom(coActors, "ACTED_IN"), coActors.relationshipTo(anyNode("m2"), "ACTED_IN").relationshipFrom(cocoActors, "ACTED_IN") ) .where(not(tom.relationshipTo(anyNode(), "ACTED_IN").relationshipFrom(cocoActors, "ACTED_IN"))) .and(tom.isNotEqualTo(cocoActors)) .returning( cocoActors.property("name").as("Recommended"), strength ).orderBy(strength.asName().descending()) .build(); assertThat(cypherRenderer.render(statement)) .isEqualTo("" + "MATCH " + "(tom:`Person` {name: 'Tom Hanks'})-[:`ACTED_IN`]-$(m)%-[:`ACTED_IN`]-(coActors), " + "(coActors)-[:`ACTED_IN`]-$(m2)%-[:`ACTED_IN`]-(cocoActors) " + "WHERE (NOT (tom)-[:`ACTED_IN`]-$()%-[:`ACTED_IN`]-(cocoActors) AND tom <( cocoActors) " + "RETURN cocoActors.name AS Recommended, count(*) AS Strength ORDER BY Strength DESC");

Slide 26

Slide 26 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 28 Current status • Works with Neo4j 3.4+ • Reactive database access needs 4.0 • Multi-database feature needs Neo4j Enterprise Edition • Works with Neo4j Aura https://neo4j.com/aura/ • Provides Neo4j support in JHipster https://www.jhipster.tech

Slide 27

Slide 27 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 29 Current status • Original version released as SDN/RX in April 2020 • Used already by customers • Will replace SDN+Neo4j-OGM in Spring Boot 2.4 / Spring Data Release Train Ockham (2020.0.0) • SDN+Neo4j-OGM in Spring Boot 2.3 and before still supported and maintained • Good choice for new projects • More effort to migrate existing SDN+Neo4j-OGM code • Different packages • More opinionated behavior

Slide 28

Slide 28 text

Introducing SDN 6 at SpringOne 2020 by @meistermeier and @rotnroll666 30 Links • Announcement of SDN 6.0 https://bit.ly/welcome_sdn6 • Spring Data Neo4j https://spring.io/projects/spring-data-neo4j • Neo4j Cypher-DSL https://github.com/neo4j-contrib/cypher-dsl • Neo4j Downloads https://neo4j.org/downloads • Neo4j Aura https://neo4j.org/aura • Neo4j Community Site https://community.neo4j.com/

Slide 29

Slide 29 text

Thank you!