首页 > 解决方案 > 为什么单个 Neo4j 关系在 Cypher 查询结果中显示两次?

问题描述

让我们考虑一个具有有向关系的平凡图:

CREATE 
  (`0` :Car {value:"Ford"})
, (`1` :Car {value:"Subaru"})
, (`0`)-[:`DOCUMENT` {value:"DOC-1"}]->(`1`);

以下查询MATCH (n1:Car)-[r:DOCUMENT]-(n2:Car) RETURN *返回:

╒══════════════════╤══════════════════╤═════════════════╕
│"n1"              │"n2"              │"r"              │
╞══════════════════╪══════════════════╪═════════════════╡
│{"value":"Subaru"}│{"value":"Ford"}  │{"value":"DOC-1"}│
├──────────────────┼──────────────────┼─────────────────┤
│{"value":"Ford"}  │{"value":"Subaru"}│{"value":"DOC-1"}│
└──────────────────┴──────────────────┴─────────────────┘

图只定义了一个Ford->Subaru关系,为什么是两个关系?
如何解释反向的(第 1 行;未在CREATE)语句中指定?

注意:这是我之前要求的将 2 个节点之间的多个关系转换为具有权重的单个关系的后续操作。我解决了我的问题,但我不相信我的答案是最好的解决方案。

标签: neo4jcypher

解决方案


您在此处的 MATCH 语句未指定方向,因此有两种可能的路径将与模式匹配(请记住,路径中节点的顺序很重要,并且可以将路径彼此区分开来),因此您有两个答案。

如果您指定关系的方向,您会发现只有一个可能的路径匹配:

MATCH (n1:Car)-[r:DOCUMENT]->(n2:Car) 
RETURN *

至于为什么我们在省略方向时会返回两条路径的问题,请记住路径是顺序敏感的:具有相同元素但元素顺序不同的两条路径是不同的路径。

为了帮助理解这一点,请考虑以下两个查询:

# Query 1
MATCH (n1:Car)-[r:DOCUMENT]-(n2:Car) 
WHERE n1.value = 'Ford'
RETURN *

╒══════════════════╤══════════════════╤═════════════════╕
│"n1"              │"n2"              │"r"              │
╞══════════════════╪══════════════════╪═════════════════╡
│{"value":"Ford"}  │{"value":"Subaru"}│{"value":"DOC-1"}│
└──────────────────┴──────────────────┴─────────────────┘

# Query 2
MATCH (n1:Car)-[r:DOCUMENT]-(n2:Car) 
WHERE n1.value = 'Subaru'
RETURN *

╒══════════════════╤══════════════════╤═════════════════╕
│"n1"              │"n2"              │"r"              │
╞══════════════════╪══════════════════╪═════════════════╡
│{"value":"Subaru"}│{"value":"Ford"}  │{"value":"DOC-1"}│
└──────────────────┴──────────────────┴─────────────────┘

从概念上讲(并且在没有索引的情况下也被计划者使用),要获得上述每个结果,您从描述中的完全匹配的结果开始,然后过滤到唯一符合给定标准的结果。

如果原始查询仅返回一行而不是两行,则上述结果将与原始无方向匹配查询不一致。


来自 OP 的附加信息

我需要一段时间才能理解它,但它确实以这种方式工作,这里有一份文档来确认它是设计使然:

当您的模式包含绑定关系,并且该关系模式未指定方向时,Cypher 将尝试在两个方向上匹配关系。

MATCH (a)-[r]-(b)
WHERE id(r)= 0
RETURN a,b

这将返回两个连接的节点,一次作为开始节点,一次作为结束节点。


推荐阅读