2017-05-24 7 views
0

Être un Noob absolu dans Neo4j et ayant eu une aide très généreuse avec une question précédente, je pensais que je serais tenter ma chance une fois de plus que je suis toujours en difficulté.Revenant un compte de tous les chemins et complets dans Neo4j

Le scénario exemple est celui des étudiants qui entre dans une maison et des promenades d'une pièce à l'autre. Le voyage ne doit pas nécessairement commencer ou se terminer dans une pièce en particulier, mais l'ordre de la séquence dans laquelle un élève entre dans une pièce est important.

Ce que je veux savoir est tous les chemins complets que les élèves ont pris avec un compte de combien de fois le chemin en question a été prise. Ci-dessous, les données sont des exemples et ce que j'ai essayé (grâce à la réponse d'une question précédente avec une série de messages de blog):

le fichier dorm.csv

ID|SID|EID|ROOM|ENTERS|LEAVES 
1|1|12|BLUE|1/01/2015 11:00|4/01/2015 10:19 
2|2|18|GREEN|1/01/2015 12:11|1/01/2015 12:11 
3|2|18|YELLOW|1/01/2015 12:11|1/01/2015 12:20 
4|2|18|BLUE|1/01/2015 12:20|5/01/2015 10:48 
5|3|28|GREEN|1/01/2015 18:41|1/01/2015 18:41 
6|3|28|YELLOW|1/01/2015 18:41|1/01/2015 21:00 
7|3|28|BLUE|1/01/2015 21:00|9/01/2015 9:30 
8|4|36|BLUE|1/01/2015 19:30|3/01/2015 11:00 
9|5|40|GREEN|2/01/2015 19:08|2/01/2015 19:08 
10|5|40|ORANGE|2/01/2015 19:08|3/01/2015 2:43 
11|5|40|PURPLE|3/01/2015 2:43|4/01/2015 16:44 
12|6|48|GREEN|3/01/2015 11:52|3/01/2015 11:52 
13|6|48|YELLOW|3/01/2015 11:52|3/01/2015 17:45 
14|6|48|RED|3/01/2015 17:45|7/01/2015 10:00 

création de nœuds pour étudiants, chambre et visite où visite est le cas d'un étudiant entrant dans une pièce unique identifiée par la propriété ID

CREATE CONSTRAINT ON (student:Student) ASSERT student.studentID IS UNIQUE; 
CREATE CONSTRAINT ON (room:Room) ASSERT room.roomID IS UNIQUE; 
CREATE CONSTRAINT ON (visit:Visit) ASSERT visit.visitID IS UNIQUE; 


USING PERIODIC COMMIT 
LOAD CSV WITH HEADERS FROM "file:///dorm.csv" as line fieldterminator '|' 
MERGE (student:Student {studentID: line.SID}) 
MERGE (room:Room {roomID: line.ROOM}) 
MERGE (visit:Visit {visitID: line.ID, roomID: line.ROOM, studentID: line.SID, ticketID: line.EID}) 
create (student)-[:VERB]->(visit)-[:OBJECT]->(room) 

Création d'une relation PREV permet la commande ou le séquençage que l'étudiant se déplace. Cela utilise des données dans le fichier dormprev. CSV. Si un étudiant n'a visité qu'une seule pièce, cet identifiant n'apparaîtra pas dans le fichier dormprev car son but est de lier les visites en chaîne. Les données ci-dessous comme

ID|PREV_ID|EID 
3|2|18 
4|3|18 
6|5|28 
7|6|28 
10|9|40 
11|10|40 
13|12|48 
14|13|48 

USING PERIODIC COMMIT 
LOAD CSV WITH HEADERS FROM "file:///dormprev.csv" as line fieldterminator '|' 
MATCH (new:Visit {visitID: line.ID}) 
MATCH (old:Visit {visitID: line.PREV_ID}) 
MERGE (new)-[:PREV]->(old) 

je peux voir tous les voyages d'étudiants par la requête ci-dessous

MATCH (student:Student)-[:VERB]->(visit:Visit)-[:OBJECT]-(room:Room) 
RETURN student, visit, room 

