首页 > 解决方案 > 遇到给定节点时,Neo4j 停止搜索无向路径

问题描述

我在 Neo4j 中有以下测试数据:

merge (n1:device {name:"n1"})-[:phys {name:"phys"}]->(:interface {name:"n1a"})-[:cable {name:"cable"}]->(:interface {name:"n2a"})-[:phys {name:"phys"}]->(n2:device {name:"n2"})
merge (n1)-[:phys {name:"phys"}]->(:interface {name:"n1b"})-[:cable {name:"cable"}]->(:interface {name:"n2b"})-[:phys {name:"phys"}]->(n2)
merge (n1)-[:phys {name:"phys"}]->(:interface {name:"n1c"})-[:cable {name:"cable"}]->(:interface {name:"n2c"})-[:phys {name:"phys"}]->(n2)
merge (n1)-[:phys {name:"phys"}]->(:interface {name:"n1d"})-[:cable {name:"cable"}]->(:interface {name:"n2d"})

给予:

在此处输入图像描述

虽然此示例在 n1 和 n2 之间的 4 条路径中的每条路径上都有 3 个关系和 2 个节点,但我的真实数据可能有更多,也可能有更多路径。

这是一个无向图,在真实数据集中,每条路径部分的关系在任一方向。

我知道每条路径都从 :device 开始,或者只是在一个非 :device 结束,或者在一个 :device 结束,并且一路上可能有任意数量的关系和其他非 :device 节点。

所以我想做:

match p=(:device {name:"n1"})-[*]-(:device) return (p)

并让它返回相同的(我会对双倍感到满意),记录数为:

match p=(:device {name:"n1"})-[*]->(:device) return (p)

因此,我正在寻找一种方法来停止匹配关系并在路径中遇到第一个 (:device) 时停止遵循该路径。

根据我有限的理解,我可以通过使每一个关系都是双向的来轻松实现这一点。但是,到目前为止,我已经避免使用该选项,因为我已经阅读了它是不好的做法。

专家额外:-)

此外,我想要一种方法来返回任何不以 :device 结尾的完整路径(例如,底部路径)

谢谢

标签: neo4jcypher

解决方案


这是一个仅使用 Cypher 有点难以处理的用例,因为我们没有办法指定“遵循可变长度路径并在到达此类型的另一个节点时停止”。

当我们使用 LIMIT 时,我们可以做这样的事情,但是当我们不知道会有多少结果时,这变得过于严格,或者我们需要对多个起始节点执行此操作。

因此,有一些APOC 路径查找程序包含更灵活的选项。其中之一是 labelFilter 选项,可让您描述如何过滤具有在扩展期间找到的特定标签的节点(黑名单、白名单等)。其中一个过滤器称为终止过滤器(在适当的标签前使用/符号),这意味着包含该节点的路径作为结果,并停止扩展,这正是您正在寻找的。

安装 APOC 后,您可以使用该apoc.path.expandConfig()过程,从您的起始节点开始,并提供 labelFilter 配置参数来获得此行为:

MATCH (start:device {name:"n1"})
CALL apoc.path.expandConfig(start, {labelFilter:'/device'}) YIELD path
RETURN path

推荐阅读