SlideShare a Scribd company logo
APOC Pearls
Michael Hunger
Developer Relations Engineering, Neo4j
Follow @mesirii
APOC Unicorns
All Images by TeeTurtle.com
& Unstable Unicorns
Power Up
Extending Neo4j
Neo4j Execution Engine
User Defined
Procedure
Applications
Bolt
User Defined Procedures let you write
custom code that is:
‱ Written in any JVM language
‱ Deployed to the Database
‱ Accessed by applications via Cypher
APOC History
‱ My Unicorn Moment
‱ 3.0 was about to have
User Defined Procedures
‱ Add the missing utilities
‱ Grew quickly 50 - 150 - 450
‱ Active OSS project
‱ Many contributors
APOC Pearls - Whirlwind Tour Through the Neo4j APOC Procedures Library
‱ Neo4j Sandbox
‱ Neo4j Desktop
‱ Neo4j Cloud
Available On
Install
‱ Utilities & Converters
‱ Data Integration
‱ Import / Export
‱ Graph Generation / Refactoring
‱ Transactions / Jobs / TTL
What's in the Box?
‱ Videos
‱ Documentation
‱ Browser Guide
‱ APOC Training
‱ Neo4j Community Forum
‱ apoc.help()
Where can I learn more?
If you learn one thing:
apoc.help("keyword)")
APOC
Video Series
Youtube Playlist
APOC Docs
‱ installation instructions
‱ videos
‱ searchable overview table
‱ detailed explaination
‱ examples
neo4j-contrib.github.io/neo4j-apoc-procedures
Browser Guide
:play apoc
‱ live examples
The Pearls -
That give you
Superpowers
17
Data
Integration
18
‱ Relational / Cassandra
‱ MongoDB, Couchbase,
ElasticSearch
‱ JSON, XML, CSV, XLS
‱ Cypher, GraphML
‱ ...
Data Integration
apoc.load.json
‱ load json from web-apis and files
‱ JSON Path
‱ streaming JSON
‱ compressed data
https://neo4j-contrib.github.io/neo4j-apoc-procedures/#_load_json
APOC Pearls - Whirlwind Tour Through the Neo4j APOC Procedures Library
WITH "https://api.stackexchange.com/2.2/questions?pagesize=100..." 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))


Huge
Transactions
23
Run large scale updates
CALL apoc.periodic.iterate(
'MATCH (n:Person) RETURN n',
'SET n.name = n.firstName + " " + n.lastName',
{batchSize:10000, parallel:true})
Run large scale updates
CALL apoc.periodic.iterate(
'LOAD CSV 
 AS row',
'MERGE (n:Node {id:row.id})
SET n.name = row.name',
{batchSize:10000, concurrency:10})
Utilities
26
Text Functions - apoc.text.*
indexOf, indexesOf
split, replace, regexpGroups
format
capitalize, decapitalize
random, lpad, rpad
snakeCase, camelCase, upperCase
charAt, hexCode
base64, md5, sha1,
https://neo4j-contrib.github.io/neo4j-apoc-procedures/#_text_functions
Collection Functions - apoc.coll.*
sum, avg, min,max,stdev,
zip, partition, pairs
sort, toSet, contains, split
indexOf, .different
occurrences, frequencies, flatten
disjunct, subtract, union, 

