SlideShare a Scribd company logo
1 of 164
Download to read offline
Utilizing Powerful Extensions
for Analytics and Operations
Mark Needham
Developer Relations Engineer, Neo4j
~ 30 things in 30 minutes
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
Neo4j Bolt Drivers
Official Drivers
Community Drivers
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
Procedures
Functions
Aggregate Functions
Can be written in any JVM language
User Defined
Procedures
11
Callable Standalone
and in
Cypher Statements
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
}
}
}
User Defined
Functions
18
Useable in any Cypher
expression or lightweight
computation
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();
}
}
User Defined
Aggregation Functions
24
Custom, efficient aggregations
for Data Science and BI
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();
}
}
Awesome Procedures
On Cypher
> 300
procedures and functions
Data Integration
Load from a relational database
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
Load XML
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)
MERGE (point:Point {id: id})
SET point.latitude = latitude,
point.longitude = longitude
MERGE (user:User {name: userName})
MERGE (user)-[:EDITED]->(point)
Load JSON
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
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)
)
Graph Refactorings
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
Cypher Execution
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})
Utility Functions
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"
And many more!
RDF and Graphs
Import RDF triples
semantics.importRDF
CALL semantics.importRDF("file:///industry.ntriples","N-Triples", {})
Thomson Reuters' OpenPermID Graph
Graph Aided Search
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
CALL ga.es.queryNode('{"query":
{"match":{"name":"alessandro"}}}')
YIELD node, score
RETURN node, score
Find nodes
CALL ga.es.queryRelationship('{"query":
{"match":{"city":"paris"}}}')
YIELD relationship, score
RETURN relationship, score
Find relationships
dzone.com/refcardz/graph-powered-search-neo4j-amp-elasticsearch
Versioned Graphs
CALL graph.versioner.init('Person',
{ssn: 123456789, name: 'Marco'},
{address: 'Via Roma 11'}
)
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
MATCH (p:Person {name: "Marco"})
WITH p
CALL graph.versioner.update(p, {address: 'Via Roma 12'})
YIELD node
RETURN node
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
Spatial
CALL spatial.addWKTLayer('geom', 'wkt')
Create spatial index
MATCH (d:District)
WITH collect(d) AS districts
CALL spatial.addNodes('geom', districts) YIELD node
RETURN count(*)
Add nodes to spatial index
MATCH (d:District)
WITH collect(d) AS districts
CALL spatial.addNodes('geom', districts) YIELD node
RETURN count(*)
Collect nodes to pass in
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
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
Graph Based
Machine Learning
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
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
Apply Cypher transformation
Graph Algorithms
Graph of Thrones
Graph of Thrones
Insights from Algorithms
Graph of Thrones
Graph of Thrones
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
• Single Source Short Path
• All-Nodes SSP
• Parallel BFS / DFS
Pathfinding
Centrality Community
Detection
Pathfinding
• Strongly Connected Components
• Union Find / WCC
• Label Propagation
• Louvain
• Triangle-Count / Clustering
Coefficent
Community Detection
Pathfinding
Community
Detection
Centrality
• PageRank (baseline)
• Betweeness
• Closeness
• Degree
Centralities
Pathfinding
Centrality
Community
Detection
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
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
DBpedia
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
CALL algo.labelPropagation()
Largest Clusters
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
Graph Algorithms Sandbox
neo4j.com/sandbox
Graph Visualization
122
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();
}
GraphQL
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.
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
}
Manual mapping code
Auto translating GraphQL → Cypher
github.com/neo4j-graphql/neo4j-graphql
github.com/neo4j-graphql/neo4j-graphql-js
Server Side Extension
dbms.unmanaged_extension_classes=org.neo4j.graphql=/graphql
dbms.security.procedures.whitelist=graphql.*
conf/neo4j.conf
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 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())
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())
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())
JavaScript Library
The GRAND stack
The GRAND stack
GraphQL
React
Apollo
Neo4j Database
import {neo4jgraphql} from 'neo4j-graphql-js';
const resolvers = {
Query: {
Movie(object, params, ctx, resolveInfo) {
return neo4jgraphql(object, params, ctx, resolveInfo);
}
}
};
dzone.com/refcardz/an-overview-of-graphql
How do I find out
about more cool stuff?
neo4j.com/tag/twin4j
Thank you for listening!
There were 28 things for
those who were counting!
devrel@neo4j.com
155
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/
Text Slide
158
Text Slide
Two-Column Slide
159
Titled Columns Slide
160
Blank Slide
161
Section Slide
162
Section Slide
163
Section Slide
164

