nosql-bootcamp / marvel-heroes-network

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Marvel Heroes Network

L'objectif de cet exercice est d'analyser les liens entre Heroes et Comics Marvel grâce à la base graphe Neo4J.

Pré-requis

Cet exercice est basé sur la version Neo4j Community Edition 4.3.7.

Voici la procédure d'installation en quelques étapes (pour Linux / MacOS) :

  • Téléchargez Neo4j Community Edition 4.3.7 ici : https://neo4j.com/download-center/#community
  • Dézippez l'archive neo4j-community-4.3.7-unix.tar.gz, par exemple dans le dossier $HOME/progs/neo4j-4.3.7
  • Lancez la console Neo4j via la commande $HOME/progs/neo4j-4.3.7/bin/neo4j console
  • Rendez-vous sur la console Neo4j dans un navigateur, à l'adresse http://localhost:7474/
    • L'utilisateur par défaut est neo4j avec le mot de passe neo4j
    • Lors de la première utilisation de la console, vous devrez modifier le mot de passe de l'utilisateur neo4j

Objectifs de l'exercice

Les objectifs sont les suivants :

  • Créer le graphe des Heroes dans Neo4J, à partir des données disponibles dans le dossier data. Les noeuds du graphe sont soit des Heroes, soit des Comics.
  • Répondre à la question suivante : existe-t-il un Hero qui connait deux Heroes différents qui eux-mêmes ne se connaissent pas ? (un Hero "connait" un autre Hero s'il apparaissent tous les deux dans un même Comic)

Liens utiles

Premiers éléments de solution

Préparation des données

Il est d'abord nécessaire de préparer correctement les fichiers CSV afin de pouvoir les importer avec neo4j-admin import.

Pour cela, 3 scripts de préparation des CSV peuvent être utilisés :

yarn install
mkdir dist
node prepare-heroes.js > dist/heroes.csv
node prepare-comics.js > dist/comics.csv
node prepare-comics-heroes.js > dist/comics-heroes.csv

Ces scripts permettent notamment :

Import des données

L'import peut donc maintenant se faire correctement avec les fichiers "préparés" :

neo4j-admin import --nodes=./dist/heroes.csv --nodes=./dist/comics.csv --relationships=./dist/comics-heroes.csv

Le résultat de l'import devrait être le suivant :

IMPORT DONE in 3s 946ms.
Imported:
  40045 nodes
  75257 relationships
  80090 properties

Tip : la base doit être arrêtée lors de l'import, sinon l'erreur suivante risque de se produire :

org.neo4j.exceptions.UnderlyingStorageException: Unable to open store file: /Users/sebprunier/progs/neo4j/neo4j-community-4.3.7/data/databases/neo4j/neostore
	at org.neo4j.kernel.impl.store.CommonAbstractStore.checkAndLoadStorage(CommonAbstractStore.java:258)
	at org.neo4j.kernel.impl.store.CommonAbstractStore.initialise(CommonAbstractStore.java:156)
	at org.neo4j.kernel.impl.store.NeoStores.initialize(NeoStores.java:262)
	at org.neo4j.kernel.impl.store.NeoStores.createMetadataStore(NeoStores.java:537)
	at org.neo4j.kernel.impl.store.StoreType$15.open(StoreType.java:148)
	at org.neo4j.kernel.impl.store.NeoStores.openStore(NeoStores.java:255)
	at org.neo4j.kernel.impl.store.NeoStores.getOrOpenStore(NeoStores.java:300)
	at org.neo4j.kernel.impl.store.NeoStores.verifyRecordFormat(NeoStores.java:181)
	at org.neo4j.kernel.impl.store.NeoStores.<init>(NeoStores.java:119)
	at org.neo4j.kernel.impl.store.StoreFactory.openNeoStores(StoreFactory.java:138)
	at org.neo4j.kernel.impl.store.StoreFactory.openAllNeoStores(StoreFactory.java:102)
	at org.neo4j.internal.batchimport.store.BatchingNeoStores.instantiateStores(BatchingNeoStores.java:247)
	at org.neo4j.internal.batchimport.store.BatchingNeoStores.createNew(BatchingNeoStores.java:203)
	at org.neo4j.internal.batchimport.ParallelBatchImporter.doImport(ParallelBatchImporter.java:99)
	at org.neo4j.importer.CsvImporter.doImport(CsvImporter.java:193)
	at org.neo4j.importer.CsvImporter.doImport(CsvImporter.java:158)
	at org.neo4j.importer.ImportCommand.execute(ImportCommand.java:256)
	at org.neo4j.cli.AbstractCommand.call(AbstractCommand.java:71)
	at org.neo4j.cli.AbstractCommand.call(AbstractCommand.java:34)
	at picocli.CommandLine.executeUserObject(CommandLine.java:1953)
	at picocli.CommandLine.access$1300(CommandLine.java:145)
	at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2352)
	at picocli.CommandLine$RunLast.handle(CommandLine.java:2346)
	at picocli.CommandLine$RunLast.handle(CommandLine.java:2311)
	at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)
	at picocli.CommandLine.execute(CommandLine.java:2078)
	at org.neo4j.cli.AdminTool.execute(AdminTool.java:89)
	at org.neo4j.cli.AdminTool.main(AdminTool.java:67)