set, insert, remove
https://github.com/neo4j-contrib/neo4j-apoc-procedures/blob/3.4/docs/overview.adoc#collection-functions
Map Functions - apoc.map.*
‱ .fromNodes, .fromPairs,
.fromLists, .fromValues
‱ .merge
‱ .setKey,removeKey
‱ .clean(map,[keys],[values])
‱ .groupBy
https://github.com/neo4j-contrib/neo4j-apoc-procedures/blob/3.4/docs/overview.adoc#map-functions
JSON - apoc.convert.*
.toJson([1,2,3])
.fromJsonList('[1,2,3]')
.fromJsonMap( '{"a":42,"b":"foo","c":[1,2,3]}')
.toTree([paths],[lowerCaseRels=true])
.getJsonProperty(node,key)
.setJsonProperty(node,key,complexValue)
Graph
Refactoring
31
‱ .cloneNodes
‱ .mergeNodes
‱ .extractNode
‱ .collapseNode
‱ .categorize
Relationship Modifications
‱ .to(rel, endNode)
‱ .from(rel, startNode)
‱ .invert(rel)
‱ .setType(rel, 'NEW-TYPE')
Aggregation Function - apoc.refactor.*
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
Triggers
35
Triggers
CALL apoc.trigger.add(
name, statement,{phase:before/after})
‱ pause/resume/list/remove
‱ Transaction-Event-Handler calls cypher statement
‱ parameters: createdNodes, assignedNodeProperties, deletedNodes,...
‱ utility functions to extract entities/properties from update-records
‱ stores in graph properties
Time to Live
37
enable in config: apoc.ttl.enabled=true
Label :TTL
apoc.date.expire(In)(node, time, unit)
Creates Index on :TTL(ttl)
Time To Live TTL
background job (every 60s - configurable)
that runs:
MATCH (n:TTL)
WHERE n.ttl > timestamp()
WITH n LIMIT 1000
DET DELETE n
Time To Live TTL
Aggregation
Functions
40
Aggregation Function - apoc.agg.*
‱ more efficient variants of collect(x)[a..b]
‱ .nth,.first,.last,.slice
‱ .median(x)
‱ .percentiles(x,[0.5,0.9])
‱ .product(x)
‱ .statistics() provides a full
numeric statistic
Graph
Grouping
42
Graph Grouping
MATCH (p:Person) set p.decade = b.born / 10;
MATCH (p1:Person)-->()<--(p2:Person)
WITH p1,p2,count(*) as c
MERGE (p1)-[r:INTERACTED]-(p2)
ON CREATE SET r.count = c
CALL apoc.nodes.group(['Person'],['decade'])
YIELD node, relationship RETURN *;
Cypher
Procedures
44
apoc.custom.asProcedure/asFunction
(name,statement, columns, params)
‱ Register statements as real procedures & functions
‱ 'custom' namespace prefix
‱ Pass parameters, configure result columns
‱ Stored in graph and distributed across cluster
Custom Procedures (WIP)
call apoc.custom.asProcedure('neighbours',
'MATCH (n:Person {name:$name})-->(nb)
RETURN neighbour',
[['neighbour','NODE']],[['name','STRING']]);
call custom.neighbours('Joe') YIELD neighbour;
Custom Procedures (WIP)
Report Issues
Contribute!
Ask Questions
neo4j.com/slack community.neo4j.com
APOC on GitHub
Join the
Workshop
tomorrow!
Any Questions?
Best
Question
gets a box!
Expand Operation
53
Expand Operations
Customized path expansion from start node(s)
‱ Min/max traversals
‱ Limit number of results
‱ Optional (no rows removed if no results)
‱ Choice of BFS/DFS expansion
‱ Custom uniqueness (restrictions on visitations of nodes/rels)
‱ Relationship and label filtering
‱ Supports repeating sequences
Expand Operations
apoc.path.expand(startNode(s), relationshipFilter, labelFilter, minLevel, maxLevel) YIELD path
‱ The original, when you don’t need much customization
apoc.path.expandConfig(startNode(s), configMap) YIELD path
‱ Most flexible, rich configuration map
apoc.path.subgraphNodes(startNode(s), configMap) YIELD node
‱ Only distinct nodes, don't care about paths
apoc.path.spanningTree(startNode(s), configMap) YIELD path
‱ Only one distinct path to each node
apoc.path.subgraphAll(startNode(s), configMap) YIELD nodes, relationships
‱ Only (collected) distinct nodes (and all rels between them)
Config map values
‱ minLevel: int
‱ maxLevel: int
‱ relationshipFilter
‱ labelFilter
‱ uniqueness: (‘RELATIONSHIP_PATH’, ’NODE_GLOBAL’, ‘NODE_PATH’, etc)
‱ bfs: boolean,
‱ filterStartNode: boolean
‱ limit: int
‱ optional: boolean
‱ endNodes: [nodes]
‱ terminatorNodes: [nodes]
‱ sequence
‱ beginSequenceAtStart: boolean
Relationship Filter
‱ '<ACTED_IN' - Incoming Rel
‱ 'DIRECTED>' - Outgoing Rel
‱ 'REVIEWED' - Any direction
‱ '<ACTED_IN | DIRECTED> | REVIEWED' - Multiple, in varied directions
‱ You can't do that with Cypher
-[ACTED_IN|DIRECTED|REVIEWED]->
Label Filter
What is/isn't allowed during expansion, and what is/isn't returned
‱ '-Director' – Blacklist, not allowed in path
‱ '+Person' –Whitelist, only allowed in path (no whitelist = all allowed)
‱ '>Reviewer' – End node, only return these, and continue expansion
‱ '/Actor:Producer' – Terminator node, only return these, stop expansion
'Person|Movie|-Director|>Reviewer|/Actor:Producer' – Combine them
Sequences
Repeating sequences of relationships, labels, or both.
Uses labelFilter and relationshipFilter, just add commas
Or use sequence for both together
labelFilter:'Post | -Blocked, Reply, >Admin'
relationshipFilter:'NEXT>,<FROM,POSTED>|REPLIED>'
sequence:'Post |-Blocked, NEXT>, Reply, <FROM, >Admin,
POSTED>| REPLIED>'
End nodes / Terminator nodes
What if we already have the nodes that should end the expansion?
endNodes – like filter, but takes a collection of nodes (or ids)
terminatorNodes – like filter (stop expand), but also takes a collection
(whitelistNodes and blacklistNodes too! )
Can be used with labelFilter or sequence, but continue or include must be unanimous
End nodes / Terminator nodes
What if we already have the nodes that should end the expansion?
endNodes – like filter, but takes a collection of nodes (or ids)
terminatorNodes – like filter (stop expand), but also takes a collection
(whitelistNodes and blacklistNodes too! )
Can be used with labelFilter or sequence, but continue or include must be unanimous
Bolt Connector
62
Bolt Connector
CALL apoc.bolt.execute(url, statement, params, config) YIELD row
CALL apoc.bolt.load(url, statement, params, config) YIELD row
call apoc.bolt.load("bolt://user:password@localhost:7687","
match(p:Person {name:{name}}) return p", {name:'Michael'})
supports bolt connector parameters
returns: scalars, Maps (row), virtual nodes,rels,paths
Connect to Community
Graph
"bolt://all:readonly@138.197.15.1"
and load all Meetup Group
64
Conversion Functions
65
Turn "[1,2,3]" into a Cypher
List
in plain Cypher
66
Turn JSON List into Cypher List
with "[1,2,3]" as str
with split(substring(str,1, length(str)-2),",") as numbers
return [x IN numbers| toInteger(x)]
apoc.convert.toJson
apoc.convert.fromJsonMap
apoc.convert.fromJsonList
JSON Conversion Functions
https://neo4j-contrib.github.io/neo4j-apoc-procedures/#_from_tojson
Conversion Functions
apoc.convert.toString,.toBoolean,.toFloat,.toInteger
apoc.convert.toMap
apoc.convert.toList,.toSet
apoc.convert.toNode,.toRelationship
Logging
70
Logging
Triggers
72
Gephi Integration
73
Gephi Integration
match path = (:Person)-[:ACTED_IN]->(:Movie)
WITH path LIMIT 1000
with collect(path) as paths
call apoc.gephi.add(null,'workspace0', paths) yield nodes,
relationships, time
return nodes, relationships, time
incremental send to Gephi, needs Gephi Streaming extension
Graph Refactorings
75
Refactor the movie
graph
76
Cypher Execution
77
apoc.cypher.run(fragment, params)
apoc.cypher.doIt(fragment, params)
apoc.cypher.runTimeboxed
apoc.cypher.runFile(file or url,{config})
apoc.cypher.runSchemaFile(file or url,{config})
apoc.cypher.runMany('cypher;nstatements;',{params},{config})
apoc.cypher.mapParallel(fragment, params, list-to-parallelize)
Cypher Execution
Check out the other
periodic procs
Try apoc.periodic.iterate
example
79
Graph Grouping
80
Warmup
81
Warmup
‱ load page-cache
‱ page-skipping
‱ new implementation based on PageCache.*
‱ nodes + rels + rel-groups
‱ properties
‱ string / array properties
‱ index pages
Monitoring
83
Monitoring
‱ apoc.monitor.ids
‱ apoc.monitor.kernel
‱ apoc.monitor.store
‱ apoc.monitor.tx
‱ apoc.monitor.locks(minWaitTime long)
Conditional Cypher
Execution
85
Conditional Cypher Execution
CALL apoc.[do.]when(condition, ifQuery, elseQuery, params)
CALL apoc.[do.]case([condition, query, condition, query, 
​],
elseQuery, params)
Graph Generation
87
Graph Generation
‱ apoc.generate.er(noNodes, noEdges, 'label', 'type')
Erdos-Renyi model (uniform)
‱ apoc.generate.ws(noNodes, degree, beta, 'label', 'type')
Watts-Strogatz model (clusters)
‱ apoc.generate.ba(noNodes, edgesPerNode, 'label', 'type')
Barabasi-Albert model (preferential attachment
‱ apoc.generate.complete(noNodes, 'label', 'type')
‱ apoc.generate.simple([degrees], 'label', 'type')
Locking
89
Locking
call apoc.lock.nodes([nodes])
call apoc.lock.rels([relationships])
call apoc.lock.all([nodes],[relationships])
JSON
91
Export
92
Export
apoc.export.csv .all / .data / .query
apoc.export.cypher
apoc.export.graphml
leaving off filename does stream cypher to client
Data Creation
94
Data Creation
CALL apoc.create.node(['Label'], {key:value,
​})
CALL apoc.create.nodes(['Label'], [{key:value,
​}])
CALL apoc.create.addLabels, .removeLabels
CALL apoc.create.setProperty
CALL apoc.create.setProperties
CALL apoc.create.relationship(from,'TYPE',{key:value,
​}, to)
CALL apoc.nodes.link([nodes],'REL_TYPE')
Virtual Entities
96
Virtual Entities
Function AND Procedure
apoc.create.vNode(['Label'], {key:value,
​}) YIELD node
apoc.create.vRelationship(from,TYPE,{key:value,
​}, to)
apoc.create.vPattern({_labels:[Label],key:value},'TYPE',
{key:value,
​}, {_labels:['LabelB'],key:value})
Try
apoc.date.* with datetime()
text, coll, map, convert funcs
98
And many more!
Latest Releases
Summer Release 3.4.0.2 (Aug 8)
Spring Release 3.4.0.1 (May 16)
Winter Release 3.3.0.2 (Feb 23)
TASK
Aggregation Functions
101
Latest Additions
‱ apoc.diff graph
‱ new text similarity functions
‱ CSV loader based on neo4j-
import format
‱ apoc.load.xls
‱ apoc.group.nodes
‱ Accessor functions for
(virtual) entities
‱ S3 Support
‱ HDFS Support
‱ apoc.index.addNodeMap
‱ apoc.path.create
‱ apoc.path.slice
‱ apoc.path.combine
‱ apoc.text.code(codepoint)
‱ stream apoc.export.cypher
‱ apoc.coll.combinations(),
apoc.coll.frequencies()
102
TASK
Which of these are you
interested in?
Ask / Try
103
Procedures / Functions from Cypher
CALL apoc.custom.asProcedure('answer','RETURN 42 as answer');
CALL custom.answer();
works also with parameters, and return columns declarations
CALL apoc.custom.asFunction('answer','RETURN $input','long',
[['input','number']]);
RETURN custom.answer(42) as answer;
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
108
Callable Standalone
and in
Cypher Statements
CALL example.search('User','name:Brook*')
How to build them
Developer Manual
Build a procedure or function
you'd like
start with
the template repo
github.com/neo4j-examples/neo4j-procedure-template
112
User Defined Procedures
User-defined procedures are
● @Procedure annotated, named Java Methods
○ default name: package + method
● take @Name'ed parameters (3.1. default values)
● return a Stream of value objects
● fields are turned into columns
● can use @Context injected GraphDatabaseService etc
● run within Transaction
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
}
}
}
Deploy & Register in Neo4j Server via neo4j-harness
Call & test via neo4j-java-driver
Deploying User Defined Procedures
Build or download (shadow) jar
● Drop jar-file into $NEO4J_HOME/plugins
● Restart server
● Procedure should be available
● Otherwise check neo4j.log / debug.log
User Defined
Functions
120
Useable in any Cypher
expression or lightweight
computation
RETURN example.join(['Hello', 'World'],' ')
=> "Hello World"
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
127
Custom, efficient aggregations
for Data Science and BI
Aggregation Function In APOC
‱ more efficient variants of collect(x)[a..b]
‱ apoc.agg.nth, apoc.agg.first, apoc.agg.last, apoc.agg.slice
‱ apoc.agg.median(x)
‱ apoc.agg.percentiles(x,[0.5,0.9])
‱ apoc.agg.product(x)
‱ apoc.agg.statistics() provides a full numeric statistic
UNWIND ['abc', 'abcd', 'ab'] AS string
RETURN example.longestString(string)
=> 'abcd'
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();
}
}
One Question / Comment
from each!