More Related Content

What's hot

Mutant Tests Too: The SQL
Mutant Tests Too: The SQLMutant Tests Too: The SQL
Mutant Tests Too: The SQL
DataWorks Summit
 

What's hot (20)

ELK Ruminating on Logs (Zendcon 2016)
ELK Ruminating on Logs (Zendcon 2016)ELK Ruminating on Logs (Zendcon 2016)
ELK Ruminating on Logs (Zendcon 2016)
 
Oracle GoldenGate Presentation from OTN Virtual Technology Summit - 7/9/14 (PDF)
Oracle GoldenGate Presentation from OTN Virtual Technology Summit - 7/9/14 (PDF)Oracle GoldenGate Presentation from OTN Virtual Technology Summit - 7/9/14 (PDF)
Oracle GoldenGate Presentation from OTN Virtual Technology Summit - 7/9/14 (PDF)
 
What's cool in the new and updated OSGi Specs (2013)
What's cool in the new and updated OSGi Specs (2013)What's cool in the new and updated OSGi Specs (2013)
What's cool in the new and updated OSGi Specs (2013)
 
Relational Database Access with Python ‘sans’ ORM
Relational Database Access with Python ‘sans’ ORM  Relational Database Access with Python ‘sans’ ORM
Relational Database Access with Python ‘sans’ ORM
 
05 integrate redis
05 integrate redis05 integrate redis
05 integrate redis
 
Combine Spring Data Neo4j and Spring Boot to quickl
Combine Spring Data Neo4j and Spring Boot to quicklCombine Spring Data Neo4j and Spring Boot to quickl
Combine Spring Data Neo4j and Spring Boot to quickl
 
More kibana
More kibanaMore kibana
More kibana
 
Extreme Replication - RMOUG Presentation
Extreme Replication - RMOUG PresentationExtreme Replication - RMOUG Presentation
Extreme Replication - RMOUG Presentation
 
ECO 2022 - OCI and HashiCorp Terraform
ECO 2022 - OCI and HashiCorp TerraformECO 2022 - OCI and HashiCorp Terraform
ECO 2022 - OCI and HashiCorp Terraform
 
Database As A Service: OEM + ODA (OOW 15 Presentation)
Database As A Service: OEM + ODA (OOW 15 Presentation)Database As A Service: OEM + ODA (OOW 15 Presentation)
Database As A Service: OEM + ODA (OOW 15 Presentation)
 
Evolving Streaming Applications
Evolving Streaming ApplicationsEvolving Streaming Applications
Evolving Streaming Applications
 
Oem12c db12c and You
Oem12c db12c and YouOem12c db12c and You
Oem12c db12c and You
 
02 integrate highchart
02 integrate highchart02 integrate highchart
02 integrate highchart
 
GraphQL 101
GraphQL 101GraphQL 101
GraphQL 101
 
Mutant Tests Too: The SQL
Mutant Tests Too: The SQLMutant Tests Too: The SQL
Mutant Tests Too: The SQL
 
SQL for NoSQL and how Apache Calcite can help
SQL for NoSQL and how  Apache Calcite can helpSQL for NoSQL and how  Apache Calcite can help
SQL for NoSQL and how Apache Calcite can help
 
Lightbend Lagom: Microservices Just Right
Lightbend Lagom: Microservices Just RightLightbend Lagom: Microservices Just Right
Lightbend Lagom: Microservices Just Right
 
Oozie @ Riot Games
Oozie @ Riot GamesOozie @ Riot Games
Oozie @ Riot Games
 
