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;