More Related Content

PPTX
The Basics of MongoDB
PDF
Python Generators
PDF
Oracle 12c PDB insights
PPTX
Python-Classes.pptx
PDF
State of the Dolphin - May 2022
PDF
ProxySQL and the Tricks Up Its Sleeve - Percona Live 2022.pdf
PDF
TypeScript Introduction
PDF
Introduction to Apache NiFi 1.11.4
The Basics of MongoDB
Python Generators
Oracle 12c PDB insights
Python-Classes.pptx
State of the Dolphin - May 2022
ProxySQL and the Tricks Up Its Sleeve - Percona Live 2022.pdf
TypeScript Introduction
Introduction to Apache NiFi 1.11.4

What's hot (20)

PDF
MySQL Security
PDF
Redpanda and ClickHouse
PDF
MySQL Shell for DBAs
PDF
Oracle Security Presentation
ZIP
NoSQL databases
PDF
A Basic Django Introduction
PDF
Python Programming Tutorial | Edureka
PDF
Introduction to web programming with JavaScript
PDF
MySQL Shell - The Best MySQL DBA Tool
PDF
SeaweedFS introduction
PPTX
For Loops and Nesting in Python
PDF
An introduction to MongoDB
PDF
PySpark Training | PySpark Tutorial for Beginners | Apache Spark with Python ...
PPTX
Spark SQL Tutorial | Spark SQL Using Scala | Apache Spark Tutorial For Beginn...
PDF
What is Multithreading In Python | Python Multithreading Tutorial | Edureka
PDF
Django Tutorial | Django Web Development With Python | Django Training and Ce...
PPTX
An Introduction To REST API
PDF
Redo log improvements MYSQL 8.0
PDF
MySQL Performance Tuning: Top 10 Tips
PDF
A Thorough Comparison of Delta Lake, Iceberg and Hudi
MySQL Security
Redpanda and ClickHouse
MySQL Shell for DBAs
Oracle Security Presentation
NoSQL databases
A Basic Django Introduction
Python Programming Tutorial | Edureka
Introduction to web programming with JavaScript
MySQL Shell - The Best MySQL DBA Tool
SeaweedFS introduction
For Loops and Nesting in Python
An introduction to MongoDB
PySpark Training | PySpark Tutorial for Beginners | Apache Spark with Python ...
Spark SQL Tutorial | Spark SQL Using Scala | Apache Spark Tutorial For Beginn...
What is Multithreading In Python | Python Multithreading Tutorial | Edureka
Django Tutorial | Django Web Development With Python | Django Training and Ce...
An Introduction To REST API
Redo log improvements MYSQL 8.0
MySQL Performance Tuning: Top 10 Tips
A Thorough Comparison of Delta Lake, Iceberg and Hudi
Ad

