Diese Präsentation wurde erfolgreich gemeldet.
Die SlideShare-Präsentation wird heruntergeladen. ×

GraphTour - Utilizing Powerful Extensions for Analytics & Operations

Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige

Hier ansehen

1 von 164 Anzeige

Weitere Verwandte Inhalte

Diashows für Sie (20)

Ähnlich wie GraphTour - Utilizing Powerful Extensions for Analytics & Operations (20)

Anzeige

Weitere von Neo4j (20)

Aktuellste (20)

Anzeige

GraphTour - Utilizing Powerful Extensions for Analytics & Operations

  1. 1. Utilizing Powerful Extensions for Analytics and Operations Mark Needham Developer Relations Engineer, Neo4j
  2. 2. ~ 30 things in 30 minutes
  3. 3. 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
  4. 4. 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
  5. 5. Neo4j Bolt Drivers
  6. 6. Official Drivers
  7. 7. Community Drivers
  8. 8. 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
  9. 9. Procedures Functions Aggregate Functions
  10. 10. Can be written in any JVM language
  11. 11. User Defined Procedures 11
  12. 12. Callable Standalone and in Cypher Statements
  13. 13. 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; } } }
  14. 14. 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; } } }
  15. 15. 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; } } }
  16. 16. 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 } } }
  17. 17. 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 } } }
  18. 18. User Defined Functions 18
  19. 19. Useable in any Cypher expression or lightweight computation
  20. 20. 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 ); } }
  21. 21. 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 ); } }
  22. 22. 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 ); } }
  23. 23. 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(); } }
  24. 24. User Defined Aggregation Functions 24
  25. 25. Custom, efficient aggregations for Data Science and BI
  26. 26. 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; } } }
  27. 27. 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; } } }
  28. 28. 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; } } }
  29. 29. 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; } } }
  30. 30. 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(); } }
  31. 31. Awesome Procedures On Cypher
  32. 32. > 300 procedures and functions
  33. 33. Data Integration
  34. 34. Load from a relational database
  35. 35. 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
  36. 36. 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
  37. 37. 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
  38. 38. Load XML
  39. 39. 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)
  40. 40. 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)
  41. 41. 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)
  42. 42. 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)
  43. 43. 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) MERGE (point:Point {id: id}) SET point.latitude = latitude, point.longitude = longitude MERGE (user:User {name: userName}) MERGE (user)-[:EDITED]->(point)
  44. 44. Load JSON
  45. 45. 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) )
  46. 46. 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 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) )
  47. 47. Graph Refactorings
  48. 48. 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
  49. 49. 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
  50. 50. apoc.create.addLabels MATCH (n:Movie) CALL apoc.create.addLabels( id(n), [ n.genre ] ) YIELD node REMOVE node.genre RETURN node
  51. 51. Cypher Execution
  52. 52. Run large scale updates CALL apoc.periodic.iterate( 'MATCH (n:Person) RETURN n', 'SET n.name = n.firstName + " " + n.lastName', {batchSize:10000, iterateList:true, parallel:true})
  53. 53. Utility Functions
  54. 54. Compute soundex encoding of a string CALL apoc.text.phonetic('Hello, dear User!') YIELD value RETURN value // will return 'H436'
  55. 55. How similar do two strings sound? CALL apoc.text.phoneticDelta( 'Hello Mr Rabbit', 'Hello Mr Ribbit') // will return '4' (very similar)
  56. 56. Extract domain names WITH 'http://www.example.com/all-the-things' AS url RETURN apoc.data.domain(url) // will return 'www.example.com'
  57. 57. Date to Timestamp RETURN apoc.date.parse( '2015/03/25 03:15:59', 's', 'yyyy/MM/dd HH:mm:ss' ) // will return 1427253359
  58. 58. Timestamp to Date RETURN apoc.date.format( 1427253359, 's', 'yyyy/MM/dd HH:mm:ss' ) // will return "2015/03/25 03:15:59"
  59. 59. And many more!
  60. 60. RDF and Graphs
  61. 61. Import RDF triples
  62. 62. semantics.importRDF CALL semantics.importRDF("file:///industry.ntriples","N-Triples", {})
  63. 63. Thomson Reuters' OpenPermID Graph
  64. 64. Graph Aided Search
  65. 65. 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 conf/neo4j.conf
  66. 66. CALL ga.es.queryNode('{"query": {"match":{"name":"alessandro"}}}') YIELD node, score RETURN node, score Find nodes
  67. 67. CALL ga.es.queryRelationship('{"query": {"match":{"city":"paris"}}}') YIELD relationship, score RETURN relationship, score Find relationships
  68. 68. dzone.com/refcardz/graph-powered-search-neo4j-amp-elasticsearch
  69. 69. Versioned Graphs
  70. 70. CALL graph.versioner.init('Person', {ssn: 123456789, name: 'Marco'}, {address: 'Via Roma 11'} ) Create node
  71. 71. CALL graph.versioner.init('Person', {ssn: 123456789, name: 'Marco'}, {address: 'Via Roma 11'} ) Immutable properties
  72. 72. CALL graph.versioner.init('Person', {ssn: 123456789, name: 'Marco'}, {address: 'Via Roma 11'} ) State properties
  73. 73. MATCH (p:Person {name: "Marco"}) WITH p CALL graph.versioner.update(p, {address: 'Via Roma 12'}) YIELD node RETURN node Update state
  74. 74. 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
  75. 75. Spatial
  76. 76. CALL spatial.addWKTLayer('geom', 'wkt') Create spatial index
  77. 77. MATCH (d:District) WITH collect(d) AS districts CALL spatial.addNodes('geom', districts) YIELD node RETURN count(*) Add nodes to spatial index
  78. 78. MATCH (d:District) WITH collect(d) AS districts CALL spatial.addNodes('geom', districts) YIELD node RETURN count(*) Collect nodes to pass in
  79. 79. 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 * Query nodes by location
  80. 80. 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
  81. 81. Graph Based Machine Learning
  82. 82. 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
  83. 83. MATCH (n:News) CALL ga.nlp.annotate({text: n.text, id: id(n)}) YIELD result MERGE (n)-[:HAS_ANNOTATED_TEXT]->(result) RETURN result Annotating text
  84. 84. 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
  85. 85. MATCH (n:News) CALL ga.nlp.annotate({text: n.text, id: id(n)}) YIELD result MERGE (n)-[:HAS_ANNOTATED_TEXT]->(result) RETURN result Apply Cypher transformation
  86. 86. Graph Algorithms
  87. 87. Graph of Thrones
  88. 88. Graph of Thrones
  89. 89. Insights from Algorithms
  90. 90. Graph of Thrones
  91. 91. Graph of Thrones
  92. 92. Determines the importance of distinct nodes in the network Finds the optimal path or evaluates route availability and quality Evaluates how a group is clustered or partitioned
  93. 93. • Single Source Short Path • All-Nodes SSP • Parallel BFS / DFS Pathfinding Centrality Community Detection Pathfinding
  94. 94. • Strongly Connected Components • Union Find / WCC • Label Propagation • Louvain • Triangle-Count / Clustering Coefficent Community Detection Pathfinding Community Detection Centrality
  95. 95. • PageRank (baseline) • Betweeness • Closeness • Degree Centralities Pathfinding Centrality Community Detection
  96. 96. 1.Call as Cypher procedure 2.Pass in specification (Label, Prop, Query) and configuration 3.~.stream variant returns (a lot) of results CALL algo.<name>.stream('Label','TYPE', {conf}) YIELD nodeId, score 4.non-stream variant writes results to graph and returns statistics CALL algo.<name>('Label','TYPE', {conf}) Usage
  97. 97. 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'}) Cypher Projection
  98. 98. DBpedia
  99. 99. CALL algo.pageRank.stream('Page', 'Link', {iterations:5}) YIELD node, score WITH * ORDER BY score DESC LIMIT 5 RETURN node.title, score Important pages +--------------------------------------+ | node.title | score | +--------------------------------------+ | "United States" | 13349.2 | | "Animal" | 6077.77 | | "France" | 5025.61 | | "List of sovereign states" | 4913.92 | | "Germany" | 4662.32 | +--------------------------------------+ 5 rows 46 seconds
  100. 100. CALL algo.labelPropagation() Largest Clusters
  101. 101. CALL algo.labelPropagation() MATCH (n:Page) WITH n ORDER BY n.pagerank DESC LIMIT 1000000 WITH n.partition AS partition, count(*) AS clusterSize, collect(n.title) AS pages RETURN pages[0] AS mainPage, pages[1..10] AS otherPages ORDER BY clusterSize DESC LIMIT 20 Largest Clusters
  102. 102. Graph Algorithms Sandbox neo4j.com/sandbox
  103. 103. Graph Visualization 122
  104. 104. 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(); }
  105. 105. 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(); }
  106. 106. 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(); }
  107. 107. GraphQL
  108. 108. 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?
  109. 109. 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?
  110. 110. 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?
  111. 111. 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? type Planet { name: String climate: String } type Character { name: String friends: [Character] homeWorld: Planet species: Species } type Species { name: String lifespan: Int origin: Planet }
  112. 112. Manual mapping code
  113. 113. Auto translating GraphQL → Cypher github.com/neo4j-graphql/neo4j-graphql github.com/neo4j-graphql/neo4j-graphql-js
  114. 114. Server Side Extension
  115. 115. dbms.unmanaged_extension_classes=org.neo4j.graphql=/graphql dbms.security.procedures.whitelist=graphql.* conf/neo4j.conf
  116. 116. 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") }' )
  117. 117. 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
  118. 118. import requests from requests.auth import HTTPBasicAuth graphql_query = """ query PersonQuery($name:String!) { Person(name:$name) { name born } } """ response = requests.post("http://localhost:7474/graphql/", auth=HTTPBasicAuth("neo4j", "neo"), headers={'content-type': 'application/json'}, json={"query": graphql_query, "variables": {"name": "Kevin Bacon"}} ) print(response.json())
  119. 119. import requests from requests.auth import HTTPBasicAuth graphql_query = """ query PersonQuery($name:String!) { Person(name:$name) { name born } } """ response = requests.post("http://localhost:7474/graphql/", auth=HTTPBasicAuth("neo4j", "neo"), headers={'content-type': 'application/json'}, json={"query": graphql_query, "variables": {"name": "Kevin Bacon"}} ) print(response.json())
  120. 120. import requests from requests.auth import HTTPBasicAuth graphql_query = """ query PersonQuery($name:String!) { Person(name:$name) { name born } } """ response = requests.post("http://localhost:7474/graphql/", auth=HTTPBasicAuth("neo4j", "neo"), headers={'content-type': 'application/json'}, json={"query": graphql_query, "variables": {"name": "Kevin Bacon"}} ) print(response.json())
  121. 121. JavaScript Library
  122. 122. The GRAND stack
  123. 123. The GRAND stack GraphQL React Apollo Neo4j Database
  124. 124. import {neo4jgraphql} from 'neo4j-graphql-js'; const resolvers = { Query: { Movie(object, params, ctx, resolveInfo) { return neo4jgraphql(object, params, ctx, resolveInfo); } } };
  125. 125. dzone.com/refcardz/an-overview-of-graphql
  126. 126. How do I find out about more cool stuff?
  127. 127. neo4j.com/tag/twin4j
  128. 128. Thank you for listening!
  129. 129. There were 28 things for those who were counting! devrel@neo4j.com 155
  130. 130. Agenda Neo4j as extensible open source database engaged community (slack, SO, partners ...) Extensible via user defined procs/functions to add capabilities to cypher either add new capabilities or implement a crucial / time critical query / operation as procedure APOC show off some cool procs - load json (stack-overflow), graph refactoring SO guide from students workshop steal some queries from or SO talk / blog Write your own procedure Graph Algorithms intro to graph algos (why) PR / Clustering Spatial (mention) GraphQL (mention) drop in neo4j-graphql -> show endpoint in GraphiQL {Tag(name: "cypher") { questions { title, upvotes, owner { name, reputation } answers { text, owner { name }}}} Mini Application? https://neo4j.com/blog/charting-neo4j-3-0/
  131. 131. Text Slide
  132. 132. 158 Text Slide
  133. 133. Two-Column Slide 159
  134. 134. Titled Columns Slide 160
  135. 135. Blank Slide 161
  136. 136. Section Slide 162
  137. 137. Section Slide 163
  138. 138. Section Slide 164

×