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

88

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

(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, или это то, что лучше всего сделать, вернув все ингредиенты и отсортировав их самостоятельно?

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

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

Ответы:

157

Обновление 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

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

ИЛИ

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

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

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

Гил Сталь
источник
3
В Neo4j 2.0 используйте OPTIONAL MATCH для сопоставления необязательных отношений, т.е. первый пример будет выглядеть как OPTIONAL MATCH (источник) - [r: someType] - (цель) RETURN source, r
boggle
Я пытаюсь разместить помеченный узел в WHERE NOT, это не работает. Например: MATCH a WHERE NOT (a) - [: LOVES] -> (Stranger), в этом 'Stranger' - метка узла. Я использую neo4j версии 2.1.2
Кришна Шетти
1
Неважно, я понимаю, почему вы хотите показать прогресс, чтобы прийти к такому ответу: СООТВЕТСТВУЙТЕ WHERE NOT (a) - [: LOVES] -> ()
NumenorForLife
4
MATCH a...Пример должен теперь бытьMATCH (a) WHERE NOT (a)-[:LOVES]->()
Ли
1
@ gil-stal Почему я не могу использовать имя узла с таким запросом. СООТВЕТСТВУЙТЕ ГДЕ НЕТ (a) - [: LOVES] -> (b: SomeLabel). Если я не использую имя узла, он работает.
iit2011081 02
15

Для получения узлов, не имеющих отношения

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

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

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

Сатиш Шинде
источник
4
MATCH (player) WHERE NOT (player)-[r]-() RETURN player дает Неопределенную ошибку переменной r . Как я могу определить r?
Chathura Wijeweera
чтобы исправить это, либо укажите отношение (например (player -[:rel]- ()), либо оставьте (player -[]- ()
поле
MATCH (player) WHERE NOT (player)-[]-() RETURN player- Работает нормально
Прашант Терала
Ваш первый запрос на самом деле неверен. Сам шаблон MATCH всегда возвращает только существующие отношения, ни одно из которых не является NULL. Таким образом, вашей строке WHERE нечего фильтровать.
Кристи С.
@CristiS. Спасибо, что дали мне знать. Я обновил запрос, он должен работать
Сатиш Шинде
8

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

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

Важно также , чтобы использовать 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

Дитер Писаревски
источник
2

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

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

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

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

сбивать с толку
источник
2

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

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.

Николай
источник
2

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

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означает, что длина отношений должна быть равна нулю, что означает, что ингредиент и повар должны быть одним и тем же узлом, а это не так.

Андрес
источник
Да, но он не возвращает желаемый ингредиент. Он возвращает то, что у шеф-повара уже есть общего с рецептом, я хочу узнать разницу.
Николас