Nœud de retour si la relation n'est pas présente

88

J'essaie de créer une requête en utilisant un chiffrement qui «trouvera» les ingrédients manquants qu'un chef pourrait avoir, mon graphique est configuré comme suit:

(ingredient_value)-[:is_part_of]->(ingredient)

(ingredient)aurait une clé / valeur de nom = "couleurs de teinture". (ingredient_value)pourrait avoir une clé / valeur de valeur = "rouge" et "fait partie de" le (ingredient, name="dye colors").

(chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)

J'utilise cette requête pour obtenir toutes les ingredientsvaleurs, mais pas leurs valeurs réelles, requises par une recette, mais je voudrais le retour uniquement de ce ingredientsque le chef n'a pas, au lieu de tous les ingrédients requis par chaque recette. j'ai essayé

(chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)<-[:has_ingredient*0..0]-chef

mais cela ne retourna rien.

Est-ce quelque chose qui peut être accompli par cypher / neo4j ou est-ce quelque chose qui est mieux géré en retournant tous les ingrédients et en les triant moi-même?

Bonus: il existe également un moyen d'utiliser le chiffrement pour faire correspondre toutes les valeurs d'un chef à toutes les valeurs requises par une recette. Jusqu'à présent, je n'ai renvoyé que toutes les correspondances partielles renvoyées par a chef-[:has_value]->ingredient_value<-[:requires_value]-recipeet j'ai agrégé les résultats moi-même.