Similar to APOC Pearls - Whirlwind Tour Through the Neo4j APOC Procedures Library (20)

PPTX
Top 10 Cypher Tuning Tips & Tricks
 
PPTX
GraphConnect 2022 - Top 10 Cypher Tuning Tips & Tricks.pptx
 
PDF
Practical Graph Algorithms with Neo4j
 
PDF
03 introduction to graph databases
 
ODP
Introduction to Neo4j APOC
PDF
RadioBOSS Advanced 7.0.8 Free Download
PDF
Evernote 10.132.4.49891 With Crack free
PDF
Roadmap y Novedades de producto
 
PDF
Adobe Photoshop 2025 Free crack Download
PDF
Office Tool Plus Free Download (Latest 2025)
PDF
Knowledge and Scalability Through Graph Composition
 
PPTX
Boost Your Neo4j with User-Defined Procedures
 
PPTX
The Inside Scoop on Neo4j: Meet the Builders
 
PDF
Road to NODES - Blazing Fast Ingest with Apache Arrow
 
PPTX
Intro to Cypher
PDF
Neo4j: The path to success with Graph Database and Graph Data Science
 
PPT
Processing Large Graphs
PPTX
Fun with Fabric in 15
 
PDF
Atlantis Word Processor 4.4.5.1 Free Download
PDF
Auslogics Video Grabber Free 1.0.0.12 Free
Top 10 Cypher Tuning Tips & Tricks
 
GraphConnect 2022 - Top 10 Cypher Tuning Tips & Tricks.pptx
 
Practical Graph Algorithms with Neo4j
 
03 introduction to graph databases
 
Introduction to Neo4j APOC
RadioBOSS Advanced 7.0.8 Free Download
Evernote 10.132.4.49891 With Crack free
Roadmap y Novedades de producto
 
Adobe Photoshop 2025 Free crack Download
Office Tool Plus Free Download (Latest 2025)
Knowledge and Scalability Through Graph Composition
 
Boost Your Neo4j with User-Defined Procedures
 
