Training GDS Graph Catalog - tomgeudens/practical-neo4j GitHub Wiki
Context: Cut-and-paste commands for the Graph Data Science - Graph Catalog session.
Prerequisite: This document will assume you have a Neo4j instance running and are connected to it with the Neo4j Browser. You also need to have the Game of Thrones database loaded.
Setup
001
// Make sure you're in the correct database
:use gameofthrones
Trying Mode I
002
// Estimate required memory first
CALL gds.pageRank.stream.estimate({
nodeProjection: "Person",
relationshipProjection: "INTERACTS"
}) YIELD requiredMemory, nodeCount, relationshipCount
RETURN *;
003
// We want Jon Snow
CALL gds.pageRank.stream({
nodeProjection: "Person",
relationshipProjection: "INTERACTS"
}) YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC, name ASC
LIMIT 10;
Trying Mode II
004
// Estimate required memory first
CALL gds.pageRank.stream.estimate({
nodeQuery: "MATCH (p:Person) RETURN id(p) AS id",
relationshipQuery: "MATCH (p1:Person)-[]->(:Battle)<-[]-(p2:Person) RETURN id(p1) AS source, id(p2) AS target"
}) YIELD requiredMemory, nodeCount, relationshipCount
RETURN *;
005
// Let the brutes come out on top ...
CALL gds.pageRank.stream({
nodeQuery: "MATCH (p:Person) RETURN id(p) AS id",
relationshipQuery: "MATCH (p1:Person)-[]->(:Battle)<-[]-(p2:Person) RETURN id(p1) AS source, id(p2) AS target"
}) YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC, name ASC
LIMIT 10;
Trying Mode III
006
// Estimate required memory first
CALL gds.graph.create.cypher.estimate(
"MATCH (p:Person) RETURN id(p) AS id",
"MATCH (p1:Person)-[]->(:Battle)<-[]-(p2:Person) RETURN id(p1) AS source, id(p2) AS target"
) YIELD requiredMemory, nodeCount, relationshipCount
RETURN *;
007
// Create the graph that lets the brutes come out on top
CALL gds.graph.create.cypher(
"gds-brutes",
"MATCH (p:Person) RETURN id(p) AS id",
"MATCH (p1:Person)-[]->(:Battle)<-[]-(p2:Person) RETURN id(p1) AS source, id(p2) AS target"
) YIELD graphName, nodeCount, relationshipCount
RETURN *;
008
// Let the brutes come out on top ...
CALL gds.pageRank.stream('gds-brutes') YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC, name ASC
LIMIT 10;
009
// Most central amongst the brutes
CALL gds.betweenness.stream('gds-brutes') YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC, name ASC
LIMIT 10;
Trying Mode IV
010
// Estimate required memory first
CALL gds.graph.create.estimate(
"Person",
"INTERACTS"
) YIELD requiredMemory, nodeCount, relationshipCount
RETURN *;
011
// Create the graph that should get us Jon Snow
CALL gds.graph.create(
"gds-interaction",
"Person",
"INTERACTS"
) YIELD graphName, nodeCount, relationshipCount
RETURN *;
012
// Pagerank doesn't give us Jon
CALL gds.pageRank.stream('gds-interaction') YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC, name ASC
LIMIT 10;
013
// Maybe betweenness does
CALL gds.betweenness.stream('gds-interaction') YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC, name ASC
LIMIT 10;
Graph Catalog Management
014
// I wonder what list() does
CALL gds.graph.list();
015
// Examining the brutes projection ...
CALL gds.graph.list('gds-brutes');
016
// Examining the interaction projection ...
CALL gds.graph.list('gds-interaction');
017
// Drop the interaction projection
CALL gds.graph.drop('gds-interaction');
018
// Verify the drop() worked
CALL gds.graph.list();
019
// A peek in the kitchen
CALL gds.debug.sysInfo();
Native Projection versus Cypher Projection
020
// Plumbing 101
CALL gds.pageRank.stream({
nodeProjection: "Person",
relationshipProjection: {
INTERACTS: {
type: "INTERACTS",
orientation: "UNDIRECTED"
}
}
}) YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC, name ASC
LIMIT 20;
Mutability
021
// Creating a bipartite graph for houses
CALL gds.graph.create('house-bipartite',
['House','Person'],
{ HAS_MEMBER: { type: 'BELONGS_TO', orientation: 'REVERSE'}});
022
// How similar are the houses ... 5% is the minimum
CALL gds.nodeSimilarity.mutate('house-bipartite', {
similarityCutoff: 0.05,
mutateRelationshipType: 'SIMILAR',
mutateProperty: 'score'
});
023
// Write back the community number to the database
CALL gds.louvain.write('house-bipartite', { writeProperty: 'community'});
024
// Show time
MATCH (x:House)
WITH x.community as community, count(*) as members, collect(x.name) as membernames
RETURN * ORDER BY members DESC LIMIT 10;
Cleanup
025
// Cleaning up the projections
CALL gds.graph.list()
YIELD graphName AS namedGraph
WITH namedGraph
CALL gds.graph.drop(namedGraph)
YIELD graphName
RETURN graphName;