Neo4j - Найти узлы, которые никогда не имели отношения с другим узлом - PullRequest
0 голосов
/ 27 июня 2018

Предполагая, что у меня есть пример с узлами и отношениями, подобными этому:

(:Node_A) -[:rel_a]-> (:Node_B) -[:rel_b]-> (:Node_C)

Я хочу найти все узлы Node_A, которые никогда не имели отношения с (:Node_C {label:'A'}).

Я пытался:

MATCH (a:Node_A) -[:rel_a]-> (b:Node_B), (c:Node_C {label:'A'})
WHERE NOT (b) -[:rel_b]-> (c)
RETURN a

но я не получил ожидаемого результата.

В случае, если у меня есть эти узлы и отношения, я не хочу, чтобы node_a возвращался.

(node_a:Node_A) -[:rel_a]-> (b1:Node_B),
(node_a:Node_A) -[:rel_a]-> (b2:Node_B),

(b1:Node_B) -[:rel_b]-> (c:Node_C {label:'A'}),
(b1:Node_B) -[:rel_b]-> (c1:Node_C {label:'B'}),

(b2:Node_B) -[:rel_b]-> (c2:Node_C {label:'C'})

Как мне сопоставить узлы, которые никогда не имели отношения с (:Node_C {label:'A'})?

1 Ответ

0 голосов
/ 27 июня 2018

Причина, по которой вы не получили ожидаемый результат, заключается в том, что существует путь, соответствующий данному шаблону (узел Node_A подключен к узлу Node_B, так что узел Node_B не подключен к Node_C узел с label:'A'). Это потому, что, согласно описанию вашего примера графа, у вас есть 2: Node_B узлы, связанные с вашим единственным: Node_A узлом. Один из них связан с двумя: узлами Node_C, одним из которых является узел: Node_C, которого вы пытаетесь избежать (и в этом случае путь THAT с этим: узел Node_B отфильтровывается из-за вашего предложения WHERE), и другое: узел Node_B подключен к узлу safe: Node_C с меткой 'C', и это путь, который соответствует вашему запросу и возвращается.

Есть несколько способов получить желаемую фильтрацию.

Одним из них является определение полного шаблона, который вы хотите полностью исключить в предложении WHERE, и исключение части: Node_B из предложения MATCH:

MATCH (a:Node_A), (c:Node_C {label:'A'})
WHERE NOT (a) -[:rel_a]-> (:Node_B) -[:rel_b]-> (c)
RETURN a

Если вы не знаете или не заботитесь о промежуточных узлах или отношениях между a и c, вы можете опустить их из шаблона:

MATCH (a:Node_A), (c:Node_C {label:'A'})
WHERE NOT (a) --> () --> (c)
RETURN a

Вы можете выразить то же самое, используя отношения переменной длины, где мы знаем, что c может быть только через 2 прыжка:

MATCH (a:Node_A), (c:Node_C {label:'A'})
WHERE NOT (a) -[*2]-> (c)
RETURN a

EDIT

stdob-- правильно указывает, что для всех этих подходов мы предположили, что в графе существует узел :Node_C с label:'A'. Если это не гарантировано, и так получилось, что такого узла НЕТ, то эти запросы ничего не вернут обратно.

Если нам нужно справиться с этим потенциальным случаем, то лучше перенести это из MATCH в предложение WHERE:

MATCH (a:Node_A)
WHERE NOT (a) -[*2]-> (:Node_C {label:'A'})
RETURN a

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

...