Rückgabeknoten, wenn keine Beziehung vorhanden ist

86

Ich versuche, mit Cypher eine Abfrage zu erstellen, die fehlende Zutaten, die ein Koch möglicherweise hat, "findet". Mein Diagramm ist folgendermaßen eingerichtet:

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

(ingredient)hätte einen Schlüssel / Wert von name = "Farbstofffarben". (ingredient_value)könnte einen Schlüssel / Wert von value = "red" haben und "is part of" the (ingredient, name="dye colors").

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

Ich verwende diese Abfrage, um alle ingredients, aber nicht die tatsächlichen Werte zu erhalten, die ein Rezept erfordert, aber ich möchte, dass nur die zurückgegeben werden ingredients, die der Küchenchef nicht hat, anstelle aller Zutaten, die jedes Rezept benötigt. Ich habe es versucht

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

aber das gab nichts zurück.

Ist dies etwas, das von cypher / neo4j erreicht werden kann, oder ist dies etwas, das am besten gehandhabt werden kann, indem alle Zutaten zurückgegeben und selbst sortiert werden?

Bonus: Es gibt auch eine Möglichkeit, mit Chiffre alle Werte, die ein Koch hat, mit allen Werten abzugleichen, die ein Rezept benötigt. Bisher habe ich nur alle Teilübereinstimmungen zurückgegeben, die von a zurückgegeben werden, chef-[:has_value]->ingredient_value<-[:requires_value]-recipeund die Ergebnisse selbst aggregiert.

Nikolaus
quelle
Überprüfen Sie hier für Informationen, die für v3 relevant sind: stackoverflow.com/questions/25673223/…
Maciej
Für zukünftige Benutzer; kann existsin einer WHEREKlausel (auch negieren) auch neo4j.com/developer/subqueries/#existential-subqueries für weitere Informationen verwenden.
Ozanmuyes

Antworten:

156

Update 10.01.2013:

Ist in der Neo4j 2.0- Referenz darauf gestoßen :

Versuchen Sie, keine optionalen Beziehungen zu verwenden. Über alles,

benutze sie nicht so:

MATCH a-[r?:LOVES]->() WHERE r IS NULL wo Sie nur sicherstellen, dass sie nicht existieren.

Tun Sie dies stattdessen so:

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

Verwenden von cypher zum Überprüfen, ob keine Beziehung besteht:

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

Das ? mark macht die Beziehung optional.

ODER

In neo4j 2 mache ich:

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

Jetzt können Sie nach nicht vorhandenen (Null-) Beziehungen suchen.

Gil Stal
quelle
3
Verwenden Sie in Neo4j 2.0 OPTIONAL MATCH, um optionale Beziehungen abzugleichen, dh das erste Beispiel würde wie folgt aussehen: OPTIONAL MATCH (Quelle) - [r: someType] - (Ziel) RETURN-Quelle, r
boggle
Ich versuche, einen beschrifteten Knoten in WHERE NOT zu haben, es funktioniert nicht. Wie: MATCH a WHERE NOT (a) - [: LOVES] -> (Stranger), in diesem 'Stranger' ist eine Knotenbezeichnung. Ich benutze neo4j Version 2.1.2
Krishna Shetty
1
Egal, ich verstehe, warum Sie den Fortschritt zeigen möchten, um diese Antwort zu erreichen: MATCH a WHERE NOT (a) - [: LOVES] -> ()
NumenorForLife
4
Das MATCH a...Beispiel sollte jetzt seinMATCH (a) WHERE NOT (a)-[:LOVES]->()
Liam
1
@ gil-stal Warum ich bei dieser Abfrage keinen Knotennamen verwenden kann. MATCH a WO NICHT (a) - [: LOVES] -> (b: SomeLabel). Wenn ich keinen Knotennamen verwende, funktioniert es.
iit2011081
14

Zum Abrufen von Knoten ohne Beziehung

Dies ist die gute Option, um zu überprüfen, ob eine Beziehung besteht oder nicht

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

