使用多个子句匹配会导致奇怪的结果

时间:2015-04-03 15:59:47

标签: neo4j cypher

我在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子句时遇到了一些奇怪的问题,所以我在https://groups.google.com/d/msg/neo4j/7ePLU8y93h8/8jpuopsFEFsJ阅读了Michael Hunger的解释,建议Neo4j用户管理结果一个匹配使用WITH以避免"标识符唯一性"。但是,当我运行以下查询时,它只会超时:

MATCH (g1:gene{name:"SV422_HUMAN"}),(g2:gene{name:"BRCA1_HUMAN"})
MATCH g1-[r1]-()
WITH r1
MATCH g2-[r2]-()
RETURN count(r1)+count(r2);

我怀疑此查询没有返回,因为r1返回了大量记录。在这种情况下,我将如何操作我的" get-number-of-relationship"在2个节点上查询?我只是使用了一些不正确的语法,或者我的" 2节点的逻辑是否存在一些基本问题"查询?

2 个答案:

答案 0 :(得分:3)

您的第一个问题是,当您执行此操作时,您将返回笛卡尔积:

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。

您的第二个问题是,您未在此查询的g2子句中携带WITH

MATCH (g1:gene{name:"SV422_HUMAN"}),(g2:gene{name:"BRCA1_HUMAN"})
MATCH g1-[r1]-()
WITH r1
MATCH g2-[r2]-()
RETURN count(r1)+count(r2);

您在第一个g2子句中与MATCH匹配,但是当您仅在第3行的r1子句中携带WITH时,您将其留下。在第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

同样,这是因为我匹配了r1r2的所有组合,其中有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);

答案 1 :(得分:3)

您可以轻松解释您所看到的结果爆炸:

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以来的数字。因此,您正在评估这里基本上是一个交叉产品。

计算name1name2所有关系总和的正确方法是:

MATCH (g:someIndex)-[r]-()
WHERE g.name in ["name1", "name2"]
RETURN count(r)