При условии, что вы ищете только отношения, напрямую соединяющие каждую пару узлов в наборе (в отличие от поиска всех многоскачковых путей между парами узлов в наборе), процедуры APOC имеют apoc.algo.cover() для именно этого варианта использования:
...
// assume `nodes` is the collection of nodes
CALL apoc.algo.cover(nodes) YIELD rel
RETURN rel
РЕДАКТИРОВАТЬ
Как уже упоминалось в моем комментарии, ваше изменение требований кардинально меняет природу вопроса.
Похоже, вам нужны полные результаты пути (направленные), включая узлы, которых нет в ваших входных данных, и вы хотите убедиться, что один и тот же атрибут type
присутствует для всех отношений в пути.
Это требует, чтобы мы нашли порядок этих узлов, чтобы мы могли определить путь между ними.В то время как мы могли бы найти все возможные перестановки входных узлов (для порядка обхода путей), я думаю, что мы можем обойтись, просто найдя перестановки 2 для начального и конечного узлов (УДАЛЯЯ коллекцию дважды и удаляя строки, гденачальный и конечный узлы одинаковы).Сначала нужно найти все типы отношений ввода и вывода, чтобы мы могли использовать некоторые операции над множествами (типы вывода начального узла пересекались с типами ввода конечного узла, пересекающегося со всеми (пересекающимися) типами входа и выхода другогоузлы), чтобы найти потенциальные типы, которые могут присутствовать в отношениях, которые могут соединить все узлы.
Из оставшихся строк после этой фильтрации мы можем сопоставить путь переменной длины, который может соединить все эти узлыс использованием только предоставленных типов, чтобы каждый путь проходил только через отношения с одним типом.Затем мы выполняем фильтрацию, чтобы убедиться, что все входные узлы находятся в пути.
Предположим, что узлы имеют тип: Node со свойством name.
MATCH (entity:Entity)
WHERE entity.key in ['Product','Version','BinaryType'] AND entity.value in ['pc','10.2','64']
WITH collect(entity) as nodes
UNWIND nodes as node
WITH nodes, node, [()-[r]->(node) | r.type] as inputTypes, [(node)-[r]->() | r.type] as outputTypes
WITH nodes, node, apoc.coll.toSet(inputTypes) as inputTypes, apoc.coll.toSet(outputTypes) as outputTypes
WITH nodes, collect({node:node, inputTypes:inputTypes, outputTypes:outputTypes}) as nodeData
UNWIND nodeData as start
UNWIND nodeData as end
WITH nodes, start, end, nodeData
WHERE start <> end
WITH nodes, start, end, apoc.coll.subtract(nodeData, [start, end]) as theRest
WITH nodes, start.node as start, end.node as end, apoc.coll.intersection(start.outputTypes, end.inputTypes) as possibleTypes, [data in theRest | apoc.coll.intersection(data.inputTypes, data.outputTypes)] as otherTypes
WITH nodes, start, end, reduce(possibleTypes = possibleTypes, types in otherTypes | apoc.coll.intersection(possibleTypes, types)) as possibleTypes
WHERE size(possibleTypes) > 0
UNWIND possibleTypes as type
MATCH path = (start)-[*]->(end)
WHERE all(rel in relationships(path) WHERE rel.type = type)
AND length(path) >= size(nodes) - 1
AND all(node in nodes WHERE node in nodes(path))
RETURN nodes(path) as pathNodes, type
To toэто касается как типа, так и уровня, нам нужно собрать их обоих ранее в запросе, поэтому вместо того, чтобы иметь дело только с типом, мы имеем дело с картой как типа, так и уровня.Это усложняет запрос, но необходимо убедиться, что указанные пути имеют одинаковый тип и уровень для всех отношений в пути.
MATCH (entity:Entity)
WHERE entity.key in ['Product','Version','BinaryType'] AND entity.value in ['pc','10.2','64']
WITH collect(entity) as nodes
UNWIND nodes as node
WITH nodes, node, [()-[r]->(node) | {type:r.type, level:r.level}] as inputs, [(node)-[r]->() | {type:r.type, level:r.level}] as outputs
WITH nodes, collect({node:node, inputs:apoc.coll.toSet(inputs), outputs:apoc.coll.toSet(outputs)}) as nodeData
UNWIND nodeData as start
UNWIND nodeData as end
WITH nodes, start, end, nodeData
WHERE start <> end
WITH nodes, start, end, apoc.coll.subtract(nodeData, [start, end]) as theRest
WITH nodes, start.node as start, end.node as end, apoc.coll.intersection(start.outputs, end.inputs) as possibles, [data in theRest | apoc.coll.intersection(data.inputs, data.outputs)] as others
WITH nodes, start, end, reduce(possibles = possibles, data in others | apoc.coll.intersection(possibles, data)) as possibles
WHERE size(possibles) > 0
UNWIND possibles as typeAndLevel
MATCH path = (start)-[*]->(end)
WHERE all(rel in relationships(path) WHERE rel.type = typeAndLevel.type AND rel.level = typeAndLevel.level)
AND length(path) >= size(nodes) - 1
AND all(node in nodes WHERE node in nodes(path))
RETURN nodes(path) as pathNodes, typeAndLevel.type as type, typeAndLevel.level as level