Introducing Neo4j 3.1: New Security and Clustering Architecture
Introducing Neo4j 3.1: New Security and Clustering Architecture Introducing Neo4j 3.1: New Security and Clustering Architecture
Introducing Neo4j 3.1: New Security and Clustering Architecture
 
Scala Frameworks for Web Application 2016
Scala Frameworks for Web Application 2016Scala Frameworks for Web Application 2016
Scala Frameworks for Web Application 2016
 

Similar to GraphTour - Utilizing Powerful Extensions for Analytics & Operations

Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs
偉格 高
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
Sven Haiges
 

Similar to GraphTour - Utilizing Powerful Extensions for Analytics & Operations (20)

Neo4j GraphTour: Utilizing Powerful Extensions for Analytics and Operations
Neo4j GraphTour: Utilizing Powerful Extensions for Analytics and OperationsNeo4j GraphTour: Utilizing Powerful Extensions for Analytics and Operations
Neo4j GraphTour: Utilizing Powerful Extensions for Analytics and Operations
 
Utilizing Powerful Extensions for Analytics and Operations
Utilizing Powerful Extensions for Analytics and OperationsUtilizing Powerful Extensions for Analytics and Operations
Utilizing Powerful Extensions for Analytics and Operations
 
Utilizing Powerful Extensions for Analytics and Operations
Utilizing Powerful Extensions for Analytics and OperationsUtilizing Powerful Extensions for Analytics and Operations
Utilizing Powerful Extensions for Analytics and Operations
 
Graph Algorithms: Analytics for Understanding Data Relationships
Graph Algorithms: Analytics for Understanding Data RelationshipsGraph Algorithms: Analytics for Understanding Data Relationships
Graph Algorithms: Analytics for Understanding Data Relationships
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
3 database-jdbc(1)
3 database-jdbc(1)3 database-jdbc(1)
3 database-jdbc(1)
 
MongoDB + Java - Everything you need to know
MongoDB + Java - Everything you need to know MongoDB + Java - Everything you need to know
MongoDB + Java - Everything you need to know
 
Mongo+java (1)
Mongo+java (1)Mongo+java (1)
Mongo+java (1)
 
Go react codelab
Go react codelabGo react codelab
Go react codelab
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs
 
GraphQL & Prisma from Scratch
GraphQL & Prisma from ScratchGraphQL & Prisma from Scratch
GraphQL & Prisma from Scratch
 
Next-generation API Development with GraphQL and Prisma
Next-generation API Development with GraphQL and PrismaNext-generation API Development with GraphQL and Prisma
Next-generation API Development with GraphQL and Prisma
 
Gwt.create
Gwt.createGwt.create
Gwt.create
 
Spring boot
Spring boot Spring boot
Spring boot
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
Android best practices
Android best practicesAndroid best practices
Android best practices
 
TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...
TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...
TechDays 2016 - Developing websites using asp.net core mvc6 and entity framew...
 
The Past Year in Spring for Apache Geode
The Past Year in Spring for Apache GeodeThe Past Year in Spring for Apache Geode
The Past Year in Spring for Apache Geode
 
JDBC Tutorial
JDBC TutorialJDBC Tutorial
JDBC Tutorial
 

More from Neo4j

More from Neo4j (20)

Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
QIAGEN: Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
QIAGEN: Biomedical Knowledge Graphs for Data Scientists and BioinformaticiansQIAGEN: Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
QIAGEN: Biomedical Knowledge Graphs for Data Scientists and Bioinformaticians
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
ISDEFE - GraphSummit Madrid - ARETA: Aviation Real-Time Emissions Token Accre...
ISDEFE - GraphSummit Madrid - ARETA: Aviation Real-Time Emissions Token Accre...ISDEFE - GraphSummit Madrid - ARETA: Aviation Real-Time Emissions Token Accre...
ISDEFE - GraphSummit Madrid - ARETA: Aviation Real-Time Emissions Token Accre...
 
BBVA - GraphSummit Madrid - Caso de éxito en BBVA: Optimizando con grafos
BBVA - GraphSummit Madrid - Caso de éxito en BBVA: Optimizando con grafosBBVA - GraphSummit Madrid - Caso de éxito en BBVA: Optimizando con grafos
BBVA - GraphSummit Madrid - Caso de éxito en BBVA: Optimizando con grafos
 
