为什么这两个Cypher查询返回不同的结果?

时间:2017-04-25 17:14:30

标签: neo4j cypher

我正在尝试学习Cypher并且我拥有trust network的数据,我想查询信任的人和最可信赖的人",所以我写了这个查询, QUERY1:

QUERY1:

MATCH (u1:USER)-[:TRUST]->(u2:USER) 
with u2.Id as id, COUNT(u2) AS score 
order by score desc
limit 15
match p=(w1:USER)-[:TRUST]->(w2:USER {Id: id})
return w1.Id as user1, w2.Id as user2

之后我想将最后两行查询更改为:

QUERY2:

MATCH (u1:USER)-[:TRUST]->(u2:USER) 
with u2.Id as id, COUNT(u2) AS score 
order by score desc
limit 15
match p=(w1:USER)-[:TRUST]->(w2:USER {Id: id})-[:TRUST]->(w3:USER)
return w1.Id as user1,w2.Id as user2, w3.Id as user3

在分析结果后,我猜错了! 所以我将id硬编码为特定值,例如575,然后count(p)等于1937520,但是如果我使用硬编码的Id运行最后一行查询,则作为单独的查询:

QUERY3:

MATCH r=(u1:USER)-[:TRUST]->(u2:USER {Id: "575"})-[:TRUST]->(u3:USER)
return count(r)

count(r)等于129168!

我检查了用户" 575"信任207人,并且被624人信任,因此QUERY3结果似乎正确:207 * 624 = 129168。我的问题是为什么?! 我无法理解QUERY2的问题,第二个问题是它是否意味着QUERY1结果也是错误的?

EDIT1: 谢谢你的答案,但我仍然有这个问题,所以我检查了另一个场景,我得到了以下结果: 如果我写这样的查询:

QUERY4:
MATCH (n) WITH n limit 15 return "1"

我将在输出中打印15" 1"这意味着QUERY2的最后一部分执行15次,无论我是否对Id进行硬编码,就像它&# 39; s在for循环中。所以这里的问题是我认为WHIT X LIMIT N doSomeThing会像foreach(x : X)循环一样执行,如果我使用x,如果我不使用x则不会。愚蠢的假设...

4 个答案:

答案 0 :(得分:1)

在QUERY3中,您将u2与单个用户(用户575)进行匹配。 QUERY 3是正确的。

然而,在QUERY2中,WITH(第3行)匹配15种不同的u1-u2组合。 MATCH(第1行)为每个u1和u2返回一个“行”,即井匹配该模式。然后你只返回前15个结果,我猜这是15个不同的u1为u2 =用户{Id:575}这就是给出1937520个结果,正好是15 * 129168。

出现问题因为你没有聚合(每个u2只获得1行)。你为每个u2用户'返回'(使用WITH)一个id变量,因此count(u2)将始终为1.也许你想写u1.Id或count(u1)?无论如何,有了u2.Id或u1.Id将因为LIMIT 15(第4行)而返回15个结果。 LIMIT 1可以解决问题,但我们也可以这样做:

MATCH (u1:User)-[:TRUST]-(u2:User)
WITH DISTINCT(u2.Id) AS id
LIMIT 15

然后是剩余的QUERY2(或QUERY1,就此而言)。我删除了得分变量,但如果它是计数(u1),则可以毫无问题地读取它。

答案 1 :(得分:1)

此查询可能符合您的预期。

MATCH (:USER)-[r:TRUST]->(u2:USER) 
WITH u2, COUNT(r) AS score 
ORDER BY score DESC
LIMIT 15
MATCH (w1:USER)-[:TRUST]->(u2)-[:TRUST]->(w3:USER)
RETURN w1.Id AS user1, u2.Id AS user2, w3.Id AS user3;

它首先找到15个最受信任的用户,然后查找这些用户所在的所有2级信任路径,最后返回这些路径中用户的ID。

此外,第二个MATCH重复使用第一个u2已找到的MATCH个节点,以加快第二个MATCH的处理速度。

答案 2 :(得分:1)

我只是打破查询2,其余的应该是有意义的。

QUERY2:

MATCH (u1:USER)-[:TRUST]->(u2:USER) 
with u2.Id as id, COUNT(u2) AS score 
order by score desc
limit 15
match p=(w1:USER)-[:TRUST]->(w2:USER {Id: id})-[:TRUST]->(w3:USER)
return w1.Id as user1,w2.Id as user2, w3.Id as user3

开始
MATCH (u1:USER)-[:TRUST]->(u2:USER) 
with u2.Id as id, COUNT(u2) AS score 
order by score desc
limit 15

您基本上是在创建所有u1信任u2的列表;并且COUNT(u2)=匹配的u2的#。因此,假设u1信任u2有100个匹配,COUNT(u2)将放置' 100'在每列的该列中。 (然后你订购现在的常数,什么都不做,限制15,所以你现在有一个15 u1信任u2的任意列表。

这就是离开

match p=(w1:USER)-[:TRUST]->(w2:USER {Id: id})-[:TRUST]->(w3:USER)

这样就匹配每个路径p,其中用户w1信任用户w2(对于来自第一部分的每个id)信任用户w3。

因此,修复第一部分,以获得前15个可信用户,您需要计算传入信任的数量

MATCH (u1:USER)-[trusts:TRUST]->(u2:USER) 
with u2, COUNT(trusts) AS score 
order by score desc
limit 15

现在您有15个最受信任的用户,您可以使用return u2.id, score验证这一点。为了让那些信任这些人的人,你只需要问... ...

MATCH (u3:USER)-[:TRUST]->(u2) 

然后u3将成为所有信任前15名受信任人(u2)的用户。

另外请注意,如果您使用的是neo4j Web浏览器,请尝试将PROFILE关键字预先挂起到您的密码,以便深入了解密码查询实际执行的操作。

编辑1:

现在解释查询4的作用MATCH (n) WITH n limit 15 return "1"。我确信你猜对了,MATCH (n) WITH n limit 15匹配所有节点但是将结果限制在第15位。在RETURN部分,你说"对于每一行,返回常数' 1'。 ",它在内部为您提供15个不同的行,但返回的行不是不同的。这就是DISTINCT关键字的用途。使用RETURN DISTINCT" 1"说"对于每一行,返回常量' 1',但过滤结果集只有不同的行。"也就是说,没有2列将具有相同的值。如果你知道会有一些重复的行,但是你想要看到它们(可能是为了重量参考,或者知道它们来自2个不同的字段),那么非独特的结果很有用。

答案 3 :(得分:0)

正如我在EDIT1中提到的,这里的问题是我认为WHIT X LIMIT N doSomeThing会像foreach(x : X)循环一样执行,如果我使用x,如果我不这样做则不会用x。愚蠢的假设...