首页 > 解决方案 > 密码查询以查找多个节点之间的所有关系

问题描述

我有一个复杂的图表,如下图所示:

在此处输入图像描述

这里每个关系都有一个类型值。我需要编写一个密码查询来查找给定节点集(两个或更多)之间的所有关系(及其类型值)。可以按任何顺序输入节点,例如 x64->Linux->Oracle 或 Oracle->Linux->10.2。

编辑

我期待这样的输出。具有链接它们的关系名称的所有节点组合。

  1. 对于输入:x64->Linux->Oracle

在此处输入图像描述

  1. 对于输入:Linux->64->Oracle->12c

在此处输入图像描述

数据

可以从https://www.dropbox.com/s/w28omkdrgmhv7ud/Neo4j%20Queries.txt?dl=0访问数据

编辑 输入 x64->Linux->Oracle 的新输出格式

在此处输入图像描述

标签: neo4jcypherneo4j-apoc

解决方案


如果您只寻找直接连接集合中每对节点的关系(而不是查找集合中节点对之间的所有多跳路径),APOC 程序就有apoc.algo.cover()用于此用途案子:

...
// assume `nodes` is the collection of nodes
CALL apoc.algo.cover(nodes) YIELD rel
RETURN rel

编辑

正如我在评论中提到的,您对要求的更改极大地改变了问题的性质。

您似乎想要完整的路径结果(定向),包括不在您的输入中的节点,并且您希望确保type路径中的所有关系都存在相同的属性。

这要求我们找到这些节点的顺序,以便我们可以识别所有节点之间的路径。虽然我们可以找到输入节点的所有可能排列(对于路径的遍历顺序),但我认为我们可以只为开始和结束节点找到 2 的排列(通过 UNWINDING 集合两次并删除行起始节点和结束节点相同)。我们首先要找到所有输入和输出关系类型,以便我们可以使用一些集合操作(​​起始节点的输出类型与结束节点的输入类型相交,与其他所有(相交的)输入和输出类型相交)节点)来查找可能存在于可以连接所有节点的关系上的潜在类型。

从过滤后的剩余行中,我们可以匹配可以连接所有这些节点的可变长度路径,仅使用提供的类型,以便每个路径仅遍历具有单一类型的遍历关系。然后我们过滤以确保所有输入节点都在路径中。

我们将假设节点的类型为:具有属性“名称”的节点。

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

要同时处理类型和级别,我们需要在查询的早期收集它们,因此我们处理的不仅仅是类型,而是类型和级别的映射。这确实使查询更加复杂,但有必要确保提供的路径对于路径中的所有关系具有相同的类型和级别。

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

推荐阅读