Cependant, je ne sais pas comment retourner toutes les chambres dans un chemin complet.

si je lance cette requête

MATCH p = (:Visit)<-[:PREV]-(:Visit) return p 

Je peux voir que, par exemple, pour les étudiants ID 2 retourne vert et jaune puis jaune et bleu comme une paire séparée - je veux voir que le vert , Jaune, Bleu

Cela signifie aussi que si je lance la requête suivante:

MATCH p = (:Visit)<-[:PREV]-(:Visit) 
WITH p, EXTRACT(v IN NODES(p) | v.roomID) AS rooms 
UNWIND rooms AS stays 
WITH p, COUNT(DISTINCT stays) AS distinct_stays 
WHERE distinct_stays = LENGTH(NODES(p)) 
RETURN EXTRACT(v in NODES(p) | v.roomID), count(p) 
ORDER BY count(p) DESC 

il retournera un compte de ces appariements plutôt que le nombre de « chemins entiers » si cela fait sens e.

Par exemple, SID 2 et SID 3 les deux chambres de visite vert, jaune, bleu dans cet ordre. SID 5 visites VERT, ORANGE, VIOLET dans cet ordre.

Ce que je suis l'espoir de voir est:

[GREEN, YELLOW, BLUE] 2 
[GREEN, ORANGE, PURPLE] 1 

etc. Est-ce possible avec le modèle ci-dessus et si oui quelqu'un peut-il aider s'il vous plaît me diriger dans la bonne direction? Le nombre de chambres visitées n'est pas garanti et peut aller de un à *. Cependant, si une seule pièce est visitée, ce n'est pas vraiment intéressant et c'est la raison pour laquelle j'ai pensé que ce modèle pourrait avoir du sens (encore une fois, volé dans une série de billets de blog). Je ne sais pas si ce qui précède a du sens, mais toute aide serait très appréciée - ce qui en fait un excellent cas d'utilisation et serait vraiment utile.

Nous vous remercions de votre aide.

Répondre

0

Ce que je pense que vous cherchez est la longueur du chemin variable. Et vous pouvez accomplir cela en changeant simplement dans votre requête (notez l'astérisque):

MATCH p = (:Visit)<-[:PREV*]-(:Visit) 

ne me permettent quelques remarques supplémentaires. Oui, je comprends la commodité d'avoir roomID et studentID dans le nœud Visit (cela simplifie énormément cette requête), mais vous ignorez tout d'abord le fait d'avoir des relations (en fait, si vous le faites de cette manière il n'y a actuellement aucun intérêt à avoir les nœuds Student et Room du tout) et vous aurez du mal à les maintenir. En second lieu ... si nous allons diviser les 3e poils de forme normale proverbiale ;-), alors les relations pour une visite devraient effectivement être créés comme suit (notez la direction des relations):

CREATE (student)-[:VERB]->(visit)<-[:OBJECT]-(room) 

Autre que je dois dire que vous vous déplacez très vite :-)

Hope this helps, Tom

+0

Merci tas Tom, très apprécié! Il y a une blague à faire au sujet des relations et je fais preuve d'une retenue remarquable en m'abstenant ;-) J'ai dû suivre quelque chose d'autre en ce moment mais j'espère pouvoir regarder ça le week-end. En ce qui concerne le changement de longueur de la requête, j'imagine que cela résoudrait presque le problème mais cela n'inclurait-il pas aussi des sous-chemins alors que je ne m'intéresse qu'au voyage "complet"? Autrement dit, G Y B serait compté trois fois avec cette requête, [{G, Y}, {Y, B}, {GYB}] au lieu de simplement GYB. Merci, Tom. Va poster lundi – c95mbq

+0

Oui, il y a définitivement "un point aux relations" :-). Quoi qu'il en soit, vous pouvez ajouter des exigences supplémentaires afin que le point de départ n'ait pas de [: PREV] entrant et que le point final n'ait pas de [: PREV] sortant. Cela assurerait que vous obtenez seulement des voyages complets. –

