Вернуть узел, если связь отсутствует

Я пытаюсь создать запрос с использованием шифра, который будет «находить» недостающие ингредиенты, которые могут быть у шеф-повара. Мой график настроен следующим образом:

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

(ingredient) будет иметь ключ / значение name = "dye colors". (ingredient_value) может иметь ключ / значение value = "red" и "является частью" (ingredient, name="dye colors").

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

Я использую этот запрос, чтобы получить все ingredients, но не их фактические значения, которые требуются для рецепта, но я бы хотел, чтобы возвращались только ingredients, которых нет у шеф-повара, вместо всех ингредиентов, требуемых для каждого рецепта. Я пытался

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

но это ничего не вернуло.

Может ли это быть выполнено с помощью cypher / neo4j, или это то, что лучше всего решить, вернув все ингредиенты и отсортировав их самостоятельно?

Бонус: также есть способ использовать шифр, чтобы сопоставить все значения, которые есть у шеф-повара, со всеми значениями, которые требует рецепт. До сих пор я возвращал только все частичные совпадения, которые возвращает chef-[:has_value]->ingredient_value<-[:requires_value]-recipe, и сам собираю результаты.


person Nicholas    schedule 08.06.2012    source источник
comment
Здесь можно найти информацию, относящуюся к версии 3: stackoverflow.com/questions/25673223/   -  person Maciej    schedule 01.04.2017
comment
Для будущих пользователей; можно использовать exists в предложении WHERE (также отрицать его), neo4j.com/developer/ subqueries / # existential-subqueries для получения дополнительной информации.   -  person ozanmuyes    schedule 31.03.2020


Ответы (6)


Обновление от 10.01.2013:

Обнаружил это в ссылке на Neo4j 2.0:

Старайтесь не использовать необязательные отношения. Прежде всего,

не используйте их так:

MATCH a-[r?:LOVES]->() WHERE r IS NULL где вы просто убедитесь, что их нет.

Вместо этого сделайте так:

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

Использование шифра для проверки отсутствия связи:

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

? отметка делает отношения необязательными.

OR

В neo4j 2 выполните:

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

Теперь вы можете проверить несуществующую (нулевую) связь.

person Gil Stal    schedule 10.01.2013
comment
В Neo4j 2.0 используйте OPTIONAL MATCH для сопоставления необязательных отношений, то есть первый пример будет выглядеть как OPTIONAL MATCH (источник) - [r: someType] - (цель) RETURN source, r - person boggle; 23.02.2014
comment
Я пытаюсь создать помеченный узел в WHERE NOT, он не работает. Например: MATCH a WHERE NOT (a) - [: LOVES] - ›(Stranger), в этом 'Stranger' - метка узла. Я использую neo4j версии 2.1.2 - person Krishna Shetty; 12.09.2014
comment
Неважно, я понимаю, почему вы хотите показать прогресс, чтобы прийти к такому ответу: СООТВЕТСТВУЙТЕ WHERE NOT (a) - [: LOVES] - ›() - person NumenorForLife; 26.04.2015
comment
И тебе хорошего дня ! - person Roee Gavirel; 12.11.2015
comment
Пример MATCH a... теперь должен быть MATCH (a) WHERE NOT (a)-[:LOVES]->() - person Liam; 23.02.2017
comment
@ gil-stal Почему я не могу использовать имя узла с таким запросом. СООТВЕТСТВУЙТЕ ГДЕ НЕТ (a) - [: LOVES] - ›(b: SomeLabel). Если я не использую имя узла, он работает. - person iit2011081; 02.06.2017

Для выборки узлов, не связанных между собой

Это хороший способ проверить, существует ли связь.

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

Вы также можете проверить несколько условий для этого. Он вернет все узлы, которые не имеют отношения "воспроизведено" или "не воспроизведено".

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

Чтобы получить узлы, которые не имеют никакого отношения к

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

Он проверит, что узел не имеет входящих / исходящих отношений.

person Satish Shinde    schedule 08.12.2014
comment
MATCH (player) WHERE NOT (player)-[r]-() RETURN player дает ошибку переменная r не определена. Как я могу определить r? - person Chathura Wijeweera; 20.02.2017
comment
чтобы исправить это, либо укажите отношение (например, (player -[:rel]- ()), либо оставьте пустым для любого отношения (player -[]- () - person Archemar; 01.04.2019
comment
MATCH (player) WHERE NOT (player)-[]-() RETURN player - Работает нормально - person Prashanth Terala; 10.02.2020
comment
Ваш первый запрос на самом деле неверен. Сам шаблон MATCH всегда возвращает только существующие отношения, ни одно из которых не является NULL. Таким образом, вашей строке WHERE нечего фильтровать. - person Cristi S.; 10.05.2020
comment
@CristiS. Спасибо, что дал мне знать. Я обновил запрос, он должен работать - person Satish Shinde; 11.05.2020

Если вам нужна семантика «условного исключения», вы можете добиться этого таким образом.

Начиная с neo4j 2.2.1, вы можете использовать предложение OPTIONAL MATCH и отфильтровать несогласованные (NULL) узлы.

Также важно использовать предложение WITH между предложениями OPTIONAL MATCH и WHERE, чтобы первое WHERE определяло условие для необязательного совпадения, а второе WHERE работало как фильтр.

Предположим, у нас есть 2 типа узлов: Person и Communication. Если я хочу получить всех лиц, которые никогда не общались по телефону, но могли общаться другими способами, я бы сделал следующий запрос:

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

Шаблон совпадения будет соответствовать всем лицам с их сообщениями, где c будет NULL для нетелефонных сообщений. Затем фильтр (WHERE после WITH) отфильтрует телефонную связь, оставив все остальные.

Использованная литература:

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

person Dieter Pisarewski    schedule 08.05.2015

Я написал суть, показывающую, как это можно сделать естественным образом с помощью Cypher 2.0.

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

Ключевым моментом является использование необязательного сопоставления с доступными ингредиентами, а затем сравнение для фильтрации отсутствующих (нулевых) ингредиентов или ингредиентов с неправильным значением.

Обратите внимание, что это понятие декларативно и не требует описания алгоритма, вы просто записываете то, что вам нужно.

person boggle    schedule 23.02.2014

Я выполнил эту задачу с помощью gremlin. я сделал

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

Это вернуло пути всех недостающих ингредиентов. Я не смог сформулировать это на языке шифрования, по крайней мере, для версии 1.7.

person Nicholas    schedule 11.06.2012

Последний запрос должен быть:

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

Этот шаблон: (ingredient)<-[:has_ingredient*0..0]-chef

Причина, по которой он ничего не вернул. *0..0 означает, что длина отношений должна быть равна нулю, что означает, что ингредиент и повар должны быть одним и тем же узлом, а это не так.

person Andres    schedule 09.06.2012
comment
Да, но он не возвращает желаемый ингредиент. Он возвращает то, что у повара уже есть общего с рецептом, я хочу выяснить разницу. - person Nicholas; 09.06.2012