对多个子句使用匹配会导致奇怪的结果
Using Match with Multiple Clauses Causes Odd Results
我正在 Neo4j 2.0.4 中编写一个 Cypher 查询,试图获取所选节点的入站和出站关系总数。当我一次只使用一个节点查询时,我可以很容易地做到这一点,就像这样:
MATCH (g1:someIndex{name:"name1"})
MATCH g1-[r1]-()
RETURN count(r1);
//Returns 305
MATCH (g2:someIndex{name:"name2"})
MATCH g2-[r2]-()
RETURN count(r2);
//Returns 2334
但是当我尝试 运行 将 2 个节点放在一起进行查询时(即获取 g1 和 g2 的关系总数),我似乎得到了一个 奇怪的 结果。
MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"})
MATCH g1-[r1]-(), g2-[r2]-()
RETURN count(r1)+count(r2);
//Returns 1423740
由于某种原因,这个数字比 305+2334 的总数要大得多。
似乎其他 Neo4j 用户在使用多个 MATCH
子句时遇到了 运行 奇怪的问题,所以我通读了 Michael Hunger 在 https://groups.google.com/d/msg/neo4j/7ePLU8y93h8/8jpuopsFEFsJ 的解释,它建议 Neo4j 用户使用管道使用 WITH
避免 "identifier uniqueness" 的一场比赛的结果。但是,当我 运行 以下查询时,它只是超时:
MATCH (g1:gene{name:"SV422_HUMAN"}),(g2:gene{name:"BRCA1_HUMAN"})
MATCH g1-[r1]-()
WITH r1
MATCH g2-[r2]-()
RETURN count(r1)+count(r2);
我怀疑此查询没有 return,因为有很多记录 return 由 r1
编辑。在这种情况下,我将如何在 2 个节点上操作我的 "get-number-of-relationships" 查询?我只是使用了一些不正确的语法,还是我的“一次 2 个节点”查询的逻辑存在一些基本问题?
你的第一个问题是当你这样做时你返回的是笛卡尔积:
MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"})
MATCH g1-[r1]-(), g2-[r2]-()
RETURN count(r1)+count(r2);
如果 r1
有 305 个实例,r2
有 2334 个实例,您将返回 (305 * 2334) == 711870 行,因为您要对这个 (count(r1)+count(r2)
) 你总共得到 711870 + 711870 == 1423740.
你的第二个问题是你没有在这个查询的 WITH
子句中继承 g2
:
MATCH (g1:gene{name:"SV422_HUMAN"}),(g2:gene{name:"BRCA1_HUMAN"})
MATCH g1-[r1]-()
WITH r1
MATCH g2-[r2]-()
RETURN count(r1)+count(r2);
您在第一个 MATCH
子句中匹配 g2
,但是当您仅在第 3 行的 WITH
子句中保留 r1
时,您将其留在后面. 然后,在第 4 行中,当你在 g2-[r2]-()
上进行匹配时,你实际上是在匹配图中的所有内容,因为 g2
已被解除绑定。
让我通过 Neo4j 浏览器附带的电影数据集解决方案,因为您没有提供示例数据。假设我想获得与 Tom Hanks 和 Hugo Weaving 相关的关系总数。
作为单独的查询:
MATCH (:Person {name:'Tom Hanks'})-[r]-()
RETURN COUNT(r)
=> 13
MATCH (:Person {name:'Hugo Weaving'})-[r]-()
RETURN COUNT(r)
=> 5
如果我按照你的方式去做,我会得到 (13 * 5) * 2 == 90,这是不正确的:
MATCH (:Person {name:'Tom Hanks'})-[r1]-(),
(:Person {name:'Hugo Weaving'})-[r2]-()
RETURN COUNT(r1) + COUNT(r2)
=> 90
同样,这是因为我匹配了 r1
和 r2
的所有组合,其中有 65 个 (13 * 5 == 65),然后将其相加得到一共90个(65 + 65 == 90).
解决方法是使用DISTINCT
:
MATCH (:Person {name:'Tom Hanks'})-[r1]-(),
(:Person {name:'Hugo Weaving'})-[r2]-()
RETURN COUNT(DISTINCT r1) + COUNT(DISTINCT r2)
=> 18
显然,DISTINCT
修饰符只计算每个实体的不同实例。
如果需要,您也可以使用 WITH
完成此操作:
MATCH (:Person {name:'Tom Hanks'})-[r]-()
WITH COUNT(r) AS r1
MATCH (:Person {name:'Hugo Weaving'})-[r]-()
RETURN r1 + COUNT(r)
=> 18
TL;DR - 小心笛卡尔积。 DISTINCT
是你的朋友:
MATCH (:someIndex{name:"name1"})-[r1]-(),
(:someIndex{name:"name2"})-[r2]-()
RETURN COUNT(DISTINCT r1) + COUNT(DISTINCT r2);
您看到的结果激增的原因很容易解释:
MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"})
MATCH g1-[r1]-(), g2-[r2]-()
RETURN count(r1)+count(r2);
//Returns 1423740
在第 2 行中,g1
的任何关系的每个组合都与 g2
的任何关系组合,这解释了自 1423740 = 305 * 2334 * 2 以来的数字。所以你正在评估这里基本上是叉积。
计算 name1
和 name2
的所有关系之和的正确方法是:
MATCH (g:someIndex)-[r]-()
WHERE g.name in ["name1", "name2"]
RETURN count(r)
我正在 Neo4j 2.0.4 中编写一个 Cypher 查询,试图获取所选节点的入站和出站关系总数。当我一次只使用一个节点查询时,我可以很容易地做到这一点,就像这样:
MATCH (g1:someIndex{name:"name1"})
MATCH g1-[r1]-()
RETURN count(r1);
//Returns 305
MATCH (g2:someIndex{name:"name2"})
MATCH g2-[r2]-()
RETURN count(r2);
//Returns 2334
但是当我尝试 运行 将 2 个节点放在一起进行查询时(即获取 g1 和 g2 的关系总数),我似乎得到了一个 奇怪的 结果。
MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"})
MATCH g1-[r1]-(), g2-[r2]-()
RETURN count(r1)+count(r2);
//Returns 1423740
由于某种原因,这个数字比 305+2334 的总数要大得多。
似乎其他 Neo4j 用户在使用多个 MATCH
子句时遇到了 运行 奇怪的问题,所以我通读了 Michael Hunger 在 https://groups.google.com/d/msg/neo4j/7ePLU8y93h8/8jpuopsFEFsJ 的解释,它建议 Neo4j 用户使用管道使用 WITH
避免 "identifier uniqueness" 的一场比赛的结果。但是,当我 运行 以下查询时,它只是超时:
MATCH (g1:gene{name:"SV422_HUMAN"}),(g2:gene{name:"BRCA1_HUMAN"})
MATCH g1-[r1]-()
WITH r1
MATCH g2-[r2]-()
RETURN count(r1)+count(r2);
我怀疑此查询没有 return,因为有很多记录 return 由 r1
编辑。在这种情况下,我将如何在 2 个节点上操作我的 "get-number-of-relationships" 查询?我只是使用了一些不正确的语法,还是我的“一次 2 个节点”查询的逻辑存在一些基本问题?
你的第一个问题是当你这样做时你返回的是笛卡尔积:
MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"})
MATCH g1-[r1]-(), g2-[r2]-()
RETURN count(r1)+count(r2);
如果 r1
有 305 个实例,r2
有 2334 个实例,您将返回 (305 * 2334) == 711870 行,因为您要对这个 (count(r1)+count(r2)
) 你总共得到 711870 + 711870 == 1423740.
你的第二个问题是你没有在这个查询的 WITH
子句中继承 g2
:
MATCH (g1:gene{name:"SV422_HUMAN"}),(g2:gene{name:"BRCA1_HUMAN"})
MATCH g1-[r1]-()
WITH r1
MATCH g2-[r2]-()
RETURN count(r1)+count(r2);
您在第一个 MATCH
子句中匹配 g2
,但是当您仅在第 3 行的 WITH
子句中保留 r1
时,您将其留在后面. 然后,在第 4 行中,当你在 g2-[r2]-()
上进行匹配时,你实际上是在匹配图中的所有内容,因为 g2
已被解除绑定。
让我通过 Neo4j 浏览器附带的电影数据集解决方案,因为您没有提供示例数据。假设我想获得与 Tom Hanks 和 Hugo Weaving 相关的关系总数。
作为单独的查询:
MATCH (:Person {name:'Tom Hanks'})-[r]-()
RETURN COUNT(r)
=> 13
MATCH (:Person {name:'Hugo Weaving'})-[r]-()
RETURN COUNT(r)
=> 5
如果我按照你的方式去做,我会得到 (13 * 5) * 2 == 90,这是不正确的:
MATCH (:Person {name:'Tom Hanks'})-[r1]-(),
(:Person {name:'Hugo Weaving'})-[r2]-()
RETURN COUNT(r1) + COUNT(r2)
=> 90
同样,这是因为我匹配了 r1
和 r2
的所有组合,其中有 65 个 (13 * 5 == 65),然后将其相加得到一共90个(65 + 65 == 90).
解决方法是使用DISTINCT
:
MATCH (:Person {name:'Tom Hanks'})-[r1]-(),
(:Person {name:'Hugo Weaving'})-[r2]-()
RETURN COUNT(DISTINCT r1) + COUNT(DISTINCT r2)
=> 18
显然,DISTINCT
修饰符只计算每个实体的不同实例。
如果需要,您也可以使用 WITH
完成此操作:
MATCH (:Person {name:'Tom Hanks'})-[r]-()
WITH COUNT(r) AS r1
MATCH (:Person {name:'Hugo Weaving'})-[r]-()
RETURN r1 + COUNT(r)
=> 18
TL;DR - 小心笛卡尔积。 DISTINCT
是你的朋友:
MATCH (:someIndex{name:"name1"})-[r1]-(),
(:someIndex{name:"name2"})-[r2]-()
RETURN COUNT(DISTINCT r1) + COUNT(DISTINCT r2);
您看到的结果激增的原因很容易解释:
MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"})
MATCH g1-[r1]-(), g2-[r2]-()
RETURN count(r1)+count(r2);
//Returns 1423740
在第 2 行中,g1
的任何关系的每个组合都与 g2
的任何关系组合,这解释了自 1423740 = 305 * 2334 * 2 以来的数字。所以你正在评估这里基本上是叉积。
计算 name1
和 name2
的所有关系之和的正确方法是:
MATCH (g:someIndex)-[r]-()
WHERE g.name in ["name1", "name2"]
RETURN count(r)