Graph Everywhere - Josep Taruella - Por qué Graph Data Science en tus modelos...
Graph Everywhere - Josep Taruella - Por qué Graph Data Science en tus modelos...Graph Everywhere - Josep Taruella - Por qué Graph Data Science en tus modelos...
Graph Everywhere - Josep Taruella - Por qué Graph Data Science en tus modelos...
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
 
Neo4j_Exploring the Impact of Graph Technology on Financial Services.pdf
Neo4j_Exploring the Impact of Graph Technology on Financial Services.pdfNeo4j_Exploring the Impact of Graph Technology on Financial Services.pdf
Neo4j_Exploring the Impact of Graph Technology on Financial Services.pdf
 
Rabobank_Exploring the Impact of Graph Technology on Financial Services.pdf
Rabobank_Exploring the Impact of Graph Technology on Financial Services.pdfRabobank_Exploring the Impact of Graph Technology on Financial Services.pdf
Rabobank_Exploring the Impact of Graph Technology on Financial Services.pdf
 
Webinar - IA generativa e grafi Neo4j: RAG time!
Webinar - IA generativa e grafi Neo4j: RAG time!Webinar - IA generativa e grafi Neo4j: RAG time!
Webinar - IA generativa e grafi Neo4j: RAG time!
 
IA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG timeIA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG time
 
Neo4j: Data Engineering for RAG (retrieval augmented generation)
Neo4j: Data Engineering for RAG (retrieval augmented generation)Neo4j: Data Engineering for RAG (retrieval augmented generation)
Neo4j: Data Engineering for RAG (retrieval augmented generation)
 
Neo4j Graph Summit 2024 Workshop - EMEA - Breda_and_Munchen.pdf
Neo4j Graph Summit 2024 Workshop - EMEA - Breda_and_Munchen.pdfNeo4j Graph Summit 2024 Workshop - EMEA - Breda_and_Munchen.pdf
Neo4j Graph Summit 2024 Workshop - EMEA - Breda_and_Munchen.pdf
 
Enabling GenAI Breakthroughs with Knowledge Graphs
Enabling GenAI Breakthroughs with Knowledge GraphsEnabling GenAI Breakthroughs with Knowledge Graphs
Enabling GenAI Breakthroughs with Knowledge Graphs
 
Neo4j_Anurag Tandon_Product Vision and Roadmap.Benelux.pptx.pdf
Neo4j_Anurag Tandon_Product Vision and Roadmap.Benelux.pptx.pdfNeo4j_Anurag Tandon_Product Vision and Roadmap.Benelux.pptx.pdf
Neo4j_Anurag Tandon_Product Vision and Roadmap.Benelux.pptx.pdf
 
Neo4j Jesus Barrasa The Art of the Possible with Graph
Neo4j Jesus Barrasa The Art of the Possible with GraphNeo4j Jesus Barrasa The Art of the Possible with Graph
Neo4j Jesus Barrasa The Art of the Possible with Graph
 

Recently uploaded

AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 

Recently uploaded (20)

Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions Presentation
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 