The Inside Scoop on Neo4j: Meet the Builders
 
Road to NODES - Blazing Fast Ingest with Apache Arrow
 
Intro to Cypher
Neo4j: The path to success with Graph Database and Graph Data Science
 
Processing Large Graphs
Fun with Fabric in 15
 
Atlantis Word Processor 4.4.5.1 Free Download
Auslogics Video Grabber Free 1.0.0.12 Free
Ad

More from jexp (20)

PDF
Looming Marvelous - Virtual Threads in Java Javaland.pdf
 
PDF
Easing the daily grind with the awesome JDK command line tools
 
PDF
Looming Marvelous - Virtual Threads in Java
 
PPTX
Neo4j Connector Apache Spark FiNCENFiles
 
PPTX
How Graphs Help Investigative Journalists to Connect the Dots
 
PPTX
The Home Office. Does it really work?
 
PDF
Polyglot Applications with GraalVM
 
PPTX
Neo4j Graph Streaming Services with Apache Kafka
 
PDF
How Graph Databases efficiently store, manage and query connected data at s...
 
PPTX
Refactoring, 2nd Edition
 
PPTX
New Features in Neo4j 3.4 / 3.3 - Graph Algorithms, Spatial, Date-Time & Visu...
 
PPTX
GraphQL - The new "Lingua Franca" for API-Development
 
PPTX
A whirlwind tour of graph databases
 
PPTX
A Game of Data and GraphQL
 
PPTX
Querying Graphs with GraphQL
 
PDF
Graphs & Neo4j - Past Present Future
 
PDF
Intro to Graphs and Neo4j
 
PDF
Class graph neo4j and software metrics
 
PDF
New Neo4j Auto HA Cluster
 
KEY
Spring Data Neo4j Intro SpringOne 2012
 
Looming Marvelous - Virtual Threads in Java Javaland.pdf
 
Easing the daily grind with the awesome JDK command line tools
 
Looming Marvelous - Virtual Threads in Java
 
Neo4j Connector Apache Spark FiNCENFiles
 
How Graphs Help Investigative Journalists to Connect the Dots
 
The Home Office. Does it really work?
 
Polyglot Applications with GraalVM
 
Neo4j Graph Streaming Services with Apache Kafka
 
How Graph Databases efficiently store, manage and query connected data at s...
 
Refactoring, 2nd Edition
 
New Features in Neo4j 3.4 / 3.3 - Graph Algorithms, Spatial, Date-Time & Visu...
 
GraphQL - The new "Lingua Franca" for API-Development
 
A whirlwind tour of graph databases
 
A Game of Data and GraphQL
 
Querying Graphs with GraphQL
 
Graphs & Neo4j - Past Present Future
 
Intro to Graphs and Neo4j
 
Class graph neo4j and software metrics
 
New Neo4j Auto HA Cluster
 
Spring Data Neo4j Intro SpringOne 2012
 

Recently uploaded (20)

PPT
Chapter 2 METAL FORMINGhhhhhhhjjjjmmmmmmmmm
PPTX
mbdjdhjjodule 5-1 rhfhhfjtjjhafbrhfnfbbfnb
PDF
168300704-gasification-ppt.pdfhghhhsjsjhsuxush
PDF
.pdf is not working space design for the following data for the following dat...
PPTX
Database Infoormation System (DBIS).pptx
PPTX
CEE 2 REPORT G7.pptxbdbshjdgsgjgsjfiuhsd
PPTX
The THESIS FINAL-DEFENSE-PRESENTATION.pptx
PDF
22.Patil - Early prediction of Alzheimer’s disease using convolutional neural...
PPTX
Introduction to Firewall Analytics - Interfirewall and Transfirewall.pptx
PPTX
climate analysis of Dhaka ,Banglades.pptx
PDF
Mega Projects Data Mega Projects Data
PPTX
Introduction to Basics of Ethical Hacking and Penetration Testing -Unit No. 1...
PDF
BF and FI - Blockchain, fintech and Financial Innovation Lesson 2.pdf
PDF
Launch Your Data Science Career in Kochi – 2025
PDF
Recruitment and Placement PPT.pdfbjfibjdfbjfobj
PDF
Galatica Smart Energy Infrastructure Startup Pitch Deck
PPTX
Introduction to Knowledge Engineering Part 1
PPTX
Global journeys: estimating international migration
PPTX
05. PRACTICAL GUIDE TO MICROSOFT EXCEL.pptx
PPTX
Computer network topology notes for revision
Chapter 2 METAL FORMINGhhhhhhhjjjjmmmmmmmmm
mbdjdhjjodule 5-1 rhfhhfjtjjhafbrhfnfbbfnb
168300704-gasification-ppt.pdfhghhhsjsjhsuxush
.pdf is not working space design for the following data for the following dat...
Database Infoormation System (DBIS).pptx
CEE 2 REPORT G7.pptxbdbshjdgsgjgsjfiuhsd
The THESIS FINAL-DEFENSE-PRESENTATION.pptx
22.Patil - Early prediction of Alzheimer’s disease using convolutional neural...
Introduction to Firewall Analytics - Interfirewall and Transfirewall.pptx
climate analysis of Dhaka ,Banglades.pptx
Mega Projects Data Mega Projects Data
Introduction to Basics of Ethical Hacking and Penetration Testing -Unit No. 1...
BF and FI - Blockchain, fintech and Financial Innovation Lesson 2.pdf
Launch Your Data Science Career in Kochi – 2025
Recruitment and Placement PPT.pdfbjfibjdfbjfobj
Galatica Smart Energy Infrastructure Startup Pitch Deck
Introduction to Knowledge Engineering Part 1
Global journeys: estimating international migration
05. PRACTICAL GUIDE TO MICROSOFT EXCEL.pptx
Computer network topology notes for revision

