具有COUNT的多个可选匹配似乎不起作用

时间:2017-06-04 12:04:51

标签: neo4j cypher

我有一个Item节点,它是POSTED_BY一个User节点。此外,项目可以由零个或多个用户节点组成,零个或多个注释可以在项目节点上POSTED_IN。

我需要做的是查询特定的Item节点(给定id),然后检索:

  1. 项目节点本身
  2. 项目为POSTED_BY的用户节点
  3. LIKE项目节点的用户数
  4. 项目节点的评论数量POSTED_IN
  5. 如果我尝试仅查询1-3,并且暂时排除4,我的查询看起来像这样:

    MATCH (i:Item {id: 'ByvIzUdbZ'})-[:POSTED_BY]->(u:User) 
    OPTIONAL MATCH (u2:User)-[:LIKES]->(i)  
    RETURN i, u, COUNT(u2);
    

    这将正确返回Item节点,User和LIKES计数。

    现在,为了适应第4点,我修改了查询以添加另一个OPTIONAL MATCH,如下所示:

    MATCH (i:Item {id: 'ByvIzUdbZ'})-[:POSTED_BY]->(u:User) 
    OPTIONAL MATCH (u2:User)-[:LIKES]->(i) 
    OPTIONAL MATCH (comment:Comment)-[:POSTED_IN]->(i) 
    RETURN i, u, COUNT(u2), COUNT(comment);
    

    然而,有了这个,用户(u2)和评论(评论)的计数都是不正确的。他们似乎正在“加起来”。所以,如果Likes实际上是3,喜欢和评论计数都返回为6.任何提示我在这里做错了什么?感谢。

2 个答案:

答案 0 :(得分:1)

您正在看到cartesian products的效果。

如果MATCH子句在其自己的上生成的行数为N,但是已存在的行数(例如,来自之前的{{1 }}子句是M,然后你得到M * N行。

为了避免这种乘法效应(也会对性能和内存产生不利影响),您可以在适当的条款后立即执行aggregation。例如,在您的情况下:

MATCH

答案 1 :(得分:0)

Cyber​​sam很好地解释了为什么你会看到你所看到的。请记住,基数(行数)也会影响查询中的操作(例如MATCH和OPTIONAL MATCH)的运行次数。

例如,在您的第一个MATCH中,如果10个用户发布了相同的项目,那么您将有10个行中的每一个与10个用户中的每一个组合。

然后OPTIONAL MATCH执行,虽然你的意思是它只对每个项目执行一次(你试图获得每个项目的类似计数),它将在同一个项目上执行10次,因为有10行那个项目。这是额外的工作,您可以通过在执行匹配之前尝试将项目计数到一行来避免,或者通过聚合用户,或者在匹配用户之前获取每个项目所需的数据。

这是一个可能更好的示例查询,将匹配保存到用户直到结束,为每个可选匹配保持基数为1。

MATCH (i:Item {id: 'ByvIzUdbZ'})       // one row
OPTIONAL MATCH (u2:User)-[:LIKES]->(i)
WITH i, COUNT(u2) AS u2_count          // back to 1 row
OPTIONAL MATCH (comment:Comment)-[:POSTED_IN]->(i) 
WITH i, u2_count, COUNT(comment) AS comment_count; // back to one row again
MATCH (i)-[:POSTED_BY]->(u:User) 
RETURN i, u, u2_count, comment_count