Share
Embed
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.
Jennifer Reif
October 10, 2018
Transcript
175 slides
-
Software Engineer, Neo4j - Developer - Blogger - Conference speaker
- Continuous learner Hobbies: cats, coffee, and traveling :) [email protected] @JMHReif Who Am I? -
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. -
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 -
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 -
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 -
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 -
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 -
Bolt Binary Protocol • High-performance protocol • Secure transport (auth/TLS)
• Shared connections (pooling) • More inclusive data type system • Procedure functionality -
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 -
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 -
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 -
.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 -
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 -
@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; } -
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); } -
@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/ -
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 -
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; } } } -
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; } } } -
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; } } } -
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 } } } -
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 } } } -
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 ); } } -
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 ); } } -
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 ); } } -
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(); } } -
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; } } } -
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; } } } -
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; } } } -
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; } } } -
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(); } } -
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 -
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 -
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 -
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) -
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) -
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) -
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) -
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) -
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)) -
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 -
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 -
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 -
apoc.create.addLabels MATCH (n:Movie) CALL apoc.create.addLabels( id(n), [ n.genre ] )
YIELD node REMOVE node.genre RETURN node -
Run large scale updates CALL apoc.periodic.iterate( 'MATCH (n:Person) RETURN n',
'SET n.name = n.firstName + " " + n.lastName', {batchSize:10000, parallel:true}) -
Compute soundex encoding of a string CALL apoc.text.phonetic('Hello, dear User!')
YIELD value RETURN value // will return 'H436' -
How similar do two strings sound? CALL apoc.text.phoneticDelta( 'Hello Mr
Rabbit', 'Hello Mr Ribbit') // will return '4' (very similar) -
Extract domain names WITH 'http://www.example.com/all-the-things' AS url RETURN apoc.data.domain(url) //
will return 'www.example.com' -
Date to Timestamp RETURN apoc.date.parse( '2015/03/25 03:15:59', 's', 'yyyy/MM/dd
HH:mm:ss' ) // will return 1427253359 -
Timestamp to Date RETURN apoc.date.format( 1427253359, 's', 'yyyy/MM/dd
HH:mm:ss' ) // will return "2015/03/25 03:15:59" -
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 -
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 -
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:* -
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 -
Create node CALL graph.versioner.init('Person', {ssn: 123456789, name: 'Marco'},
{address: 'Via Roma 11'} ) -
Immutable properties CALL graph.versioner.init('Person', {ssn: 123456789, name: 'Marco'},
{address: 'Via Roma 11'} ) -
State properties CALL graph.versioner.init('Person', {ssn: 123456789, name: 'Marco'},
{address: 'Via Roma 11'} ) -
Update state MATCH (p:Person {name: "Marco"}) WITH p CALL graph.versioner.update(p,
{address: 'Via Roma 12'}) YIELD node RETURN node -
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 -
Add spatial property to nodes CREATE (d:District {...}) SET d.wkt
= 'MULTIPOLYGON(((23.22, ... )))' -
Add nodes to spatial index MATCH (d:District) WITH collect(d) AS
districts CALL spatial.addNodes('geom', districts) YIELD node RETURN count(*) -
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 * -
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 * -
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 * -
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." -
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 -
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 -
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 -
• 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/ -
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}) -
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'}) -
What’s In It? • Linear regression (Lauren Shin) • Multiple
linear regression (Lauren Shin) • DeepGL/DeepWalk (Mark Needham) • …more coming soon! -
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(); } -
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(); } -
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(); } -
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. -
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. -
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. -
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 } -
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") }' ) -
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 -
import {neo4jgraphql} from 'neo4j-graphql-js'; const resolvers = { Query: {
Movie(object, params, ctx, resolveInfo) { return neo4jgraphql(object, params, ctx, resolveInfo); } } }; -
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