2017-07-03 156 views
2

没有得到不必要的太具体,我在Neo4j 3.2中遇到以下Cyper问题。假设我们有一个包含3个实体的数据库:User,Comment,Like。Neo4j 3.2 Cypher低性能

无论出于何种原因,我试图运行下面的查询:

MATCH (n:USER) WHERE n.name = "name" 
WITH n 
MATCH (o:USER) 
WITH n, o, "2000" as number 
MATCH (n)<-[:CREATED_BY]-(:COMMENT)-[:HAS]->(l:LIKE)-[:CREATED_BY]->(o) 
RETURN n, o, number, count(l) 

查询只需几分钟即可完成。但是,如果我只是删除“2000”作为部分,它会在几十毫秒内完成。

有没有人有解释为什么?

编辑: 顶部图像,与“2000”作为号码部分;底部,没有它。

+1

我的假设是你/ cypher创建32969个新的字符串。你是否在JVM中执行gc暂停?使用数字2000时您是否遇到同样的情况? – manonthemat

回答

4

你将不得不清理你的查询,现在你不使用索引(所以用特定名称初始匹配是慢),然后执行笛卡尔针对所有产品:用户节点,然后为每一行创建字符串。因此,首先在USER(name)上创建一个索引,以便快速找到您的开始节点。我们将不得不清理比赛的其余部分。

尝试这样代替:

MATCH (n:USER) WHERE n.name = "name" 
WITH n, "2000" as number 
MATCH (n)<-[:CREATED_BY]-(:COMMENT)-[:HAS]->(l:LIKE)-[:CREATED_BY]->(o:User) 
RETURN n, o, number, count(l) 

你应该在查询看到一个类似的计划与此查询为没有“2000”。

这样做的原因是,虽然你的计划与您匹配o笛卡尔积,规划是足够的智能,实现有一个附加的限制为o,它曾在图案出现在你的最后一场比赛,并且针对这种情况进行优化可以避免执行笛卡尔产品。

然而,一个新变量number的介绍阻止了规划人员认识到这基本上是相同的情况,因此规划人员没有优化笛卡尔产品。

现在,尝试明确您希望执行查询的方式,并尽量避免在查询中使用笛卡尔积。

在这种特殊情况下,意识到当你在第三行有MATCH (o:User)时,这并不是说o的类型是a:用户在后面的匹配中,而是说你的结果中的每一行到目前为止,针对所有用户节点执行笛卡尔乘积,然后针对每个用户节点,查看提供的模式中存在哪些节点。与简单地扩展提供的模式并获取任何内容相比,这是很多不必要的工作:您在模式的另一端找到的用户节点。

编辑

至于获得两项:LIKE和:厌恶节点数,也许尝试这样的事:

MATCH (n:USER) WHERE n.name = "name" 
WITH n, "2000" as number 
MATCH (n)<-[:CREATED_BY]-(:COMMENT)-[:HAS]->(likeDislike)-[:CREATED_BY]->(o:User) 
WITH n, o, number, head(labels(likeDislike)) as type, count(likeDislike) as cnt 
WITH n, o, number, CASE WHEN type = "LIKE" THEN cnt END as likeCount, CASE WHEN type = "DISLIKE" THEN cnt END as dislikeCount 
RETURN n, o, number, sum(likeCount) as likeCount, sum(dislikeCount) as dislikeCount 

假设你仍然需要number变量在那里。

+0

感谢您的回答。这确实清除了一些事情。然而,像这样写查询的原因是,第3行不仅仅是简单地匹配所有其他用户。为了这个例子,假设数据库中还有DISLIKE节点,尽管这将是一个设计流程。查询应该计算n与其他o之间的DISLIKE节点的数量,然后也计算n和其他o之间的所有LIKE节点的数量。 – user3455402

+2

在这里执行笛卡尔产品仍然不是一个好的理由,如果您必须检查两种类型的节点,问题只会变得更糟。没有理由检查每个单独的模式:USER。而只是检查模式本身找到哪些用户。对于您的DISLIKE用例,可能不容易标记潜力:LIKE或DISLIKE节点,然后使用CASE为每个节点计数。 – InverseFalcon