Nicolas
la source
Consultez ici les informations relatives à la v3: stackoverflow.com/questions/25673223/…
Maciej
Pour les futurs utilisateurs; peut utiliser existsdans une WHEREclause (également l'annuler), neo4j.com/developer/subqueries/#existential-subqueries pour plus d'informations.
ozanmuyes

Réponses:

157

Mise à jour du 01/10/2013:

Je suis tombé sur cela dans la référence Neo4j 2.0 :

Essayez de ne pas utiliser de relations facultatives. Par dessus tout,

ne les utilisez pas comme ceci:

MATCH a-[r?:LOVES]->() WHERE r IS NULL où vous vous assurez simplement qu'ils n'existent pas.

Faites plutôt ceci comme ceci:

MATCH a WHERE NOT (a)-[:LOVES]->()

Utilisation de chiffrement pour vérifier si la relation n'existe pas:

...
MATCH source-[r?:someType]-target
WHERE r is null
RETURN source

Le ? mark rend la relation facultative.

OU

Dans neo4j 2, faites:

...
OPTIONAL MATCH source-[r:someType]-target
WHERE r is null
RETURN source

Vous pouvez maintenant rechercher une relation non existante (nulle).

Gil Stal
la source
3
Dans Neo4j 2.0, utilisez OPTIONAL MATCH pour faire correspondre les relations optionnelles, c'est-à-dire que le premier exemple ressemblerait à OPTIONAL MATCH (source) - [r: someType] - (target) RETURN source, r
boggle
J'essaie d'avoir un nœud étiqueté WHERE NOT, cela ne fonctionne pas. Comme: MATCH a WHERE NOT (a) - [: LOVES] -> (Stranger), dans ce «Stranger» est une étiquette de nœud. J'utilise neo4j version 2.1.2
Krishna Shetty
1
Peu importe
4
L' MATCH a...exemple devrait maintenant êtreMATCH (a) WHERE NOT (a)-[:LOVES]->()
Liam
1
@ gil-stal Pourquoi je ne peux pas utiliser le nom du nœud avec cette requête comme ceci. MATCH a WHERE NOT (a) - [: LOVES] -> (b: SomeLabel). Si je n'utilise pas de nom de nœud, cela fonctionne.
iit2011081
15

Pour récupérer des nœuds sans aucune relation

C'est la bonne option pour vérifier que la relation existe ou non

MATCH (player)
    WHERE NOT(player)-[:played]->()
    RETURN player

Vous pouvez également vérifier plusieurs conditions pour cela. Il renverra tous les nœuds, qui n'ont pas de relation "joué" ou "non joué".

MATCH (player) 
 WHERE NOT (player)-[:played|notPlayed]->()
 RETURN player

Pour récupérer des nœuds qui n'ont pas de relation réelle

MATCH (player) 
WHERE NOT (player)-[r]-()
RETURN player

Il vérifiera que le nœud n'a aucune relation entrante / sortante.

Satish Shinde
la source
4
MATCH (player) WHERE NOT (player)-[r]-() RETURN player donne une erreur de variable r non définie . Comment définir r?
Chathura Wijeweera
pour résoudre ce problème, spécifiez une relation (par exemple (player -[:rel]- ()) ou laissez vide pour toute relation(player -[]- ()
Archemar
MATCH (player) WHERE NOT (player)-[]-() RETURN player- Cela fonctionne bien
Prashanth Terala
Votre première requête est en fait erronée. Le modèle MATCH lui-même renvoie toujours uniquement les relations existantes, aucune d'elles n'étant NULL. Donc, votre ligne WHERE n'a rien à filtrer.
Cristi S.
@CristiS. Merci de me le faire savoir. J'ai mis à jour la requête, cela devrait fonctionner
Satish Shinde
8

Si vous avez besoin d'une sémantique "d'exclusion conditionnelle", vous pouvez y parvenir de cette façon.

À partir de neo4j 2.2.1, vous pouvez utiliser la OPTIONAL MATCHclause et filtrer les NULLnœuds sans correspondance ( ).

Il est également important d'utiliser une WITHclause entre les clauses OPTIONAL MATCHet WHERE, afin que la première WHEREdéfinisse une condition pour la correspondance facultative et la seconde WHEREse comporte comme un filtre.

En supposant que nous ayons 2 types de nœuds: Personet Communication. Si je veux obtenir toutes les personnes qui n'ont jamais communiqué par téléphone, mais qui ont pu communiquer par d'autres moyens, je ferais cette requête:

MATCH (p: Person) 
OPTIONAL MATCH p--(c: Communication) 
WHERE c.way = 'telephone'
WITH p, c 
WHERE c IS NULL 
RETURN p

Le modèle de correspondance correspondra à toutes les personnes avec leurs communications où csera NULLpour les communications non téléphoniques. Puis le filtre ( WHEREaprèsWITH ) filtrera les communications téléphoniques en laissant toutes les autres.

Références:

http://neo4j.com/docs/stable/query-optional-match.html#_introduction_3 http://java.dzone.com/articles/new-neo4j-optional

Dieter Pisarewski
la source
2

J'ai écrit un résumé montrant comment cela peut être fait assez naturellement en utilisant Cypher 2.0

http://gist.neo4j.org/?9171581

Le point clé est d'utiliser une correspondance facultative avec les ingrédients disponibles, puis de comparer pour filtrer les ingrédients manquants (nuls) ou les ingrédients avec la mauvaise valeur.

Notez que la notion est déclarative et n'a pas besoin de décrire un algorithme, vous écrivez simplement ce dont vous avez besoin.

boggle
la source
2

J'ai terminé cette tâche en utilisant gremlin. J'ai fait

x=[]

g.idx('Chef')[[name:'chef1']].as('chef')
.out('has_ingredient').as('alreadyHas').aggregate(x).back('chef')
.out('has_value').as('values')
.in('requires_value').as('recipes')
.out('requires_ingredient').as('ingredients').except(x).path()

Cela a renvoyé les chemins de tous les ingrédients manquants. Je n'ai pas pu formuler cela en langage chiffré, du moins pour la version 1.7.

Nicolas
la source
2

La dernière requête doit être:

START chef = node(..)
MATCH (chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)
WHERE (ingredient)<-[:has_ingredient]-chef
RETURN ingredient

Ce modèle: (ingredient)<-[:has_ingredient*0..0]-chef

C'est la raison pour laquelle il n'a rien retourné. *0..0signifie que la longueur des relations doit être nulle, ce qui signifie que l'ingrédient et le chef doivent être le même nœud, ce qu'ils ne sont pas.

Andrés
la source
Oui, mais cela ne renvoie pas l'ingrédient souhaité. Il renvoie ce que le chef a déjà en commun avec la recette, je veux découvrir la différence.
Nicholas