Sie können auch mehrere Bedingungen dafür überprüfen. Es werden alle Knoten zurückgegeben, die keine Beziehung "gespielt" oder "nicht gespielt" haben.

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

Knoten abrufen, die keine Beziehung haben

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

Es wird überprüft, ob der Knoten keine eingehende / ausgehende Beziehung hat.

Satish Shinde
quelle
4
MATCH (player) WHERE NOT (player)-[r]-() RETURN player gibt Variable r nicht definierten Fehler. Wie kann ich r definieren?
Chathura Wijeweera
Um dies zu beheben, geben Sie entweder eine Beziehung an (z. B. (player -[:rel]- ()) oder lassen Sie sie für eine Beziehung leer(player -[]- ()
Archemar
MATCH (player) WHERE NOT (player)-[]-() RETURN player- Es funktioniert gut
Prashanth Terala
Ihre erste Anfrage ist tatsächlich falsch. Das MATCH-Muster selbst gibt immer nur vorhandene Beziehungen zurück, von denen keine NULL ist. Ihre WHERE-Zeile hat also nichts zu filtern.
Cristi S.
@CristiS. Danke für die Information. Ich habe die Abfrage aktualisiert, die funktionieren sollte
Satish Shinde
8

Wenn Sie eine "bedingte Ausschluss" -Semantik benötigen, können Sie dies auf diese Weise erreichen.

Ab neo4j 2.2.1 können Sie OPTIONAL MATCHKlausel verwenden und die nicht übereinstimmenden ( NULL) Knoten herausfiltern .

Es ist auch wichtig, eine WITHKlausel zwischen den Klauseln OPTIONAL MATCHund zu verwenden WHERE, damit die erste WHEREeine Bedingung für die optionale Übereinstimmung definiert und die zweite WHEREsich wie ein Filter verhält.

Angenommen, wir haben zwei Arten von Knoten: Personund Communication. Wenn ich alle Personen erhalten möchte, die noch nie telefonisch kommuniziert haben, aber möglicherweise auf andere Weise kommuniziert haben, würde ich folgende Abfrage stellen:

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

Das Übereinstimmungsmuster stimmt alle Personen mit ihrer Kommunikation überein, wo cdies NULLfür nicht-telefonische Kommunikation vorgesehen ist. Dann filtert der Filter ( WHEREnachher WITH) die Telefonkommunikation heraus und lässt alle anderen übrig.

Verweise:

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

Dieter Pisarewski
quelle
2

Ich habe eine Zusammenfassung geschrieben, die zeigt, wie dies mit Cypher 2.0 ganz natürlich gemacht werden kann

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

Der entscheidende Punkt ist, die optionale Übereinstimmung mit verfügbaren Zutaten zu verwenden und diese dann mit dem Filter für fehlende (Null-) Zutaten oder Zutaten mit dem falschen Wert zu vergleichen.

Beachten Sie, dass der Begriff deklarativ ist und keinen Algorithmus beschreiben muss. Schreiben Sie einfach auf, was Sie benötigen.

boggle
quelle
2

Ich habe diese Aufgabe mit Gremlin erledigt. Ich tat

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()

Dies gab die Wege aller fehlenden Zutaten zurück. Ich konnte dies zumindest für Version 1.7 nicht in der Chiffriersprache formulieren.

Nikolaus
quelle
2

Die letzte Abfrage sollte lauten:

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

Dieses Muster: (ingredient)<-[:has_ingredient*0..0]-chef

Ist der Grund, warum es nichts zurückgegeben hat. *0..0bedeutet, dass die Länge der Beziehungen Null sein muss, was bedeutet, dass Zutat und Koch derselbe Knoten sein müssen, der sie nicht sind.

Andres
quelle
Ja, aber es wird nicht die gewünschte Zutat zurückgegeben. Es gibt zurück, was der Koch bereits mit dem Rezept gemeinsam hat. Ich möchte den Unterschied herausfinden.
Nicholas