Nó de retorno se o relacionamento não estiver presente

90

Estou tentando criar uma consulta usando uma cifra que "encontrará" ingredientes ausentes que um chef pode ter. Meu gráfico está configurado assim:

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

(ingredient)teria uma chave / valor de name = "dye colors". (ingredient_value)poderia ter uma chave / valor de valor = "vermelho" e "faz parte de" o (ingredient, name="dye colors").

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

Estou usando essa consulta para obter todos os ingredients, mas não seus valores reais, que uma receita exige, mas gostaria de retornar apenas o ingredientsque o chef não tem, em vez de todos os ingredientes que cada receita exige. eu tentei

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

mas isso não retornou nada.

Isso é algo que pode ser realizado por cypher / neo4j ou é algo que é melhor tratado devolvendo todos os ingredientes e separando-os eu mesmo?

Bônus: também existe uma maneira de usar cifragem para combinar todos os valores que um chef possui com todos os valores que uma receita exige. Até agora, retornei apenas todas as correspondências parciais retornadas por a chef-[:has_value]->ingredient_value<-[:requires_value]-recipee agregando os resultados sozinho.

Nicholas
fonte
Verifique aqui as informações relevantes para a v3: stackoverflow.com/questions/25673223/…
Maciej
Para futuros usuários; pode usar existsem uma WHEREcláusula (também negá-la), neo4j.com/developer/subqueries/#existential-subqueries para obter mais informações.
ozanmuyes,

Respostas:

159

Atualização 01/10/2013:

Descobri isso na referência do Neo4j 2.0 :

Tente não usar relacionamentos opcionais. Sobre tudo,

não os use assim:

MATCH a-[r?:LOVES]->() WHERE r IS NULL onde você apenas garante que eles não existam.

Em vez disso, faça assim:

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

Usando cifragem para verificar se não existe relação:

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

O ? marca torna o relacionamento opcional.

OU

Em neo4j 2 faça:

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

Agora você pode verificar se há relacionamento não existente (nulo).

Gil Stal
fonte
3
No Neo4j 2.0, use OPTIONAL MATCH para combinar relacionamentos opcionais, ou seja, o primeiro exemplo seria semelhante a OPTIONAL MATCH (source) - [r: someType] - (target) RETURN source, r
boggle
Estou tentando ter um nó rotulado em WHERE NOT, ele não funciona. Como: MATCH a WHERE NOT (a) - [: LOVES] -> (Stranger), neste 'Stranger' está um rótulo de nó. Estou usando o neo4j versão 2.1.2
Krishna Shetty
1
Esqueça, eu entendo por que você deseja mostrar a progressão para chegar a esta resposta: CORRESPONDER A ONDE NÃO (a) - [: AMA] -> ()
NumenorForLife
4
O MATCH a...exemplo agora deve serMATCH (a) WHERE NOT (a)-[:LOVES]->()
Liam
1
@ gil-stal Por que não posso usar o nome do nó com esta consulta como esta. CORRESPONDER A ONDE NÃO (a) - [: AMA] -> (b: Alguma Etiqueta). Se eu não usar o nome do nó, ele funciona.
iit2011081
16

Para buscar nós sem nenhum relacionamento

Esta é a boa opção para verificar se o relacionamento existe ou não

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

Você também pode verificar várias condições para isso. Ele retornará todos os nós, que não tenham o relacionamento "reproduzido" ou "não reproduzido".

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

Para buscar nós que não têm nenhum relacionamento

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

Ele verificará se o nó não tem nenhum relacionamento de entrada / saída.

Satish Shinde
fonte
4
MATCH (player) WHERE NOT (player)-[r]-() RETURN player dá um erro Variável r não definida . Como posso definir r?
Chathura Wijeweera de
para corrigir isso, especifique um relacionamento (por exemplo (player -[:rel]- ()) ou deixe em branco para qualquer relação(player -[]- ()
Archemar 01 de
MATCH (player) WHERE NOT (player)-[]-() RETURN player- Funciona bem
Prashanth Terala
Sua primeira consulta está realmente errada. O próprio padrão MATCH sempre retorna apenas relacionamentos existentes, nenhum deles NULL. Portanto, sua linha WHERE não tem nada para filtrar.
Cristi S.
@CristiS. Obrigado por me avisar. Eu atualizei a consulta, ela deve funcionar
Satish Shinde
8

Se você precisar da semântica de "exclusão condicional", poderá fazer isso desta forma.

A partir do neo4j 2.2.1, você pode usar a OPTIONAL MATCHcláusula e filtrar os NULLnós não correspondidos ( ).

Também é importante usar WITHcláusula entre as cláusulas OPTIONAL MATCHe WHERE, de modo que a primeira WHEREdefina uma condição para a correspondência opcional e a segunda WHEREse comporte como um filtro.

Supondo que temos 2 tipos de nós: Persone Communication. Se eu quiser obter todas as Pessoas que nunca se comunicaram por telefone, mas podem ter se comunicado de outras formas, eu faria esta consulta:

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

O padrão de correspondência corresponderá a todas as Pessoas com suas comunicações, onde cserá NULLpara comunicações não telefônicas. Então, o filtro ( WHEREdepois WITH) filtrará as comunicações telefônicas, deixando todas as outras.

Referências:

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

Dieter Pisarewski
fonte
2

Eu escrevi um resumo mostrando como isso pode ser feito naturalmente usando Cypher 2.0

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

O ponto principal é usar a correspondência opcional para ingredientes disponíveis e, em seguida, comparar para filtrar os ingredientes ausentes (nulos) ou ingredientes com o valor errado.

Observe que a noção é declarativa e não precisa descrever um algoritmo, você apenas anota o que precisa.

confundir
fonte
2

Concluí esta tarefa usando gremlin. eu fiz

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

Isso retornou os caminhos de todos os ingredientes que faltavam. Não fui capaz de formular isso na linguagem cifrada, pelo menos para a versão 1.7.

Nicholas
fonte
2

A última consulta deve ser:

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

Esse padrão: (ingredient)<-[:has_ingredient*0..0]-chef

É a razão pela qual não retornou nada. *0..0significa que o comprimento dos relacionamentos deve ser zero, o que significa que ingrediente e chef devem ser o mesmo nó, o que não é verdade.

Andres
fonte
Sim, mas não retorna o ingrediente desejado. Devolve o que o chef já tem em comum com a receita, quero descobrir a diferença.
Nicholas