我正在用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
但是,当我尝试用两个节点一起运行查询(即获得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在https://groups.google.com/d/msg/neo4j/7ePLU8y93h8/8jpuopsFEFsJ上的解释,该解释建议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
返回了很多记录。在这种情况下,如何在两个节点上操作“获取关系号”查询?我只是使用了一些不正确的语法,还是我的“每次2节点”查询的逻辑存在一些根本问题?
发布于 2015-04-03 08:40:06
您的第一个问题是,当您这样做时,您正在返回一个笛卡儿产品:
MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"})
MATCH g1-[r1]-(), g2-[r2]-()
RETURN count(r1)+count(r2);
如果有305个r1
实例和2334个r2
实例,则返回(3052334) == 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行的WITH
子句中传递r1
时,就会留下它。然后,在第4行,当您在g2-[r2]-()
上匹配时,您将匹配图形中的所有内容,因为g2
已经解除绑定。
让我介绍一下Neo4j浏览器附带的电影数据集的解决方案,因为您还没有提供示例数据。比方说,我想知道汤姆·汉克斯和雨果·韦文的关系总数。
作为单独的查询:
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);
发布于 2015-04-03 08:40:08
你所看到的结果的爆炸可以很容易地解释:
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 =3052334*2以来的数字。所以,你基本上是在评估一个交叉乘积。
计算name1
和name2
所有关系之和的正确方法是:
MATCH (g:someIndex)-[r]-()
WHERE g.name in ["name1", "name2"]
RETURN count(r)
https://stackoverflow.com/questions/29435590
复制相似问题