我在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节点的逻辑是否存在一些基本问题"查询?
答案 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
同样,这是因为我匹配了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);
答案 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以来的数字。因此,您正在评估这里基本上是一个交叉产品。
计算name1
和name2
所有关系总和的正确方法是:
MATCH (g:someIndex)-[r]-()
WHERE g.name in ["name1", "name2"]
RETURN count(r)