GraphTour - Utilizing Powerful Extensions for Analytics & Operations

  • 1. Utilizing Powerful Extensions for Analytics and Operations Mark Needham Developer Relations Engineer, Neo4j
  • 2. ~ 30 things in 30 minutes
  • 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. 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
  • 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
  • 10. Can be written in any JVM language
  • 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. 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. 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. 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. 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 } } }
  • 19. Useable in any Cypher expression or lightweight computation
  • 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. 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. 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. 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(); } }
  • 25. Custom, efficient aggregations for Data Science and BI
  • 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. 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. 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. 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. 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.
  • 32.
  • 34.
  • 35.
  • 36. > 300 procedures and functions
  • 37.
  • 38.
  • 40. Load from a relational database
  • 41. 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
  • 42. 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
  • 43. 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
  • 45. 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)
  • 46. 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)
  • 47. 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)
  • 48. 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)
  • 49. 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)
  • 51. 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) )
  • 52. 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) )
  • 54. 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
  • 55. 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
  • 56. apoc.create.addLabels MATCH (n:Movie) CALL apoc.create.addLabels( id(n), [ n.genre ] ) YIELD node REMOVE node.genre RETURN node
  • 58. 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})
  • 60. Compute soundex encoding of a string CALL apoc.text.phonetic('Hello, dear User!') YIELD value RETURN value // will return 'H436'
  • 61. How similar do two strings sound? CALL apoc.text.phoneticDelta( 'Hello Mr Rabbit', 'Hello Mr Ribbit') // will return '4' (very similar)
  • 62. Extract domain names WITH 'http://www.example.com/all-the-things' AS url RETURN apoc.data.domain(url) // will return 'www.example.com'
  • 63. Date to Timestamp RETURN apoc.date.parse( '2015/03/25 03:15:59', 's', 'yyyy/MM/dd HH:mm:ss' ) // will return 1427253359
  • 64. Timestamp to Date RETURN apoc.date.format( 1427253359, 's', 'yyyy/MM/dd HH:mm:ss' ) // will return "2015/03/25 03:15:59"
  • 67.
  • 68.
  • 73.
  • 74.
  • 75.
  • 76. 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
  • 81.
  • 82.
  • 83. CALL graph.versioner.init('Person', {ssn: 123456789, name: 'Marco'}, {address: 'Via Roma 11'} ) Create node
  • 84. CALL graph.versioner.init('Person', {ssn: 123456789, name: 'Marco'}, {address: 'Via Roma 11'} ) Immutable properties
  • 85. CALL graph.versioner.init('Person', {ssn: 123456789, name: 'Marco'}, {address: 'Via Roma 11'} ) State properties
  • 86. MATCH (p:Person {name: "Marco"}) WITH p CALL graph.versioner.update(p, {address: 'Via Roma 12'}) YIELD node RETURN node Update state
  • 87. 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
  • 89.
  • 91. MATCH (d:District) WITH collect(d) AS districts CALL spatial.addNodes('geom', districts) YIELD node RETURN count(*) Add nodes to spatial index
  • 92. MATCH (d:District) WITH collect(d) AS districts CALL spatial.addNodes('geom', districts) YIELD node RETURN count(*) Collect nodes to pass in
  • 93. 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
  • 94. 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
  • 96.
  • 97.
  • 98.
  • 99. 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
  • 100. 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
  • 101. 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
  • 102. 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
  • 109. 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
  • 110. • Single Source Short Path • All-Nodes SSP • Parallel BFS / DFS Pathfinding Centrality Community Detection Pathfinding
  • 111. • Strongly Connected Components • Union Find / WCC • Label Propagation • Louvain • Triangle-Count / Clustering Coefficent Community Detection Pathfinding Community Detection Centrality
  • 112. • PageRank (baseline) • Betweeness • Closeness • Degree Centralities Pathfinding Centrality Community Detection
  • 113.
  • 114.
  • 115. 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
  • 116. 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
  • 118. 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
  • 120. 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
  • 123.
  • 124.
  • 125.
  • 126. 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(); }
  • 127. 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(); }
  • 128. 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(); }
  • 130. 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?
  • 131. 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?
  • 132. 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?
  • 133. 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 }
  • 135.
  • 136. Auto translating GraphQL → Cypher github.com/neo4j-graphql/neo4j-graphql github.com/neo4j-graphql/neo4j-graphql-js
  • 138.
  • 140. 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") }' )
  • 141. 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
  • 142. 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())
  • 143. 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())
  • 144. 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())
  • 146.
  • 149. import {neo4jgraphql} from 'neo4j-graphql-js'; const resolvers = { Query: { Movie(object, params, ctx, resolveInfo) { return neo4jgraphql(object, params, ctx, resolveInfo); } } };
  • 151. How do I find out about more cool stuff?
  • 152.
  • 154. Thank you for listening!
  • 155. There were 28 things for those who were counting! devrel@neo4j.com 155
  • 156. 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/