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

(n)->(on)<-(n) cypher query gives me a cartesian product

我有一个类似这样的 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"}│
└────────────────┴─────────────────────┴────────────────┘

为了理解这个解决方案,您可以阅读cardinality的概念。

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

换句话说,您的查询是说获取此排列的所有选项,这意味着每个匹配项有两个。此处的查询是获取每场比赛的所有选项,然后“分组依据”比赛,以创建每场比赛的球队列表。

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

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

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