Węzeł zwrotny, jeśli relacja nie istnieje

88

Próbuję utworzyć zapytanie za pomocą szyfru, które pozwoli „znaleźć” brakujące składniki, które może mieć szef kuchni. Mój wykres wygląda następująco:

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

(ingredient)miałby klucz / wartość nazwa = "kolory barwnika". (ingredient_value)może mieć klucz / wartość wartość = „czerwony” i „jest częścią” (ingredient, name="dye colors").

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

Używam tego zapytania, aby uzyskać wszystkie ingredientswymagane przez przepis wartości, ale nie ich rzeczywiste wartości, ale chciałbym zwrócić tylko to ingredients, czego szef kuchni nie ma, zamiast wszystkich składników wymaganych w każdym przepisie. próbowałem

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

ale to nic nie zwróciło.

Czy jest to coś, co można osiągnąć za pomocą cypher / neo4j, czy jest to coś, z czym najlepiej sobie poradzić, zwracając wszystkie składniki i samodzielnie je przeglądając?

Bonus: istnieje również sposób, aby użyć szyfrowania, aby dopasować wszystkie wartości, które ma szef kuchni, do wszystkich wartości, których wymaga przepis. Do tej pory zwracałem tylko wszystkie częściowe dopasowania, które są zwracane przez a, chef-[:has_value]->ingredient_value<-[:requires_value]-recipei sam agregowałem wyniki.

Mikołaja
źródło
Sprawdź tutaj, aby uzyskać informacje dotyczące wersji 3: stackoverflow.com/questions/25673223/…
Maciej
Dla przyszłych użytkowników; można użyć existsw WHEREklauzuli (również ją zanegować), neo4j.com/developer/subqueries/#existential-subqueries, aby uzyskać więcej informacji.
ozanmuyes

Odpowiedzi:

157

Aktualizacja 10.01.2013:

Spotkałem się z tym w referencji Neo4j 2.0 :

Staraj się nie używać opcjonalnych relacji. Ponad wszystko,

nie używaj ich w ten sposób:

MATCH a-[r?:LOVES]->() WHERE r IS NULL gdzie po prostu upewniasz się, że nie istnieją.

Zamiast tego zrób to tak:

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

Używanie cyphera do sprawdzania, czy związek nie istnieje:

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

The? znak sprawia, że ​​relacja jest opcjonalna.

LUB

W neo4j 2 zrób:

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

Teraz możesz sprawdzić nieistniejącą (zerową) relację.

Gil Stal
źródło
3
W Neo4j 2.0 użyj DOPASOWANIA OPCJONALNEGO, aby dopasować opcjonalne relacje, tj. Pierwszy przykład będzie wyglądał następująco: DOPASOWANIE OPCJONALNE (źródło) - [r: jakiśTyp] - (cel) RETURN źródło, r
boggle
Próbuję mieć oznaczony węzeł w GDZIE NIE, to nie działa. Na przykład: MATCH a WHERE NOT (a) - [: LOVES] -> (Stranger), w tym „Stranger” jest etykietą węzła. Używam neo4j w wersji 2.1.2
Krishna Shetty,
1
Nieważne, rozumiem, dlaczego chcesz pokazać postęp, aby osiągnąć tę odpowiedź: MATCH a WHERE NOT (a) - [: LOVES] -> ()
NumenorForLife Kwietnia
4
MATCH a...Przykład powinien być terazMATCH (a) WHERE NOT (a)-[:LOVES]->()
Liam
1
@ gil-stal Dlaczego nie mogę użyć nazwy węzła w takim zapytaniu. DOPASUJ GDZIE NIE (a) - [: LOVES] -> (b: SomeLabel). Jeśli nie używam nazwy węzła, to działa.
iit2011081
15

Do pobierania węzłów bez relacji

Jest to dobra opcja, aby sprawdzić, czy związek istnieje, czy nie

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

Możesz również sprawdzić wiele warunków dla tego. Zwróci wszystkie węzły, które nie „grały” lub „nie odtwarzały” relacji.

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

Aby pobrać węzły, które nie mają żadnych powiązań

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

Sprawdza, czy węzeł nie ma żadnych relacji przychodzących / wychodzących.

Satish Shinde
źródło
4
MATCH (player) WHERE NOT (player)-[r]-() RETURN player daje Zmienna r niezdefiniowany błąd. Jak mogę zdefiniować r?
Chathura Wijeweera
aby to naprawić, podaj relację (np. (player -[:rel]- ()) lub pozostaw puste dla dowolnej relacji(player -[]- ()
Archemar
MATCH (player) WHERE NOT (player)-[]-() RETURN player- Działa dobrze
Prashanth Terala
Twoje pierwsze zapytanie jest faktycznie błędne. Sam wzorzec MATCH zawsze zwraca tylko istniejące relacje, przy czym żadna z nich nie ma wartości NULL. Więc twoja linia WHERE nie ma nic do filtrowania.
Cristi S.
@CristiS. Dzięki, że dałeś mi znać. Zaktualizowałem zapytanie, które powinno działać
Satish Shinde
8

Jeśli potrzebujesz semantyki „warunkowe wykluczenie”, możesz to osiągnąć w ten sposób.

Począwszy od neo4j 2.2.1, możesz używać OPTIONAL MATCHklauzuli i odfiltrowywać NULLwęzły unmatched ( ).

Ważne jest również użycie WITHklauzuli między klauzulami OPTIONAL MATCHi WHERE, tak aby pierwsza WHEREdefiniowała warunek opcjonalnego dopasowania, a druga WHEREzachowywała się jak filtr.

Zakładając, że mamy 2 typy węzłów: Personi Communication. Jeśli chcę uzyskać wszystkie Osoby, które nigdy nie rozmawiały przez telefon, ale mogły porozumiewać się w inny sposób, zadałbym następujące pytanie:

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

Wzorzec dopasowania będzie pasował do wszystkich osób z ich komunikacją, gdzie cbędzie NULLdotyczyła komunikacji nietelefonicznej. Następnie filtr ( WHEREpoWITH ) odfiltruje komunikację telefoniczną, pozostawiając wszystkie inne.

Bibliografia:

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

Dieter Pisarewski
źródło
2

Napisałem streszczenie pokazujące, jak można to zrobić całkiem naturalnie za pomocą Cypher 2.0

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

Kluczową kwestią jest użycie opcjonalnego dopasowania do dostępnych składników, a następnie porównanie z filtrem pod kątem brakujących (zerowych) składników lub składników o niewłaściwej wartości.

Zwróć uwagę, że pojęcie jest deklaratywne i nie musi opisywać algorytmu, po prostu zapisz, czego potrzebujesz.

uchylać się
źródło
2

Wykonałem to zadanie za pomocą gremlin. Zrobiłem

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

To zwróciło ścieżki wszystkich brakujących składników. Nie byłem w stanie sformułować tego w szyfrowanym języku, przynajmniej w wersji 1.7.

Mikołaja
źródło
2

Ostatnie zapytanie powinno brzmieć:

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

Ten wzór: (ingredient)<-[:has_ingredient*0..0]-chef

Jest powodem, dla którego nic nie zwróciło. *0..0oznacza, że ​​długość relacji musi wynosić zero, co oznacza, że ​​składnik i szef kuchni muszą być tym samym węzłem, którym nie są.

Andres
źródło
Tak, ale nie zwraca pożądanego składnika. Zwraca to, co szef kuchni ma już wspólnego z przepisem, chcę poznać różnicę.
Nicholas