APOC Pearls - Whirlwind Tour Through the Neo4j APOC Procedures Library

  • 1. APOC Pearls Michael Hunger Developer Relations Engineering, Neo4j Follow @mesirii APOC Unicorns
  • 2. All Images by TeeTurtle.com & Unstable Unicorns
  • 4. Extending Neo4j Neo4j Execution Engine User Defined Procedure Applications Bolt User Defined Procedures let you write custom code that is: ‱ Written in any JVM language ‱ Deployed to the Database ‱ Accessed by applications via Cypher
  • 5. APOC History ‱ My Unicorn Moment ‱ 3.0 was about to have User Defined Procedures ‱ Add the missing utilities ‱ Grew quickly 50 - 150 - 450 ‱ Active OSS project ‱ Many contributors
  • 7. ‱ Neo4j Sandbox ‱ Neo4j Desktop ‱ Neo4j Cloud Available On
  • 9. ‱ Utilities & Converters ‱ Data Integration ‱ Import / Export ‱ Graph Generation / Refactoring ‱ Transactions / Jobs / TTL What's in the Box?
  • 10. ‱ Videos ‱ Documentation ‱ Browser Guide ‱ APOC Training ‱ Neo4j Community Forum ‱ apoc.help() Where can I learn more?
  • 11. If you learn one thing: apoc.help("keyword)")
  • 13. APOC Docs ‱ installation instructions ‱ videos ‱ searchable overview table ‱ detailed explaination ‱ examples neo4j-contrib.github.io/neo4j-apoc-procedures
  • 15. The Pearls - That give you Superpowers 17
  • 17. ‱ Relational / Cassandra ‱ MongoDB, Couchbase, ElasticSearch ‱ JSON, XML, CSV, XLS ‱ Cypher, GraphML ‱ ... Data Integration
  • 18. apoc.load.json ‱ load json from web-apis and files ‱ JSON Path ‱ streaming JSON ‱ compressed data https://neo4j-contrib.github.io/neo4j-apoc-procedures/#_load_json
  • 20. WITH "https://api.stackexchange.com/2.2/questions?pagesize=100..." 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)) 

  • 22. Run large scale updates CALL apoc.periodic.iterate( 'MATCH (n:Person) RETURN n', 'SET n.name = n.firstName + " " + n.lastName', {batchSize:10000, parallel:true})
  • 23. Run large scale updates CALL apoc.periodic.iterate( 'LOAD CSV 
 AS row', 'MERGE (n:Node {id:row.id}) SET n.name = row.name', {batchSize:10000, concurrency:10})
  • 25. Text Functions - apoc.text.* indexOf, indexesOf split, replace, regexpGroups format capitalize, decapitalize random, lpad, rpad snakeCase, camelCase, upperCase charAt, hexCode base64, md5, sha1, https://neo4j-contrib.github.io/neo4j-apoc-procedures/#_text_functions
  • 26. Collection Functions - apoc.coll.* sum, avg, min,max,stdev, zip, partition, pairs sort, toSet, contains, split indexOf, .different occurrences, frequencies, flatten disjunct, subtract, union, 
 set, insert, remove https://github.com/neo4j-contrib/neo4j-apoc-procedures/blob/3.4/docs/overview.adoc#collection-functions
  • 27. Map Functions - apoc.map.* ‱ .fromNodes, .fromPairs, .fromLists, .fromValues ‱ .merge ‱ .setKey,removeKey ‱ .clean(map,[keys],[values]) ‱ .groupBy https://github.com/neo4j-contrib/neo4j-apoc-procedures/blob/3.4/docs/overview.adoc#map-functions
  • 28. JSON - apoc.convert.* .toJson([1,2,3]) .fromJsonList('[1,2,3]') .fromJsonMap( '{"a":42,"b":"foo","c":[1,2,3]}') .toTree([paths],[lowerCaseRels=true]) .getJsonProperty(node,key) .setJsonProperty(node,key,complexValue)
  • 30. ‱ .cloneNodes ‱ .mergeNodes ‱ .extractNode ‱ .collapseNode ‱ .categorize Relationship Modifications ‱ .to(rel, endNode) ‱ .from(rel, startNode) ‱ .invert(rel) ‱ .setType(rel, 'NEW-TYPE') Aggregation Function - apoc.refactor.*
  • 31. 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
  • 32. apoc.create.addLabels MATCH (n:Movie) CALL apoc.create.addLabels( id(n), [ n.genre ] ) YIELD node REMOVE node.genre RETURN node
  • 34. Triggers CALL apoc.trigger.add( name, statement,{phase:before/after}) ‱ pause/resume/list/remove ‱ Transaction-Event-Handler calls cypher statement ‱ parameters: createdNodes, assignedNodeProperties, deletedNodes,... ‱ utility functions to extract entities/properties from update-records ‱ stores in graph properties
  • 36. enable in config: apoc.ttl.enabled=true Label :TTL apoc.date.expire(In)(node, time, unit) Creates Index on :TTL(ttl) Time To Live TTL
  • 37. background job (every 60s - configurable) that runs: MATCH (n:TTL) WHERE n.ttl > timestamp() WITH n LIMIT 1000 DET DELETE n Time To Live TTL
  • 39. Aggregation Function - apoc.agg.* ‱ more efficient variants of collect(x)[a..b] ‱ .nth,.first,.last,.slice ‱ .median(x) ‱ .percentiles(x,[0.5,0.9]) ‱ .product(x) ‱ .statistics() provides a full numeric statistic
  • 41. Graph Grouping MATCH (p:Person) set p.decade = b.born / 10; MATCH (p1:Person)-->()<--(p2:Person) WITH p1,p2,count(*) as c MERGE (p1)-[r:INTERACTED]-(p2) ON CREATE SET r.count = c CALL apoc.nodes.group(['Person'],['decade']) YIELD node, relationship RETURN *;
  • 43. apoc.custom.asProcedure/asFunction (name,statement, columns, params) ‱ Register statements as real procedures & functions ‱ 'custom' namespace prefix ‱ Pass parameters, configure result columns ‱ Stored in graph and distributed across cluster Custom Procedures (WIP)
  • 44. call apoc.custom.asProcedure('neighbours', 'MATCH (n:Person {name:$name})-->(nb) RETURN neighbour', [['neighbour','NODE']],[['name','STRING']]); call custom.neighbours('Joe') YIELD neighbour; Custom Procedures (WIP)
  • 52. Expand Operations Customized path expansion from start node(s) ‱ Min/max traversals ‱ Limit number of results ‱ Optional (no rows removed if no results) ‱ Choice of BFS/DFS expansion ‱ Custom uniqueness (restrictions on visitations of nodes/rels) ‱ Relationship and label filtering ‱ Supports repeating sequences
  • 53. Expand Operations apoc.path.expand(startNode(s), relationshipFilter, labelFilter, minLevel, maxLevel) YIELD path ‱ The original, when you don’t need much customization apoc.path.expandConfig(startNode(s), configMap) YIELD path ‱ Most flexible, rich configuration map apoc.path.subgraphNodes(startNode(s), configMap) YIELD node ‱ Only distinct nodes, don't care about paths apoc.path.spanningTree(startNode(s), configMap) YIELD path ‱ Only one distinct path to each node apoc.path.subgraphAll(startNode(s), configMap) YIELD nodes, relationships ‱ Only (collected) distinct nodes (and all rels between them)
  • 54. Config map values ‱ minLevel: int ‱ maxLevel: int ‱ relationshipFilter ‱ labelFilter ‱ uniqueness: (‘RELATIONSHIP_PATH’, ’NODE_GLOBAL’, ‘NODE_PATH’, etc) ‱ bfs: boolean, ‱ filterStartNode: boolean ‱ limit: int ‱ optional: boolean ‱ endNodes: [nodes] ‱ terminatorNodes: [nodes] ‱ sequence ‱ beginSequenceAtStart: boolean
  • 55. Relationship Filter ‱ '<ACTED_IN' - Incoming Rel ‱ 'DIRECTED>' - Outgoing Rel ‱ 'REVIEWED' - Any direction ‱ '<ACTED_IN | DIRECTED> | REVIEWED' - Multiple, in varied directions ‱ You can't do that with Cypher -[ACTED_IN|DIRECTED|REVIEWED]->
  • 56. Label Filter What is/isn't allowed during expansion, and what is/isn't returned ‱ '-Director' – Blacklist, not allowed in path ‱ '+Person' –Whitelist, only allowed in path (no whitelist = all allowed) ‱ '>Reviewer' – End node, only return these, and continue expansion ‱ '/Actor:Producer' – Terminator node, only return these, stop expansion 'Person|Movie|-Director|>Reviewer|/Actor:Producer' – Combine them
  • 57. Sequences Repeating sequences of relationships, labels, or both. Uses labelFilter and relationshipFilter, just add commas Or use sequence for both together labelFilter:'Post | -Blocked, Reply, >Admin' relationshipFilter:'NEXT>,<FROM,POSTED>|REPLIED>' sequence:'Post |-Blocked, NEXT>, Reply, <FROM, >Admin, POSTED>| REPLIED>'
  • 58. End nodes / Terminator nodes What if we already have the nodes that should end the expansion? endNodes – like filter, but takes a collection of nodes (or ids) terminatorNodes – like filter (stop expand), but also takes a collection (whitelistNodes and blacklistNodes too! ) Can be used with labelFilter or sequence, but continue or include must be unanimous
  • 59. End nodes / Terminator nodes What if we already have the nodes that should end the expansion? endNodes – like filter, but takes a collection of nodes (or ids) terminatorNodes – like filter (stop expand), but also takes a collection (whitelistNodes and blacklistNodes too! ) Can be used with labelFilter or sequence, but continue or include must be unanimous
  • 61. Bolt Connector CALL apoc.bolt.execute(url, statement, params, config) YIELD row CALL apoc.bolt.load(url, statement, params, config) YIELD row call apoc.bolt.load("bolt://user:password@localhost:7687"," match(p:Person {name:{name}}) return p", {name:'Michael'}) supports bolt connector parameters returns: scalars, Maps (row), virtual nodes,rels,paths
  • 64. Turn "[1,2,3]" into a Cypher List in plain Cypher 66
  • 65. Turn JSON List into Cypher List with "[1,2,3]" as str with split(substring(str,1, length(str)-2),",") as numbers return [x IN numbers| toInteger(x)]
  • 72. Gephi Integration match path = (:Person)-[:ACTED_IN]->(:Movie) WITH path LIMIT 1000 with collect(path) as paths call apoc.gephi.add(null,'workspace0', paths) yield nodes, relationships, time return nodes, relationships, time incremental send to Gephi, needs Gephi Streaming extension
  • 76. apoc.cypher.run(fragment, params) apoc.cypher.doIt(fragment, params) apoc.cypher.runTimeboxed apoc.cypher.runFile(file or url,{config}) apoc.cypher.runSchemaFile(file or url,{config}) apoc.cypher.runMany('cypher;nstatements;',{params},{config}) apoc.cypher.mapParallel(fragment, params, list-to-parallelize) Cypher Execution
  • 77. Check out the other periodic procs Try apoc.periodic.iterate example 79
  • 80. Warmup ‱ load page-cache ‱ page-skipping ‱ new implementation based on PageCache.* ‱ nodes + rels + rel-groups ‱ properties ‱ string / array properties ‱ index pages
  • 82. Monitoring ‱ apoc.monitor.ids ‱ apoc.monitor.kernel ‱ apoc.monitor.store ‱ apoc.monitor.tx ‱ apoc.monitor.locks(minWaitTime long)
  • 84. Conditional Cypher Execution CALL apoc.[do.]when(condition, ifQuery, elseQuery, params) CALL apoc.[do.]case([condition, query, condition, query, 
​], elseQuery, params)
  • 86. Graph Generation ‱ apoc.generate.er(noNodes, noEdges, 'label', 'type') Erdos-Renyi model (uniform) ‱ apoc.generate.ws(noNodes, degree, beta, 'label', 'type') Watts-Strogatz model (clusters) ‱ apoc.generate.ba(noNodes, edgesPerNode, 'label', 'type') Barabasi-Albert model (preferential attachment ‱ apoc.generate.complete(noNodes, 'label', 'type') ‱ apoc.generate.simple([degrees], 'label', 'type')
  • 91. Export apoc.export.csv .all / .data / .query apoc.export.cypher apoc.export.graphml leaving off filename does stream cypher to client
  • 93. Data Creation CALL apoc.create.node(['Label'], {key:value,
​}) CALL apoc.create.nodes(['Label'], [{key:value,
​}]) CALL apoc.create.addLabels, .removeLabels CALL apoc.create.setProperty CALL apoc.create.setProperties CALL apoc.create.relationship(from,'TYPE',{key:value,
​}, to) CALL apoc.nodes.link([nodes],'REL_TYPE')
  • 95. Virtual Entities Function AND Procedure apoc.create.vNode(['Label'], {key:value,
​}) YIELD node apoc.create.vRelationship(from,TYPE,{key:value,
​}, to) apoc.create.vPattern({_labels:[Label],key:value},'TYPE', {key:value,
​}, {_labels:['LabelB'],key:value})
  • 96. Try apoc.date.* with datetime() text, coll, map, convert funcs 98
  • 98. Latest Releases Summer Release 3.4.0.2 (Aug 8) Spring Release 3.4.0.1 (May 16) Winter Release 3.3.0.2 (Feb 23)
  • 100. Latest Additions ‱ apoc.diff graph ‱ new text similarity functions ‱ CSV loader based on neo4j- import format ‱ apoc.load.xls ‱ apoc.group.nodes ‱ Accessor functions for (virtual) entities ‱ S3 Support ‱ HDFS Support ‱ apoc.index.addNodeMap ‱ apoc.path.create ‱ apoc.path.slice ‱ apoc.path.combine ‱ apoc.text.code(codepoint) ‱ stream apoc.export.cypher ‱ apoc.coll.combinations(), apoc.coll.frequencies() 102
  • 101. TASK Which of these are you interested in? Ask / Try 103
  • 102. Procedures / Functions from Cypher CALL apoc.custom.asProcedure('answer','RETURN 42 as answer'); CALL custom.answer(); works also with parameters, and return columns declarations CALL apoc.custom.asFunction('answer','RETURN $input','long', [['input','number']]); RETURN custom.answer(42) as answer;
  • 103. 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
  • 105. Can be written in any JVM language
  • 109. How to build them Developer Manual
  • 110. Build a procedure or function you'd like start with the template repo github.com/neo4j-examples/neo4j-procedure-template 112
  • 111. User Defined Procedures User-defined procedures are ● @Procedure annotated, named Java Methods ○ default name: package + method ● take @Name'ed parameters (3.1. default values) ● return a Stream of value objects ● fields are turned into columns ● can use @Context injected GraphDatabaseService etc ● run within Transaction
  • 112. 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; } } }
  • 113. 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 } } } Deploy & Register in Neo4j Server via neo4j-harness Call & test via neo4j-java-driver
  • 114. Deploying User Defined Procedures Build or download (shadow) jar ● Drop jar-file into $NEO4J_HOME/plugins ● Restart server ● Procedure should be available ● Otherwise check neo4j.log / debug.log
  • 116. Useable in any Cypher expression or lightweight computation
  • 118. 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 ); } }
  • 119. 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 ); } }
  • 120. 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 ); } }
  • 121. 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(); } }
  • 123. Custom, efficient aggregations for Data Science and BI
  • 124. Aggregation Function In APOC ‱ more efficient variants of collect(x)[a..b] ‱ apoc.agg.nth, apoc.agg.first, apoc.agg.last, apoc.agg.slice ‱ apoc.agg.median(x) ‱ apoc.agg.percentiles(x,[0.5,0.9]) ‱ apoc.agg.product(x) ‱ apoc.agg.statistics() provides a full numeric statistic
  • 125. UNWIND ['abc', 'abcd', 'ab'] AS string RETURN example.longestString(string) => 'abcd'
  • 126. 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; } } }
  • 127. 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; } } }
  • 128. 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; } } }
  • 129. 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; } } }
  • 130. 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(); } }
  • 131. One Question / Comment from each!