+0

J'ai fini par changer les choses et j'ai créé un NEXT au lieu de PREV. Votre commentaire avec un autre post SO que je suis tombé a abouti à la requête ci-dessous, qui semble retourner le résultat attendu, au moins avec les petites données de l'échantillon: 'MATCH p = (de: Visit) - [: NEXT *] - > (to: Visit) où not ((à) - [: NEXT] ->()) et non (() - [: NEXT] -> (à partir de)) AVEC p, EXTRACT (v IN NODES (p) | v.roomID) AS chambres chambres de délasser et AS reste AVEC p, COUNT (séjour DISTINCTS) AS distinct_stays OU distinct_stays = longueur (nodes (p)) EXTRACT RETURN (v dans nodes (p) | v.roomID), compte (p) ' Merci pour votre aide! – c95mbq

0

Construire un peu sur les suggestions de Tom, vous pourriez envisager un autre modèle supprimant: Visitez nœuds complètement, et faire vos types de relations sont un peu plus concentrés, comme ceci:

(:Student)-[:VISITED]->(:Room) 

Vous pouvez définir les propriétés entrées et à gauche sur la relation: VISITED, ce qui vous permettra de classer les relations (et les pièces correspondantes) dans l'ordre visité.

Voici une importation alternative qui va le faire, en utilisant APOC Procedures (vous devrez installer la version correcte correspondant à votre version Neo4j) pour analyser les horodatages de vos chaînes de date.

USING PERIODIC COMMIT 
LOAD CSV WITH HEADERS FROM "file:///dorm.csv" as line fieldterminator '|' 
MERGE (student:Student {studentID: line.SID}) 
MERGE (room:Room {roomID: line.ROOM}) 
WITH student, room, apoc.date.parse(line.ENTERS, 'ms', 'MM/dd/yyyy HH:mm') as entered, apoc.date.parse(line.LEAVES, 'ms', 'MM/dd/yyyy HH:mm') as left 
CREATE (student)-[r:VISITED]->(room) 
SET r.entered = entered, r.left = left 

Et maintenant votre requête pour obtenir tous les chemins et le nombre d'étudiants qui ont pris ces chemins devient très facile:

MATCH (s:Student)-[v:VISITED]->(r:Room) 
WHERE size((s)-[:VISITED]->()) > 1 
WITH s, r 
ORDER BY v.entered ASC 
WITH s, collect(r.roomID) as rooms 
RETURN rooms, count(s) 
+0

Merci pour votre aide InverseFalcon, très appréciée.Je n'ai pas encore eu l'occasion de le tester, mais j'espère le faire dans les prochains jours et je reviendrai. L'aide de Toi et Tom est incroyablement importante pour les noobs comme moi. Ayant travaillé avec SQL pendant si longtemps, j'ai du mal à comprendre cela et j'attends toujours le moment de l'ampoule. Semble être d'une valeur si indéniable que cela vaut la peine de persister et qu'une aide aussi amicale et généreuse va un long chemin. Je reviendrai dès que j'aurai l'occasion d'y revenir. A bientôt – c95mbq

+0

Content de vous aider! Vous pouvez également considérer le [slack] des utilisateurs de neo4j (https://neo4j.com/developer/slack/) pour des ressources et des conseils supplémentaires. Assurez-vous également de passer par certains des tutoriels intégrés offerts par le navigateur neo4j lui-même, ceux-ci sont assez riches! – InverseFalcon

+0

Merci InverseFalcon. Je me suis inscrit sur le mou et je suis sûr que ça va être d'une grande utilité. Je pense que j'ai attrapé la mauvaise version apoc comme je n'étais pas en mesure de tester votre requête, mais je suis certainement en train de la revisiter quand les choses s'arrangent un peu. Déchiré soit d'accepter le vôtre ou la réponse de Tom, mais est allé avec Tom, j'aimerais pouvoir choisir les deux! Merci pour votre aide, encore une fois, va revoir apoc et votre solution quand les choses sont plus calmes. Cheers – c95mbq