Training Lightning Basics - tomgeudens/practical-neo4j GitHub Wiki

Context: Cut-and-paste commands for the Lightning Basics training.

Prerequisite: You are attending a Neo4j Lightning Basics training.

Twenty Minutes

From bank to Panama

MATCH sg=(:Bank {name: "KBC Bank NV"})-[*]-(:Country {name: "Panama"})
RETURN sg;

Shortest way from bank to Panama

MATCH sg=shortestPath( (:Bank {name: "KBC Bank NV"})-[*]-(:Country {name: "Panama"}) )
RETURN sg;

The usual suspect

MATCH sg=(:Bank {name: "KBC Bank NV"})-[*]-(:Person {name: "Vladimir Putin"})-[*]-(:Country {name: "Panama"}) 
RETURN sg;

Any person

MATCH (:Bank {name: "KBC Bank NV"})-[*]-(x:Person)-[*]-(:Country {name: "Panama"}) 
RETURN DISTINCT x.name as suspect;

Flexible model in action

MATCH (p:Person {name: "Tom Geudens"})
SET p:Fraudster;

Fraudsters only

MATCH (f:Fraudster)
RETURN f;

Cypher ASCII Art

The mysterious Mr White

MATCH (p:Person {name: "Tom Hanks"}) RETURN p
MATCH ()-[ai:ACTED_IN {roles: ["Mr. White"]}]-() RETURN ai
MATCH (x)-[ai:ACTED_IN {roles: ["Mr. White"]}]-(y) RETURN x.name, x.title, ai.roles, y.name, y.title

Lock & Load

Inspection - Expected number of Movie nodes

LOAD CSV FROM 'http://data.neo4j.com/intro/movies/movies.csv'
AS row
RETURN count(*);

Inspection - Expected number of Person nodes

LOAD CSV FROM 'http://data.neo4j.com/intro/movies/people.csv'
AS row 
RETURN count(*);

Inspection - Expected number of DIRECTED relationships

LOAD CSV FROM 'http://data.neo4j.com/intro/movies/directors.csv' AS row 
RETURN count(*);

Inspection - Expected number of ACTED_IN relationships

LOAD CSV FROM 'http://data.neo4j.com/intro/movies/actors.csv' AS row 
RETURN count(*);

Inspection - Visually

LOAD CSV FROM 'http://data.neo4j.com/intro/movies/movies.csv' AS row 
RETURN * LIMIT 5;

Inspection - Visually ... WITH HEADERS

LOAD CSV WITH HEADERS FROM 'http://data.neo4j.com/intro/movies/movies.csv' AS row
RETURN row, keys(row) LIMIT 5;

Inspection - Casting

LOAD CSV WITH HEADERS FROM 'http://data.neo4j.com/intro/movies/movies.csv' AS row
RETURN row.title as title, toInteger(row.released) as released, row.tagline as tagline
ORDER BY released DESC LIMIT 10;

Bulk loading done wrong

LOAD CSV WITH HEADERS FROM 'http://data.neo4j.com/intro/movies/movies.csv' AS row
CREATE (m:Movie {title: row.title, released: toInteger(row.released), tagline: row.tagline})
RETURN m;

Cleanup

CALL apoc.periodic.commit(
 "MATCH ()-[r]->() WITH r LIMIT $limit DELETE r RETURN count(*)",
 {limit:2000}
);
CALL apoc.periodic.commit(
 "MATCH (n) WITH n LIMIT $limit DELETE n RETURN count(*)",
 {limit:2000}
);

Schema first

CREATE CONSTRAINT uc_Movie_title ON (m:Movie) ASSERT m.title IS UNIQUE;
CREATE CONSTRAINT uc_Person_name ON (p:Person) ASSERT p.name IS UNIQUE;

Movie nodes

LOAD CSV WITH HEADERS FROM 'http://data.neo4j.com/intro/movies/movies.csv' AS row
CREATE (:Movie {title: row.title, released: toInteger(row.released), tagline: row.tagline});

Check Movie nodes

MATCH (:Movie) RETURN count(*);

Person nodes

LOAD CSV WITH HEADERS FROM 'http://data.neo4j.com/intro/movies/people.csv' AS row
CREATE (:Person {name: row.name, born: toInteger(row.born)});

Check Person nodes

MATCH (:Person) RETURN count(*);

DIRECTED relationships

LOAD CSV WITH HEADERS FROM 'http://data.neo4j.com/intro/movies/directors.csv' AS row
MATCH (p:Person {name: row.person })
MATCH (m:Movie {title: row.movie})
MERGE (p)-[:DIRECTED]->(m);

Check DIRECTED relationships

