Extensibility for Java Developers in Neo4j

Extensibility for Java Developers in Neo4j

In this presentation, you will find out all the different ways you can extend Neo4j and easily integrate it with other popular technologies! From GraphQL to in-house applications to Spring Data, you can utilize your existing technology stack and plug it into Neo4j to maximize business value from your data as a graph of connected information.

10f2b035856eef2b59c02267e3ee9e63?s=128

Jennifer Reif

October 10, 2018
Tweet

Transcript

  1. Extensibility for Java Developers in Neo4j Jennifer Reif Neo4j @JMHReif

  2. Software Engineer, Neo4j - Developer - Blogger - Conference speaker

    - Continuous learner Hobbies: cats, coffee, and traveling :) jennifer.reif@neo4j.com @JMHReif Who Am I?
  3. What is a Graph Database?

  4. Chart Graph

  5. Database - specifically graph • Database: a structured set of

    data held in a computer, especially one that is accessible in various ways. • Relational? NoSQL? Graph? • Graph database: uses graph structures for semantic queries with nodes, edges and properties to represent and store data.
  6. Neo4j is a Graph Database

  7. Neo4j Fast Reliable No size limit Binary & HTTP protocol

    ACID transactions 2-4 M
 ops/s per core Clustering scale & HA Official Drivers Neo4j is a database
  8. Neo4j Native GraphDB Cypher Query Language Developer Workbench Extensible Procedures

    & Functions Schema Free Property Graph Model Graph Visualization Graph Storage Neo4j is a graph database
  9. Neo4j Developer Surface Native LanguageDrivers BOLT User- Defined Procedure 2000-2010

    0.x Embedded Java API 2010-2014 1.x REST 2014-2015 2.x Cypher over HTTP 2016 3.0.x Bolt, Official Language Drivers, User-Defined Procedures 2016 3.1.x User-Defined Functions 2017 3.2.x User-Defined Aggregation Functions
  10. Neo4j Developer Surface Native LanguageDrivers BOLT User- Defined Procedure 2000-2010

    0.x Embedded Java API 2010-2014 1.x REST 2014-2015 2.x Cypher over HTTP 2016 3.0.x Bolt, Official Language Drivers, User Defined Procedures 2016 3.1.x User Defined Functions 2017 3.2.x User Defined Aggregation Functions
  11. Interfaces to Neo4j • BOLT: • binary protocol / Cypher-only

    pipe • type system similar to Cypher • official drivers • HTTP: • familiar protocol • JSON (lossy) • community drivers / standard HTTP tooling • Embedded: • Java-only • core API • in-process
  12. Bolt Binary Protocol • High-performance protocol • Secure transport (auth/TLS)

    • Shared connections (pooling) • More inclusive data type system • Procedure functionality
  13. Neo4j Bolt Drivers

  14. Official Drivers

  15. Java Driver import org.neo4j.driver.v1.*; Driver driver = GraphDatabase.driver( "bolt://localhost", AuthTokens.basic(

    "neo4j", "neo4j" ) ); Session session = driver.session(); session.run( "CREATE (a:Person {name:'Arthur', title:'King'})" ); StatementResult result = session.run( "MATCH (a:Person) WHERE a.name = 'Arthur' RETURN a.name AS name, a.title AS title" ); while ( result.hasNext() ) { Record record = result.next(); System.out.println( record.get( "title" ).asString() + " " + record.get("name").asString() ); } session.close(); driver.close(); github.com/neo4j/neo4j-java-driver / org.neo4j.driver:neo4j-java-driver:1.5.0
  16. Javascript Driver var neo4j = require('neo4j-driver').v1; var driver = neo4j.driver("bolt://localhost",

    neo4j.auth.basic("neo4j", "neo4j")); var session = driver.session(); session .run( "CREATE (a:Person {name:'Arthur', title:'King'})" ) .then( function() { return session.run( "MATCH (a:Person) WHERE a.name = 'Arthur' RETURN a.name AS name, a.title AS title" ) }) .then( function( result ) { console.log( result.records[0].get("title") + " " + result.records[0].get("name") ); session.close(); driver.close(); }) github.com/neo4j/neo4j-javascript-driver / npm install neo4j-driver
  17. Python Driver from neo4j.v1 import GraphDatabase, basic_auth driver = GraphDatabase.driver("bolt://localhost",

    auth=basic_auth("neo4j", "neo4j")) session = driver.session() session.run("CREATE (a:Person {name:'Arthur', title:'King'})") query = "MATCH (a:Person) WHERE a.name = 'Arthur' RETURN a.name AS name, a.title AS title" result = session.run(query) for record in result: print("%s %s" % (record["title"], record["name"])) session.close() github.com/neo4j/neo4j-python-driver / pip install neo4j-driver
  18. .NET Driver using Neo4j.Driver.V1; using (var driver = GraphDatabase.Driver("bolt://localhost", AuthTokens.Basic("neo4j",

    "neo4j"))) using (var session = driver.Session()) { session.Run("CREATE (a:Person {name:'Arthur', title:'King'})"); var result = session.Run("MATCH (a:Person) WHERE a.name = 'Arthur' RETURN a.name AS name, a.title AS title"); foreach (var record in result) { Output.WriteLine($"{record["title"].As<string>()} {record["name"].As<string>()}"); } } github.com/neo4j/neo4j-dotnet-driver / PM> Install-Package Neo4j.Driver-1.0.3
  19. Community Drivers

  20. Spring Data Neo4j & Object-Graph Mapper

  21. https://projects.spring.io/spring-data-neo4j/

  22. https://github.com/spring-projects/spring-data-neo4j

  23. Capabilities • Can use with SpringBoot • Annotation-based OGM for

    POJOs • Connect to Neo4j with Bolt, HTTP, and embedded • Interface-based repository support • Persistence lifecycle events
  24. @NodeEntity public class Person { @Id @GeneratedValue private Long id;

    private String name; private int born; @Relationship(type = "ACTED_IN") private List<Movie> movies = new ArrayList<>(); } @NodeEntity public class Movie { … @JsonIgnoreProperties("movie") @Relationship(type = "ACTED_IN", direction = Relationship.INCOMING) private List<Role> roles; } @RelationshipEntity(type = "ACTED_IN") public class Role { @Id @GeneratedValue private Long id; private List<String> roles = new ArrayList<>(); @StartNode private Person person; @EndNode private Movie movie; }
  25. public interface MovieRepository extends Neo4jRepository<Movie, Long> { //derived finder methods

    - auto-mapping Movie findByTitle(@Param("title") String title); Collection<Movie> findByTitleLike(@Param("title") String title); @Query("MATCH (m:Movie)<-[r:ACTED_IN]-(a:Person) RETURN m,r,a LIMIT {limit}") Collection<Movie> graph(@Param("limit") int limit); }
  26. @Service public class MovieService { private final MovieRepository movieRepository; public

    MovieService(MovieRepository movieRepository) { this.movieRepository = movieRepository; } @Transactional(readOnly = true) public Movie findByTitle(String title) { return movieRepository.findByTitle(title); } @Transactional(readOnly = true) public Collection<Movie> findByTitleLike(String title) { return movieRepository.findByTitleLike(title); } @Transactional(readOnly = true) public Map<String, Object> graph(int limit) { Collection<Movie> result = movieRepository.graph(limit); return toD3Format(result); } } https://neo4j.com/developer/spring-data-neo4j/
  27. Neo4j Developer Surface Native LanguageDrivers BOLT User- Defined Procedure 2000-2010

    0.x Embedded Java API 2010-2014 1.x REST 2014-2015 2.x Cypher over HTTP 2016 3.0.x Bolt, Official Language Drivers, User-Defined Procedures 2016 3.1.x User-Defined Functions 2017 3.2.x User-Defined Aggregation Functions
  28. Procedures Functions Aggregate Functions

  29. Can be written in any JVM language

  30. User-Defined Procedures

  31. Callable as Stand-Alone or in Cypher Statements

  32. CALL example.search('User','name:Brook*')

  33. public class FullTextIndex { @Context public GraphDatabaseService db; @Procedure( name

    = "example.search", mode = Procedure.Mode.READ ) public Stream<SearchHit> search( @Name("index") String index, 
 @Name("query") String query ) { if( !db.index().existsForNodes( index )) { return Stream.empty(); } return db.index().forNodes( index ).query( query ).stream()
 .map( SearchHit::new ); } public static class SearchHit { public final Node node; SearchHit(Node node) { this.node = node; } } }
  34. public class FullTextIndex { @Context public GraphDatabaseService db; @Procedure( name

    = "example.search", mode = Procedure.Mode.READ ) public Stream<SearchHit> search( @Name("index") String index, 
 @Name("query") String query ) { if( !db.index().existsForNodes( index )) { return Stream.empty(); } return db.index().forNodes( index ).query( query ).stream()
 .map( SearchHit::new ); } public static class SearchHit { public final Node node; SearchHit(Node node) { this.node = node; } } }
  35. public class FullTextIndex { @Context public GraphDatabaseService db; @Procedure( name

    = "example.search", mode = Procedure.Mode.READ ) public Stream<SearchHit> search( @Name("index") String index, 
 @Name("query") String query ) { if( !db.index().existsForNodes( index )) { return Stream.empty(); } return db.index().forNodes( index ).query( query ).stream()
 .map( SearchHit::new ); } public static class SearchHit { public final Node node; SearchHit(Node node) { this.node = node; } } }
  36. try ( Driver driver = GraphDatabase.driver("bolt://localhost", Config.build().toConfig()) ) { try

    ( Session session = driver.session() ) { String call = "CALL example.search('User',$query)"; Map<String,Object> params = singletonMap("query", "name:Brook*"); StatementResult result = session.run(call, params); while ( result.hasNext() ) { // process results } } }
  37. try ( Driver driver = GraphDatabase.driver("bolt://localhost", Config.build().toConfig()) ) { try

    ( Session session = driver.session() ) { String call = "CALL example.search('User',$query)"; Map<String,Object> params = singletonMap("query", "name:Brook*"); StatementResult result = session.run(call, params); while ( result.hasNext() ) { // process results } } }
  38. User-Defined Functions

  39. Useable in any Cypher expression or lightweight computation

  40. RETURN example.join(['Hello','World'],' ') => "Hello World"

  41. public class Join { @UserFunction @Description("example.join(['s1','s2',...], delimiter) - join the

    given strings with the given delimiter.") public String join( @Name(“strings") List<String> strings, @Name(value = "delimiter", defaultValue = ",") String delimiter) { if ( strings == null || delimiter == null ) { return null; } return String.join( delimiter, strings ); } }
  42. public class Join { @UserFunction @Description("example.join(['s1','s2',...], delimiter) - join the

    given strings with the given delimiter.") public String join( @Name("strings") List<String> strings, @Name(value = "delimiter", defaultValue = ",") String delimiter) { if ( strings == null || delimiter == null ) { return null; } return String.join( delimiter, strings ); } }
  43. public class Join { @UserFunction @Description("example.join(['s1','s2',...], delimiter) - join the

    given strings with the given delimiter.") public String join( @Name("strings") List<String> strings, @Name(value = "delimiter", defaultValue = ",") String delimiter) { if ( strings == null || delimiter == null ) { return null; } return String.join( delimiter, strings ); } }
  44. try ( Driver driver = GraphDatabase.driver( "bolt://localhost", 
 Config.build().toConfig() )

    ) { try ( Session session = driver.session() ) { String query = "RETURN example.join(['Hello','World']) AS result"; String result = session.run( query ) .single().get( "result" ).asString(); } }
  45. User-Defined Aggregation Functions

  46. Custom, efficient aggregations for Data Science and BI

  47. UNWIND ['abc', 'abcd', 'ab'] AS string
 RETURN example.longestString(string) => 'abcd'

  48. public class LongestString { @UserAggregationFunction @Description( "aggregates the longest string

    found" ) public LongStringAggregator longestString() { return new LongStringAggregator(); } public static class LongStringAggregator { private int longest; private String longestString; @UserAggregationUpdate public void findLongest( @Name( "string" ) String string ) { if ( string != null && string.length() > longest) { longest = string.length(); longestString = string; } } @UserAggregationResult public String result() { return longestString; } } }
  49. public class LongestString { @UserAggregationFunction @Description( "aggregates the longest string

    found" ) public LongStringAggregator longestString() { return new LongStringAggregator(); } public static class LongStringAggregator { private int longest; private String longestString; @UserAggregationUpdate public void findLongest( @Name( "string" ) String string ) { if ( string != null && string.length() > longest) { longest = string.length(); longestString = string; } } @UserAggregationResult public String result() { return longestString; } } }
  50. public class LongestString { @UserAggregationFunction @Description( "aggregates the longest string

    found" ) public LongStringAggregator longestString() { return new LongStringAggregator(); } public static class LongStringAggregator { private int longest; private String longestString; @UserAggregationUpdate public void findLongest( @Name( "string" ) String string ) { if ( string != null && string.length() > longest) { longest = string.length(); longestString = string; } } @UserAggregationResult public String result() { return longestString; } } }
  51. public class LongestString { @UserAggregationFunction @Description( "aggregates the longest string

    found" ) public LongStringAggregator longestString() { return new LongStringAggregator(); } public static class LongStringAggregator { private int longest; private String longestString; @UserAggregationUpdate public void findLongest( @Name( "string" ) String string ) { if ( string != null && string.length() > longest) { longest = string.length(); longestString = string; } } @UserAggregationResult public String result() { return longestString; } } }
  52. try ( Driver driver = GraphDatabase.driver("bolt://localhost", 
 Config.build().toConfig()) ) {

    try ( Session session = driver.session() ) { String query = "UNWIND ['abc', 'abcd', 'ab'] AS string " + "RETURN example.longestString(string) AS result"; String result = session.run(query).single().get("result").asString(); } }
  53. None
  54. None
  55. Awesome Procedures On Cypher

  56. None
  57. 450+ procedures and functions

  58. None
  59. APOC - Data Integration

  60. Load from a relational database

  61. apoc.load.jdbc WITH "jdbc:mysql://localhost:3306/northwind?user=root" AS url CALL apoc.load.jdbc(url,"products") 
 YIELD row

    MERGE (p:Product {id: row.ProductID}) SET p.name = row.ProductName, p.unitPrice = row.UnitPrice
  62. WITH "jdbc:mysql://localhost:3306/northwind?user=root" AS url CALL apoc.load.jdbc(url,"products") 
 YIELD row MERGE

    (p:Product {id: row.ProductID}) SET p.name = row.ProductName, p.unitPrice = row.UnitPrice Execute procedure
  63. Apply Cypher transformation WITH "jdbc:mysql://localhost:3306/northwind?user=root" AS url CALL apoc.load.jdbc(url,"products") 


    YIELD row MERGE (p:Product {id: row.ProductID}) SET p.name = row.ProductName, p.unitPrice = row.UnitPrice
  64. Load XML

  65. apoc.load.xml CALL apoc.load.xml('http://overpass.osm.rambler.ru/cgi/xapi_meta *[bbox=11.54,48.14,11.543,48.145]') YIELD value UNWIND value["_children"] AS child

    WITH child WHERE child["_type"] = "node" WITH child.id AS id, 
 child.lat AS latitude, 
 child.lon AS longitude, 
 child["user"] AS userName MERGE (point:Point {id: id}) SET point.latitude = latitude, 
 point.longitude = longitude MERGE (user:User {name: userName}) MERGE (user)-[:EDITED]->(point)
  66. Execute procedure CALL apoc.load.xml('http://overpass.osm.rambler.ru/cgi/xapi_meta? *[bbox=11.54,48.14,11.543,48.145]') YIELD value UNWIND value["_children"] AS

    child WITH child WHERE child["_type"] = "node" WITH child.id AS id, 
 child.lat AS latitude, 
 child.lon AS longitude, 
 child["user"] AS userName MERGE (point:Point {id: id}) SET point.latitude = latitude, 
 point.longitude = longitude MERGE (user:User {name: userName}) MERGE (user)-[:EDITED]->(point)
  67. UNWIND the array of elements CALL apoc.load.xml('http://overpass.osm.rambler.ru/cgi/xapi_meta? *[bbox=11.54,48.14,11.543,48.145]') YIELD value

    UNWIND value["_children"] AS child WITH child WHERE child["_type"] = "node" WITH child.id AS id, 
 child.lat AS latitude, 
 child.lon AS longitude, 
 child["user"] AS userName MERGE (point:Point {id: id}) SET point.latitude = latitude, 
 point.longitude = longitude MERGE (user:User {name: userName}) MERGE (user)-[:EDITED]->(point)
  68. Filter rows CALL apoc.load.xml('http://overpass.osm.rambler.ru/cgi/xapi_meta? *[bbox=11.54,48.14,11.543,48.145]') YIELD value UNWIND value["_children"] AS

    child WITH child WHERE child["_type"] = "node" WITH child.id AS id, 
 child.lat AS latitude, 
 child.lon AS longitude, 
 child["user"] AS userName MERGE (point:Point {id: id}) SET point.latitude = latitude, 
 point.longitude = longitude MERGE (user:User {name: userName}) MERGE (user)-[:EDITED]->(point)
  69. Apply Cypher transformation CALL apoc.load.xml('http://overpass.osm.rambler.ru/cgi/xapi_meta? *[bbox=11.54,48.14,11.543,48.145]') YIELD value UNWIND value["_children"]

    AS child WITH child WHERE child["_type"] = "node" WITH child.id AS id, 
 child.lat AS latitude, 
 child.lon AS longitude, 
 child["user"] AS userName MERGE (point:Point {id: id}) SET point.latitude = latitude, 
 point.longitude = longitude MERGE (user:User {name: userName}) MERGE (user)-[:EDITED]->(point)
  70. Load JSON

  71. apoc.load.json WITH "https://api.stackexchange.com/2.2/questions? pagesize=100&order=desc&sort=creation&tagged=neo4j&site=stackoverflow&filter=!5-i6Zw8Y)4W7vpy91PMYsKM- k9yzEsSC1_Uxlf" AS url CALL apoc.load.json(url) YIELD

    value UNWIND value.items AS q MERGE (question:Question {id:q.question_id}) 
 ON CREATE SET question.title = q.title, 
 question.share_link = q.share_link, 
 question.favorite_count = q.favorite_count MERGE (owner:User {id:q.owner.user_id}) 
 ON CREATE SET owner.display_name = q.owner.display_name
 MERGE (owner)-[:ASKED]->(question) FOREACH (tagName IN q.tags | 
 MERGE (tag:Tag {name:tagName}) MERGE (question)-[:TAGGED]->(tag))
 FOREACH (a IN q.answers | MERGE (question)<-[:ANSWERS]-(answer:Answer {id:a.answer_id}) MERGE (answerer:User {id:a.owner.user_id}) 
 ON CREATE SET answerer.display_name = a.owner.display_name 
 MERGE (answer)<-[:PROVIDED]-(answerer))
  72. WITH "https://api.stackexchange.com/2.2/questions?pagesize=100&order=desc&sort=creation&tagged=neo4j&site=stackoverflow&filter=!5- i6Zw8Y)4W7vpy91PMYsKM-k9yzEsSC1_Uxlf" AS url CALL apoc.load.json(url) YIELD value UNWIND

    value.items AS q MERGE (question:Question {id:q.question_id}) 
 ON CREATE SET question.title = q.title, 
 question.share_link = q.share_link, 
 question.favorite_count = q.favorite_count MERGE (owner:User {id:q.owner.user_id}) 
 ON CREATE SET owner.display_name = q.owner.display_name
 MERGE (owner)-[:ASKED]->(question) FOREACH (tagName IN q.tags | 
 MERGE (tag:Tag {name:tagName}) MERGE (question)-[:TAGGED]->(tag))
 FOREACH (a IN q.answers | MERGE (question)<-[:ANSWERS]-(answer:Answer {id:a.answer_id}) MERGE (answerer:User {id:a.owner.user_id}) 
 ON CREATE SET answerer.display_name = a.owner.display_name 
 MERGE (answer)<-[:PROVIDED]-(answerer)) Use FOREACH for arrays within a row
  73. APOC - Graph Refactoring

  74. apoc.refactor.mergeNodes MATCH (n:Person) WITH n.email AS email, collect(n) as people

    WHERE size(people) > 1 CALL apoc.refactor.mergeNodes(people) YIELD node RETURN node
  75. apoc.refactor.mergeNodes MATCH (n:Person) WITH n.email AS email, collect(n) as people

    WHERE size(people) > 1 CALL apoc.refactor.mergeNodes(people) YIELD node RETURN node
  76. apoc.create.addLabels MATCH (n:Movie) CALL apoc.create.addLabels(id(n), [n.genre]) YIELD node REMOVE node.genre

    RETURN node
  77. apoc.create.addLabels MATCH (n:Movie) CALL apoc.create.addLabels( id(n), [ n.genre ] )

    YIELD node REMOVE node.genre RETURN node
  78. APOC - Cypher Execution

  79. Run large scale updates CALL apoc.periodic.iterate( 'MATCH (n:Person) RETURN n',

    'SET n.name = n.firstName + " " + n.lastName',
 {batchSize:10000, parallel:true})
  80. APOC - Utility Functions

  81. Compute soundex encoding of a string CALL apoc.text.phonetic('Hello, dear User!')

    YIELD value RETURN value 
 // will return 'H436'
  82. How similar do two strings sound? CALL apoc.text.phoneticDelta(
 'Hello Mr

    Rabbit', 'Hello Mr Ribbit') 
 // will return '4' (very similar)
  83. Extract domain names WITH 'http://www.example.com/all-the-things' AS url RETURN apoc.data.domain(url) //

    will return 'www.example.com'
  84. Date to Timestamp RETURN apoc.date.parse(
 '2015/03/25 03:15:59',
 's', 
 'yyyy/MM/dd

    HH:mm:ss'
 )
 
 // will return 1427253359
  85. Timestamp to Date RETURN apoc.date.format(
 1427253359, 
 's', 
 'yyyy/MM/dd

    HH:mm:ss'
 ) 
 // will return "2015/03/25 03:15:59"
  86. And many more! https://neo4j-contrib.github.io/neo4j-apoc-procedures/

  87. Kafka and Neo4j

  88. None
  89. Functionality • Still in development! • Stream transaction event handler

    events to a Kafka topic • Read Kafka records from given topic(s) • Treat records as input parameters • Uses configured Cypher statements to merge into the graph
  90. What Do I Need? • Configuration properties • Set up

    node-patterns to send to Kafka • Choose Labels and properties to include/exclude • Patterns separated by semicolon
  91. neo4j.conf kafka.zookeeper.connect=localhost:2181 kafka.bootstrap.servers=localhost:9092 kafka.acks=1 kafka.num.partitions=1 kafka.retries=2 kafka.batch.size=16384 kafka.buffer.memory=33554432 kafka.reindex.batch.size=1000 kafka.session.timeout.ms=15000

    kafka.connection.timeout.ms=10000 kafka.replication=1 kafka.group.id=neo4j kafka.topics=neo4j kafka.patterns=neo4j:*
  92. Label & Property Setup kafka.topics=topic1,topic2 kafka.patterns=topic1:*;topic2:Label1 {prop1, prop2}, topic1:Label1:Label2{*,-prop1}, topic2:Label3{-prop1,-prop2,prop3}

  93. RDF data into Neo4j

  94. None
  95. None
  96. Import RDF triples

  97. semantics.importRDF CALL semantics.importRDF("file:///industry.ntriples","N-Triples", {})

  98. Thomson Reuters' OpenPermID Graph

  99. Graph-Aided Search

  100. None
  101. None
  102. None
  103. conf/neo4j.conf com.graphaware.runtime.enabled=true
 
 #ES becomes the module ID:
 com.graphaware.module.ES. 2=com.graphaware.module.es.ElasticSearchModuleBootstrapper


    
 #URI of Elasticsearch
 com.graphaware.module.ES.uri=localhost
 
 #Port of Elasticsearch
 com.graphaware.module.ES.port=9201
  104. Find nodes CALL ga.es.queryNode(‘{\"query\": {\"match\":{\"name\":=\"alessandro\"}}}') YIELD node, score RETURN node,

    score
  105. Find relationships CALL ga.es.queryRelationship(‘{\"query\": {\"match\":{\"city\":\"paris\"}}}') YIELD relationship, score RETURN relationship,

    score
  106. dzone.com/refcardz/graph-powered-search-neo4j-amp-elasticsearch

  107. Versioned Graphs

  108. None
  109. None
  110. Create node CALL graph.versioner.init('Person', 
 {ssn: 123456789, name: 'Marco'}, 


    {address: 'Via Roma 11'}
 )
  111. Immutable properties CALL graph.versioner.init('Person', 
 {ssn: 123456789, name: 'Marco'}, 


    {address: 'Via Roma 11'}
 )
  112. State properties CALL graph.versioner.init('Person', 
 {ssn: 123456789, name: 'Marco'}, 


    {address: 'Via Roma 11'}
 )
  113. Update state MATCH (p:Person {name: "Marco"}) WITH p CALL graph.versioner.update(p,

    {address: 'Via Roma 12'}) YIELD node RETURN node
  114. Pass in the new state MATCH (p:Person {name: "Marco"}) WITH

    p CALL graph.versioner.update(p, {address: 'Via Roma 12'}) YIELD node RETURN node
  115. Spatial

  116. None
  117. Create spatial index CALL spatial.addWKTLayer('geom', 'wkt')

  118. Add spatial property to nodes CREATE (d:District {...}) SET d.wkt

    = 'MULTIPOLYGON(((23.22, ... )))'
  119. Add nodes to spatial index MATCH (d:District) WITH collect(d) AS

    districts CALL spatial.addNodes('geom', districts) YIELD node RETURN count(*)
  120. Query nodes by location CALL spatial.withinDistance('geom',
 {latitude: 37.563440, longitude: -122.322265},

    1) 
 YIELD node AS d WITH d, d.wkt AS wkt, d.state AS state, d.district AS district LIMIT 1 MATCH (d)<-[:REPRESENTS]-(l:Legislator) MATCH (l)-[:SERVES_ON]->(c:Committee) MATCH (c)<-[:REFERRED_TO]-(b:Bill) MATCH (b)-[:DEALS_WITH]->(s:Subject) RETURN *
  121. Finds nodes within 1km CALL spatial.withinDistance('geom',
 {latitude: 37.563440, longitude: -122.322265},

    1) 
 YIELD node AS d WITH d, d.wkt AS wkt, d.state AS state, d.district AS district LIMIT 1 MATCH (d)<-[:REPRESENTS]-(l:Legislator) MATCH (l)-[:SERVES_ON]->(c:Committee) MATCH (c)<-[:REFERRED_TO]-(b:Bill) MATCH (b)-[:DEALS_WITH]->(s:Subject) RETURN *
  122. Continue with the rest of the query CALL spatial.withinDistance('geom',
 {latitude:

    37.563440, longitude: -122.322265}, 1) 
 YIELD node AS d WITH d, d.wkt AS wkt, d.state AS state, d.district AS district LIMIT 1 MATCH (d)<-[:REPRESENTS]-(l:Legislator) MATCH (l)-[:SERVES_ON]->(c:Committee) MATCH (c)<-[:REFERRED_TO]-(b:Bill) MATCH (b)-[:DEALS_WITH]->(s:Subject) RETURN *
  123. lyonwj.com/2016/08/09/neo4j-spatial-procedures- congressional-boundaries/

  124. Graph-based Machine Learning

  125. None
  126. None
  127. Annotating text CREATE (n:News) SET n.text = "Scores of people

    were already lying dead or injured inside a crowded Orlando nightclub, and the police had spent hours trying to connect with the gunman and end the situation without further violence. But when Omar Mateen threatened to set off explosives, the police decided to act, and pushed their way through a wall to end the bloody standoff."
  128. Annotating text MATCH (n:News) CALL ga.nlp.annotate({text: n.text, id: id(n)}) YIELD

    result MERGE (n)-[:HAS_ANNOTATED_TEXT]->(result) RETURN result
  129. Execute procedure MATCH (n:News) CALL ga.nlp.annotate({text: n.text, id: id(n)}) YIELD

    result MERGE (n)-[:HAS_ANNOTATED_TEXT]->(result) RETURN result
  130. Relate to text node MATCH (n:News) CALL ga.nlp.annotate({text: n.text, id:

    id(n)}) YIELD result MERGE (n)-[:HAS_ANNOTATED_TEXT]->(result) RETURN result
  131. None
  132. Graph Algorithms

  133. None
  134. Insights from Algorithms

  135. Graph

  136. Graph of Thrones

  137. • Single Source Short Path • All Pairs SSP •

    Parallel BFS / DFS • Minimum Weight Spanning Tree • Shortest Path • A* • Yen’s K-shortest paths • Random Walk • Strongly-Connected Components • Union Find / WCC • Label Propagation • Louvain • Triangle-Count / Clustering Coefficent • PageRank (baseline) • Betweeness • Closeness • Degree • Harmonic (new!) https://neo4j.com/docs/graph-algorithms/current/
  138. Usage 1.Call as Cypher procedure 2.Pass in specification (Label, Prop,

    Query) and configuration 3.Execute and return results A. ~.stream variant returns (a lot) of results CALL algo.<name>.stream('Label','TYPE', {conf}) YIELD nodeId, score B. non-stream variant writes results to graph and returns statistics
 CALL algo.<name>('Label','TYPE', {conf})
  139. Cypher Projection Pass in Cypher statement for node and relationship

    lists. 
 CALL algo.<name>( 'MATCH ... RETURN id(n)', 'MATCH (n)-->(m) RETURN id(n) as source, id(m) as target', 
 {graph:'cypher'})
  140. Graph Algorithms Sandbox neo4j.com/sandbox

  141. Graph ML Models

  142. None
  143. What’s In It? • Linear regression (Lauren Shin) • Multiple

    linear regression (Lauren Shin) • DeepGL/DeepWalk (Mark Needham) • …more coming soon!
  144. https://towardsdatascience.com/graphs-and-linear-regression-734d1446e9cd

  145. Graph Visualization

  146. None
  147. None
  148. None
  149. var viz; function draw() { var config = { container_id:

    "viz", server_url: "bolt://localhost:7687", server_user: "neo4j", server_password: "sorts-swims-burglaries", labels: { "Character": { "caption": "name", "size": "pagerank", "community": "community" } }, relationships: { "INTERACTS": { "thickness": "weight", "caption": false } }, initial_cypher: "MATCH (n)-[r:INTERACTS]->(m) RETURN *" }; viz = new NeoVis.default(config); viz.render(); }
  150. var viz; function draw() { var config = { container_id:

    "viz", server_url: "bolt://localhost:7687", server_user: "neo4j", server_password: "sorts-swims-burglaries", labels: { "Character": { "caption": "name", "size": "pagerank", "community": "community" } }, relationships: { "INTERACTS": { "thickness": "weight", "caption": false } }, initial_cypher: "MATCH (n)-[r:INTERACTS]->(m) RETURN *" }; viz = new NeoVis.default(config); viz.render(); }
  151. var viz; function draw() { var config = { container_id:

    "viz", server_url: "bolt://localhost:7687", server_user: "neo4j", server_password: "sorts-swims-burglaries", labels: { "Character": { "caption": "name", "size": "pagerank", "community": "community" } }, relationships: { "INTERACTS": { "thickness": "weight", "caption": false } }, initial_cypher: "MATCH (n)-[r:INTERACTS]->(m) RETURN *" }; viz = new NeoVis.default(config); viz.render(); }
  152. GraphQL

  153. What is it? GraphQL is a query language for your

    API, and a server-side runtime for executing queries by using a type system you define for your data.
  154. What is it? GraphQL is a query language for your

    API, and a server- side runtime for executing queries by using a type system you define for your data.
  155. What is it? GraphQL is a query language for your

    API, and a server-side runtime for executing queries by using a type system you define for your data.
  156. What is it? GraphQL is a query language for your

    API, and a server-side runtime for executing queries by using a type system you define for your data. type Planet {
 name: String
 climate: String
 } type Character {
 name: String
 friends: [Character]
 homeWorld: Planet
 species: Species
 } type Species {
 name: String
 lifespan: Int
 origin: Planet
 }
  157. Manual mapping code

  158. None
  159. Auto translating GraphQL → Cypher github.com/neo4j-graphql/neo4j-graphql github.com/neo4j-graphql/neo4j-graphql-js

  160. Server-side Java extension

  161. None
  162. conf/neo4j.conf dbms.unmanaged_extension_classes=org.neo4j.graphql=/graphql
 dbms.security.procedures.whitelist=graphql.*

  163. CALL graphql.idl('
 type Movie { title: String! released: Int actors:

    [Person] @relation(name:"ACTED_IN",direction:IN) } type Person { name: String! born: Int movies: [Movie] @relation(name:"ACTED_IN") }' )
  164. WITH '{ Person(born: 1961) { name, born } }' as

    query, {} as params CALL graphql.execute(query,params) 
 YIELD result UNWIND result.Person as p RETURN p.name, p.born
  165. Javascript extension

  166. None
  167. import {neo4jgraphql} from 'neo4j-graphql-js'; const resolvers = { Query: {

    Movie(object, params, ctx, resolveInfo) { return neo4jgraphql(object, params, ctx, resolveInfo); } } };
  168. The GRAND stack

  169. The GRAND stack GraphQL
 React
 Apollo
 Neo4j Database

  170. dzone.com/refcardz/an-overview-of-graphql

  171. How do I find out about more cool stuff???

  172. This Week in Neo4j - Developer Update neo4j.com/tag/twin4j

  173. Neo4j Community Site!

  174. (you)-[:HAVE]->(questions)<-[:ANSWERS]-(jennifer) @JMHReif jennifer.reif@neo4j.com

  175. How many did we cover? • Bolt drivers: https://neo4j.com/developer/language-guides/ •

    User-defined procs/funcs: https://neo4j.com/developer/procedures-functions/ • APOC: https://github.com/neo4j-contrib/neo4j-apoc-procedures • Neo4j/Kafka: https://github.com/neo4j-contrib/neo4j-streams • Neo4j/RDF: https://github.com/jbarrasa/neosemantics • Neo4j/Elasticsearch: https://github.com/graphaware/neo4j-to-elasticsearch • Versioned graphs: https://github.com/h-omer/neo4j-versioner-core • Spatial: https://github.com/neo4j-contrib/spatial • NLP: https://github.com/graphaware/neo4j-nlp • Graph Algorithms: https://github.com/neo4j-contrib/neo4j-graph-algorithms • ML models: https://github.com/neo4j-graph-analytics/ml-models • Graph Visualization: https://github.com/neo4j-contrib/neovis.js • GraphQL/GRANDstack: https://github.com/neo4j-graphql