Caused by: org.neo4j.io.pagecache.impl.FileLockException: This file is locked by another process, please ensure you don't have another Neo4j process or tool using it: '/Users/sebprunier/progs/neo4j/neo4j-community-4.3.7/data/databases/neo4j/neostore'.'

Quelques requêtes basiques pour visualiser nos données

Afficher des Heroes

Pour afficher tous les noeuds de type Hero :

MATCH (hero:Hero) 
RETURN hero

On peut limiter le nombre de résultats, comme en SQL :

MATCH (hero:Hero) 
RETURN hero 
LIMIT 5

On peut rechercher un Hero par son nom :

MATCH (hero:Hero {name:"Captain America"}) 
RETURN hero

Des clauses WHERE peuvent être ajoutées, par exemple :

MATCH (hero:Hero) 
WHERE hero.name CONTAINS "Captain" 
RETURN hero

Afficher les Comics d'un Hero

On peut rechercher les Comics d'un Hero en parcourant les relations de type APPEARED_IN. Par exemple pour Jessica Jones :

MATCH (jessica:Hero {name: "Jessica Jones"})-[:APPEARED_IN]->(comic:Comic)
RETURN jessica,comic

Pour simplifier la visualisation, il est possible d'afficher un tableau plutôt qu'un graphe en précisant (un peu comme une projection en SQL), les attributs des Comics que l'on souhaite afficher :

MATCH (jessica:Hero {name: "Jessica Jones"})-[:APPEARED_IN]->(comic:Comic)
RETURN comic.title AS Titre

Plus court chemin

Un besoin classique dans des graphes est la recherche de plus court chemin entre deux noeuds.

Ici par exemple, nous pouvons chercher les plus courts chemins entre deux Heroes, en l'occurrence Punisher et Colossus :

MATCH p=shortestPath(
(punisher:Hero {name:"Punisher"})-[:APPEARED_IN*]-(colossus:Hero {name:"Colossus"})
)
RETURN p

Ce qui nous donne le résultat suivant : Punisher et Colossus sont tous les deux présent dans le Comic intitulé Marvel Fanfare (1982) #45

Réponses à la question

Pour répondre à la question "Existe-t-il un Hero qui connait deux Heros différents qui eux-mêmes ne se connaissent pas ?", un algorithme de type "recommandation" est adatpté.

Voici un exemple de requête permettant de répondre à la question :

MATCH (hero:Hero)-[:APPEARED_IN]->(c1:Comic)<-[:APPEARED_IN]-(coHero:Hero),
  (coHero)-[:APPEARED_IN]->(c2:Comic)<-[:APPEARED_IN]-(cocoHero)
WHERE NOT (hero)-[:APPEARED_IN]->()<-[:APPEARED_IN]-(cocoHero) AND hero <> cocoHero
RETURN DISTINCT hero.name, c1.title, coHero.name, c2.title, cocoHero.name
LIMIT 10

Et voici le résultat :

hero.name c1.title coHero.name c2.title cocoHero.name
Captain America Cable and X-Force (2012) #9 X-Force Cable & X-Force: Onslaught Rising (Trade Paperback) Risque
Captain America Cable and X-Force (2012) #9 X-Force Cable & X-Force: Onslaught Rising (Trade Paperback) Hellfire Club
Captain America Cable and X-Force (2012) #9 X-Force X-Force (1991) #1 Wildside
Captain America Cable and X-Force (2012) #9 X-Force X-Force (1991) #1 Stryfe
Captain America Cable and X-Force (2012) #9 X-Force X-Force (1991) #1 Forearm
Captain America Cable and X-Force (2012) #9 X-Force X-Force (1991) #1 Feral
Captain America Cable and X-Force (2012) #9 X-Force X-Force (1991) #1 Boomer
Captain America Cable and X-Force (2012) #9 X-Force X-Force (1991) #1 Black Tom
Captain America Cable and X-Force (2012) #9 X-Force X-Force (1991) #2 Feral
Captain America Cable and X-Force (2012) #9 X-Force X-Force (1991) #2 Boomer

On peut vérifier les liens entre les héros avec un algorithme de calcul de plus cours chemin, par exemple :

MATCH p=shortestPath(
(h1:Hero {name:"Captain America"})-[:APPEARED_IN*]-(h2:Hero {name:"Stryfe"})
)
RETURN p

About


Languages

Language:JavaScript 100.0%