#neo4j #cypher
#neo4j #шифр
Вопрос:
Как я могу сказать cypher, чтобы ОН НЕ следовал определенному отношению / краю?
Например, у меня есть a :NODE
, который связан с другим :NODE
через :BUDDY
связь. Кроме того, каждый :NODE
связан :STUFF
с произвольной глубиной произвольными ребрами, которые НЕ имеют типа :BUDDY
. Теперь я хочу добавить сокращенное отношение от каждого :NODE
к своему :STUFF
. Однако я не включаю :STUFF
его :BUDDIES
.
(:NODE)-[:BUDDY]->(:NODE)
(:NODE)-[*]->(:STUFF)
Мой текущий запрос выглядит следующим образом:
MATCH (n:Node)-[*]->(s:STUFF) WHERE NOT (n)-[:BUDDY]->()-[*]->(s) CREATE (n)-[:HAS]->(s)
Однако у меня есть некоторые проблемы с этим запросом:
1) Если я когда-нибудь добавлю :BUDDY
связь не напрямую между :NODE
дочерними элементами :NODE
запроса, они будут использовать эту связь для сопоставления. Возможно, это не предназначено, поскольку я вообще не хочу включать приятелей.
2) Объяснение говорит мне, что neo4j выполняет сопоставление (:NODE)-[*]->(:STUFF)
, а затем AntiSemiApply
шаблон (n)-[:BUDDY]->()
. В результате он сопоставляет весь график, чтобы затем отменить сопоставление большинства найденных соединений. Это кажется неэффективным, и запрос выполняется медленнее, чем мне хотелось бы (как бы субъективно это ни звучало).
Одно (плохое) исправление заключается в ограничении глубины (:NODE)-[*]->(:STUFF)
via (:NODE)-[*..XX]->(:STUFF)
. Однако я не могу гарантировать эту глубину, если не использую смехотворно большое число для наихудших сценариев.
На самом деле я просто хотел бы сказать neo4j, чтобы он просто не следовал определенным отношениям. Например MATCH (n:NODE)-[ALLBUT(:BUDDY)*]->(s:STUFF) CREATE (n)-[:HAS]->(s)
, Как я могу добиться этого без необходимости перечислять все разрешенные соединения и соединять их с помощью a |
(что действительно быстро, но мне приходится вручную отслеживать все возможные отношения)?
Ответ №1:
Один из вариантов для этой конкретной схемы — явно пройти мимо точки, где BUDDY
связь вызывает беспокойство, а затем выполнить все неограниченные перемещения, которые вам нравятся оттуда. Затем вам нужно применить фильтр только к одноэтапным связям:
MATCH (n:Node) -[r]-> (leaf)
WHERE NOT type(r) = 'BUDDY'
WITH n, leaf
MATCH (leaf) -[*] -> (s:Stuff)
WITH n, COLLECT(DISTINCT leaf) AS leaves, COLLECT(DISTINCT s) AS stuff
RETURN n, [leaf IN leaves WHERE leaf:Stuff] stuff AS stuffs
Другой вариант — установить apoc
и изучить процедуру расширения пути, которая позволяет вам вносить в черный список метки узлов (например,: Node) из вашего запроса path, что может работать так же хорошо, в зависимости от вашего графика. Смотрите здесь .
Комментарии:
1. решение будет в порядке, если я не буду добавлять
:BUDDY
отношения глубже в график. Я посмотрю на apoc.
Ответ №2:
Мое окончательное решение — создать строку из набора
{relations}{relations_id_do_not_want}
и используйте это для сопоставления. Поскольку я использую API и, следовательно, могу выполнять это поколение автоматически, это не такое большое неудобство, как я опасался, но все же неудобство. Однако это было единственное решение, которое я смог найти с момента публикации этого вопроса.
Ответ №3:
Вы могли бы использовать условие типа nrelationship:
MATCH (:Node)-[r:REL]->(:OtherNode)
WHERE NOT type(r) = 'your_unwanted_rel_type'
Хотя у меня нет никаких подсказок о perf