Restituisci nodo se la relazione non è presente


88

Sto cercando di creare una query utilizzando la crittografia che "troverà" gli ingredienti mancanti che uno chef potrebbe avere, il mio grafico è impostato in questo modo:

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

(ingredient)avrebbe una chiave / valore di name = "dye colors". (ingredient_value)potrebbe avere una chiave / valore di valore = "rosso" e "fa parte di" (ingredient, name="dye colors").

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

Sto usando questa query per ottenere tutti i ingredientsvalori, ma non i loro effettivi, richiesti da una ricetta, ma vorrei restituire solo quello ingredientsche lo chef non ha, invece di tutti gli ingredienti richiesti da ciascuna ricetta. Provai

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

ma questo non ha restituito nulla.

È qualcosa che può essere realizzato da cypher / neo4j o è qualcosa che è meglio gestito restituendo tutti gli ingredienti e sistemandoli io stesso?

Bonus: esiste anche un modo per utilizzare la cifratura per abbinare tutti i valori che uno chef ha a tutti i valori richiesti da una ricetta. Finora ho restituito solo tutte le corrispondenze parziali restituite da a chef-[:has_value]->ingredient_value<-[:requires_value]-recipee aggregando i risultati da solo.


Controlla qui per informazioni relative alla v3: stackoverflow.com/questions/25673223/…
Maciej

Per futuri utenti; può usare existsin una WHEREclausola (anche negarla), neo4j.com/developer/subqueries/#existential-subqueries per maggiori informazioni.
ozanmuyes

Risposte:


157

Aggiornamento 01/10/2013:

Mi sono imbattuto in questo nel riferimento di Neo4j 2.0 :

Cerca di non usare relazioni opzionali. Soprattutto,

non usarli in questo modo:

MATCH a-[r?:LOVES]->() WHERE r IS NULL dove ti assicuri solo che non esistano.

Invece fai così:

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

Utilizzo di cypher per verificare se la relazione non esiste:

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

Il ? mark rende la relazione facoltativa.

O

In neo4j 2 fai:

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

Ora puoi verificare la presenza di una relazione inesistente (nulla).


3
In Neo4j 2.0, usa CORRISPONDENZA OPZIONALE per abbinare relazioni opzionali, ovvero il primo esempio sarebbe come PARTITA OPZIONALE (fonte) - [r: someType] - (destinazione) fonte RITORNO, r
boggle

Sto cercando di avere un nodo etichettato in WHERE NOT, non funziona. Come: MATCH a WHERE NOT (a) - [: LOVES] -> (Stranger), in questo "Stranger" è un'etichetta di nodo. Sto usando neo4j versione 2.1.2
Krishna Shetty

1
Non importa, capisco perché vorresti mostrare la progressione per raggiungere questa risposta: MATCH a WHERE NOT (a) - [: LOVES] -> ()
NumenorForLife

4
L' MATCH a...esempio dovrebbe ora essereMATCH (a) WHERE NOT (a)-[:LOVES]->()
Liam

1
@ gil-stal Perché non posso usare il nome del nodo con questa query come questa. MATCH a WHERE NOT (a) - [: LOVES] -> (b: SomeLabel). Se non uso il nome del nodo, funziona.
iit2011081

15

Per il recupero di nodi senza alcuna relazione

Questa è la buona opzione per verificare che la relazione esista o meno

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

Puoi anche controllare più condizioni per questo. Restituirà tutti i nodi, che non hanno la relazione "giocato" o "non riprodotto".

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

Per recuperare i nodi che non hanno alcuna relazione

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

Controllerà che il nodo non abbia alcuna relazione in entrata / uscita.


4
MATCH (player) WHERE NOT (player)-[r]-() RETURN player restituisce un errore variabile r non definito . Come posso definire r?
Chathura Wijeweera

per risolvere questo problema, specificare una relazione (ad esempio (player -[:rel]- ()) o lasciare vuoto per qualsiasi relazione(player -[]- ()
Archemar

MATCH (player) WHERE NOT (player)-[]-() RETURN player- Funziona bene
Prashanth Terala

La tua prima domanda è effettivamente sbagliata. Il modello MATCH stesso restituisce sempre solo le relazioni esistenti, nessuna delle quali NULL. Quindi la tua riga WHERE non ha nulla da cui filtrare.
Cristi S.

@CristiS. Grazie per avermi fatto sapere. Ho aggiornato la query che dovrebbe funzionare
Satish Shinde

8

Se hai bisogno della semantica "esclusione condizionale", puoi ottenerla in questo modo.

A partire da neo4j 2.2.1, puoi usare la OPTIONAL MATCHclausola e filtrare i NULLnodi senza corrispondenza ( ).

È anche importante utilizzare WITHclausole tra le clausole OPTIONAL MATCHe WHERE, in modo che la prima WHEREdefinisca una condizione per la corrispondenza facoltativa e la seconda WHEREsi comporti come un filtro.

Supponendo di avere 2 tipi di nodi: Persone Communication. Se desidero contattare tutte le Persone che non hanno mai comunicato per telefono, ma potrebbero aver comunicato in altri modi, farei questa domanda:

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

Il modello di corrispondenza abbinerà tutte le Persone con le loro comunicazioni dove csarà NULLper le comunicazioni non telefoniche. Quindi il filtro ( WHEREdopo WITH) filtrerà le comunicazioni telefoniche lasciando tutte le altre.

Riferimenti:

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


2

Ho scritto una sintesi che mostra come questo può essere fatto in modo abbastanza naturale usando Cypher 2.0

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

Il punto chiave è utilizzare la corrispondenza facoltativa con gli ingredienti disponibili e quindi confrontare per filtrare gli ingredienti mancanti (nulli) o gli ingredienti con il valore sbagliato.

Nota che la nozione è dichiarativa e non ha bisogno di descrivere un algoritmo, scrivi solo quello che ti serve.


2

Ho completato questa attività utilizzando gremlin. L'ho fatto

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

Questo ha restituito i percorsi di tutti gli ingredienti mancanti. Non sono stato in grado di formularlo nel linguaggio cifrato, almeno per la versione 1.7.


2

L'ultima query dovrebbe essere:

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

Questo modello: (ingredient)<-[:has_ingredient*0..0]-chef

È il motivo per cui non ha restituito nulla. *0..0significa che la lunghezza delle relazioni deve essere zero, il che significa che ingrediente e chef devono essere lo stesso nodo, cosa che non sono.


Sì, ma non restituisce l'ingrediente desiderato. Restituisce ciò che lo chef ha già in comune con la ricetta, voglio scoprire la differenza.
Nicholas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.