(n)->(on)<-(n) 密码查询给了我一个笛卡尔乘积



我有一个Cypher查询,它是这样的:

MATCH (t1:Team)-[:PLAYS_ON]->(m:Match)<-[:PLAYS_ON]-(t2:Team)
RETURN t1 AS "Team 1", m AS "Match", t2 as "Team 2"

我的目标是有一个查询,允许我看到比赛,哪些球队在驱逐的上下文中相互匹配。

假设1队、2队和3队,比赛是1队对2队和2队对3队,我的预期输出是:

+------+-----+------+
|Team 1|match|Team 2|
|------+-----+------|
|Team 1|date |Team 2|
|Team 2|date |Team 3|
+------+-----+------+

但是我得到:

+------+-----+------+
|Team 1|match|Team 2|
|------+-----+------|
|Team 1|date |Team 2|
|Team 2|date |Team 1|
|Team 2|date |Team 3|
|Team 3|date |Team 2|
+------+-----+------+

我对Cypher/Neo4J比较陌生,所以,如果事实证明我犯了一个非常明显和愚蠢的错误,我不会印象深刻,但我没有大脑看到它。

谢谢你的回答!

方法之一是:

MATCH (t:Team)-[:PLAYS_ON]->(m:Match)
WITH collect(t) AS t, m
RETURN t[0] AS t1, m, t[1] AS t2

在此示例数据上:

MERGE (a:Team{name: 'Team1'})
MERGE (b:Team{name: 'Team2'})
MERGE (c:Team{name: 'Team3'})
MERGE (d:Match{Date: '2022-05-11'})
MERGE (e:Match{Date: '2022-05-12'})
MERGE (a)-[:PLAYS_ON]-(d)
MERGE (b)-[:PLAYS_ON]-(d)
MERGE (b)-[:PLAYS_ON]-(e)
MERGE (c)-[:PLAYS_ON]-(e)

会给你这个:

╒════════════════╤═════════════════════╤════════════════╕
│"t1"            │"m"                  │"t2"            │
╞════════════════╪═════════════════════╪════════════════╡
│{"name":"Team1"}│{"Date":"2022-05-11"}│{"name":"Team2"}│
├────────────────┼─────────────────────┼────────────────┤
│{"name":"Team2"}│{"Date":"2022-05-12"}│{"name":"Team3"}│
└────────────────┴─────────────────────┴────────────────┘

为了理解这个解决方案,你可以阅读基数的概念。

基本上,由于第一个MATCH的选项数量是每个(:Match)两个(两个团队,一个匹配),因此查询将每个(:Match)返回两个选项。由于每次匹配只需要一个结果,因此可以使用collect将这两行组合为一行。

换句话说,您的查询是说获取此排列的所有选项,即每个匹配两个选项。这里的查询是获得每个匹配的所有选项,然后"分组";Match,为每场比赛创建一个球队列表。

实现您想要的结果的另一种方法是这个查询(使用Nimrod Serok的图):

MATCH (t1:Team)-[:PLAYS_ON]->(m:Match)<-[:PLAYS_ON]-(t2:Team)
WHERE id(t1) < id(t2)
RETURN t1, m, t2

这是有效的,因为WHERE子句确保相同的团队配对不会在两个方向上被考虑(这会导致笛卡尔积)。