MATCH ()-[:DIRECTED]->() RETURN count(*);

ACTED_IN relationships

LOAD CSV WITH HEADERS FROM 'http://data.neo4j.com/intro/movies/actors.csv'
AS row
MATCH (p:Person {name: row.person })
MATCH (m:Movie {title: row.movie})
MERGE (p)-[actedIn:ACTED_IN]->(m)
ON CREATE SET actedIn.roles = split(row.roles,';');

Check ACTED_IN relationships

MATCH ()-[:ACTED_IN]->() RETURN count(*);

Something weird going on here ...

MATCH(p:Person {name: "Tom Hanks"})-[ai:ACTED_IN]-(m:Movie) RETURN p,ai,m;

Something's Gotta Give

MATCH (m:Movie) WHERE m.title STARTS WITH "Something"
RETURN m, keys(m);

Cypher Strikes Back

Finding Tom

MATCH (p:Person {name: "Tom Hanks"})
RETURN p;

Finding Tom II

MATCH (p:Person)
WHERE p.name = "Tom Hanks"
RETURN p;

Analyzing finding Tom

PROFILE MATCH (p:Person {name: "Tom Hanks"})
RETURN p;

Analyzing finding Tom II

PROFILE MATCH (p:Person)
WHERE p.name = "Tom Hanks"
RETURN p;

Analyzing without finding Tom

EXPLAIN MATCH (p:Person {name: "Tom Hanks"})
RETURN p;

Did Tom act with Tom ?

MATCH (p1:Person)-[a1:ACTED_IN]->(m:Movie)<-[a2:ACTED_IN]-(p2:Person)
WHERE p1.name = "Tom Hanks"
AND p2.name = "Tom Cruise"
RETURN p1.name, a1.roles, p2.name, a2.roles, m.title;

Did Tom act with Kevin ?

MATCH (p1:Person)-[a1:ACTED_IN]->(m:Movie)<-[a2:ACTED_IN]-(p2:Person)
WHERE p1.name = "Tom Hanks"
AND p2.name = "Kevin Bacon"
RETURN p1.name, a1.roles, p2.name, a2.roles, m.title;

Create myself as a trainer ...

CREATE (:Trainer {name: "Tom Geudens"});

Cleanup

MATCH (t:Trainer) DELETE t;

Add schema

CREATE CONSTRAINT ON (t:Trainer) ASSERT t.name IS UNIQUE;
CREATE CONSTRAINT ON (t:Training) ASSERT t.title IS UNIQUE;

Create myself as the trainer and create the training

CREATE (:Trainer {name: "Tom Geudens"})
CREATE (:Training {title: "Basics"});

Create the relationship

MATCH (t:Training {title: "Basics"})
MATCH (tr:Trainer {name: "Tom Geudens"})
MERGE (tr)-[te:TEACHES {location: "Online", when: date("2021-06-04")}]->(t)
RETURN tr,te,t;

Just an update?

MATCH (tr:Trainer {name: "Tom Geudens"})-[t:TEACHES]->(f:Training {title: "Basics"})
SET tr.age = 48, t.at = time("10:00:00"), f.duration = duration("PT2H")
RETURN tr, t, f;

Return with a recommendation

Who should play with Tom

MATCH (tom:Person {name: "Tom Hanks"})-[:ACTED_IN]->(m1:Movie)<-[:ACTED_IN]-(coActors:Person)-[:ACTED_IN]->(m2:Movie)<-[:ACTED_IN]-(cocoActors:Person)
WHERE NOT (tom)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors)
AND tom <> cocoActors
RETURN cocoActors.name AS Recommended, count(*) AS Strength ORDER BY Strength DESC;

But it's wrong, isn't it?

MATCH (tom:Person {name: "Tom Hanks"})-[:ACTED_IN]->(m1:Movie)<-[:ACTED_IN]-(coActors:Person)-[:ACTED_IN]->(m2:Movie)<-[:ACTED_IN]-(cocoActors:Person)
WHERE NOT (tom)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors)
AND tom <> cocoActors
RETURN cocoActors.name AS Recommended, collect(coActors.name) as thisiswrong, count(*) AS Strength ORDER BY Strength DESC;

Much better

MATCH (tom:Person {name: "Tom Hanks"})-[:ACTED_IN]->(m1:Movie)<-[:ACTED_IN]-(coActors:Person)-[:ACTED_IN]->(m2:Movie)<-[:ACTED_IN]-(cocoActors:Person)
WHERE NOT (tom)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors)
AND tom <> cocoActors
RETURN cocoActors.name AS Recommended, collect(DISTINCT coActors.name), count(DISTINCT coActors.name) AS Strength ORDER BY Strength DESC;