以下Cypher查询执行速度非常慢。它的轮廓看起来很好 - 有人可以指出我做错了什么。它应该根据运行每个部分所需的时间快速返回。
PROFILE
MATCH
(deal2:lDeal) <-[tr2:PARTICIPATES_IN]- (frComp:lCompany { id:2353462}) //1944 rows
MATCH
(inter) -[tr1:WORKED_IN | PARTICIPATES_IN]-> (deal2) //58,373
WITH
collect(distinct id(inter)) as interCol
MATCH
(article:lArticle { articleId:13194153}) -[r:WRITTEN_ABOUT] -> (Comp1:lCompany)
MATCH
(Comp1) -[fr1:PARTICIPATES_IN]-> (deal1:lDeal) //6671
MATCH
(deal1) <-[fr2:WORKED_IN | PARTICIPATES_IN]- (inter) //135,011
WHERE
id(inter) in interCol
RETURN
inter
EDIT 8/18/2014 2:41 PM EST:
根据@jjaderberg的建议尝试了多种变体而没有任何性能改进:
变化1:
MATCH
(inter)-[:WORKED_IN|PARTICIPATES_IN]->(:lDeal)<-[:PARTICIPATES_IN]-(:lCompany {id:2353462})
WHERE
inter-[:WORKED_IN|PARTICIPATES_IN]->(:lDeal)<-[:PARTICIPATES_IN]-(:lCompany)<-[:WRITTEN_ABOUT]-(:lArticle {articleId:13194153})
变化2:
MATCH
(inter)-[:WORKED_IN|PARTICIPATES_IN]->(cDeal:lDeal)
WHERE
cDeal<-[:PARTICIPATES_IN]-(:lCompany {id:2353462})
WITH
inter
MATCH
inter-[:WORKED_IN|PARTICIPATES_IN]->(:lDeal)<-[:PARTICIPATES_IN]-(:lCompany)<-[:WRITTEN_ABOUT]-(:lArticle {articleId:13194153})
RETURN inter
变化3:
MATCH
(inter)-[:WORKED_IN|PARTICIPATES_IN]->(cDeal:lDeal)
WHERE
cDeal<-[:PARTICIPATES_IN]-(:lCompany {id:2353462})
WITH
inter
MATCH
inter-[:WORKED_IN|PARTICIPATES_IN]->(:lDeal)<-[:PARTICIPATES_IN]-(:lCompany)<-[:WRITTEN_ABOUT]-(:lArticle {articleId:13194153})
RETURN
inter
变化4:
MATCH
(inter)-[:WORKED_IN|PARTICIPATES_IN]->(cDeal:lDeal)
WHERE
cDeal<-[:PARTICIPATES_IN]-(:lCompany {id:2353462})
WITH
inter
MATCH
inter-[:WORKED_IN|PARTICIPATES_IN]->(aDeal:lDeal)
WHERE
aDeal<-[:PARTICIPATES_IN]-(:lCompany)<-[:WRITTEN_ABOUT]-(:lArticle {articleId:13194153})
RETURN
inter
还尝试了@ MichaelHunger的解决方案 - 配置文件仍然需要很长时间。 Per Michael的请求 - 这里有一些额外的查询配置文件:
PROFILE
MATCH
(inter)-[:WORKED_IN|PARTICIPATES_IN]->(deal:lDeal)<-[:PARTICIPATES_IN]- (c:lCompany {id:2353462})
USING
index c:lCompany(id)
RETURN
count(*), count(distinct inter), count(distinct deal), count(distinct c);
PROFILE
MATCH
inter-[:WORKED_IN|PARTICIPATES_IN]->(deal:lDeal)<-[:PARTICIPATES_IN]-(c:lCompany)<-[:WRITTEN_ABOUT]-(a:lArticle {articleId:13194153})
USING
INDEX a:lArticle(articleId)
RETURN
count(*), count(distinct inter), count(distinct deal), count(distinct a), count(distinct c);
我们迄今为止所做的最好的是以下仍然很慢(COST.26370330总分数达到72828毫秒)。
MATCH
(comp2:lCompany {id:2353462})-[tr2:PARTICIPATES_IN]->(deal2:lDeal)<-[tr1]-(inter)-[fr2]->(deal1:lDeal)
WITH
DISTINCT deal1
MATCH
deal1<-[fr1:PARTICIPATES_IN]-(comp1:lCompany)<-[r:WRITTEN_ABOUT]-(article:lArticle)
USING INDEX article:lArticle(articleId)
WHERE
article.articleId=13194153
RETURN
DISTINCT count(comp1) as count, comp1.id ,comp1.name order by count desc, comp1.name
其中提供了以下资料:
答案 0 :(得分:2)
(与泰德合作)限制中间结果,以下是我们提出的最佳结果(在15,222毫秒内成本总计8,354,507点击率):
MATCH (comp2:lCompany {id:2353462})-[tr2:PARTICIPATES_IN]->(deal2:lDeal)<-[tr1]-(inter)
WITH DISTINCT inter
MATCH inter-[fr2]->(deal1:lDeal)
WITH DISTINCT deal1
MATCH deal1<-[fr1:PARTICIPATES_IN]-(comp1:lCompany)<-[r:WRITTEN_ABOUT]-(article:lArticle)
USING INDEX article:lArticle(articleId)
WHERE article.articleId=13194153
RETURN DISTINCT count(comp1) as count, comp1.id ,comp1.name order by count desc, comp1.name
答案 1 :(得分:1)
为了优化查询,我会将其分解为部分并进行优化。在不了解您的域名的情况下确定建议很难。如果您在http://console.neo4j.org分享一小部分样本,可能会有所帮助。除了领域理解之外,我还会看到以下两点。
如果我理解了您的查询,那么您将从两个不同的单个起点匹配两个不同路径上的两组节点,然后返回这些结果的交集。您的查询的人工重建可能是
请告诉我该公司参与的所有交易,或者更确切地说,参与或参与这些交易的所有利益相关方(仅告诉我每次交易)。
我还有一篇关于一家或多家公司的文章,我想知道参与或参与这些公司参与的任何交易的所有利益相关者。
开个玩笑,我不想知道所有这些利益相关者(联盟),只想知道两条路径上发生的那些(交集)!
如果这至少是一个有点公平的重建,那么你可以考虑将你的查询改为
请告知所有参与或参与本公司参与的任何交易的利益相关者 如果他们也参与或参与了本文所述的一家或多家公司参与的交易。
这可能会被转换回Cypher
MATCH (inter)-[:WORKED_IN|PARTICIPATES_IN]->(:lDeal)-[:PARTICIPATES_IN]->(:lCompany {id:2353462})
WHERE inter-[:WORKED_IN|PARTICIPATES_IN]->(:lDeal)<-[:PARTICIPATES_IN]-(:lCompany)<-[:WRITTEN_ABOUT]-(:lArticle {articleId:13194153})
显着的区别在于使用其中一个路径作为WHERE
子句中的过滤器,而不是进行额外的MATCH
和交叉操作。你可能会发现在MATCH
和WHERE
之间切换模式也会影响基数的表现,但我不确定会有多大差异。
将匹配模式分成不同的MATCH
子句,而不是在一个MATCH
子句中用逗号分隔它们之间存在很大的区别。区别在于逗号分隔列表会将模式视为相同模式的一部分,尽管可能是不相交的模式,并且会在遍历时强制执行关系唯一性。使用单独的MATCH
子句中的模式,可以单独处理模式,并且可以再次遍历相同的关系。也许你建议将模式分开。但是,由于您对节点ID的集合执行了DISTINCT
操作,因此您可能需要重新访问并确保不同的MATCH
子句是您真正想要的。在http://console.neo4j.org
MATCH (n:Crew { name:"Neo" })-[:KNOWS|LOVES]->(m)
MATCH n-[:LOVES]->o
RETURN n,m,o
----
n m o
(0:Crew {name:"Neo"}) (1:Crew {name:"Morpheus"}) (2:Crew {name:"Trinity"})
(0:Crew {name:"Neo"}) (2:Crew {name:"Trinity"}) (2:Crew {name:"Trinity"})
和
MATCH (n:Crew { name:"Neo" })-[:KNOWS|LOVES]->(m), n-[:LOVES]->o
RETURN n,m,o
----
n m o
(0:Crew {name:"Neo"}) (1:Crew {name:"Morpheus"}) (2:Crew {name:"Trinity"})
不同之处在于,允许第一个查询(具有单独的MATCH
子句)重用第一个查询中匹配的关系,因此匹配次数多于第二个查询。您可以在手册中的section 8.4处阅读相关内容。
上面建议的查询,将所有匹配拉成一个MATCH
子句,如果确实是低效率的原因,也会处理这个问题。
使用上面我的查询建议中表达的模式,不再需要大多数标识符。我放弃了这些,不是因为性能,而是因为我认为它使查询更具可读性,而且我认为这也是一种效率。
答案 2 :(得分:0)
您尝试的是一种SQL样式的连接。
请改为尝试:
MATCH
(inter)-[:WORKED_IN|PARTICIPATES_IN]->(:lDeal)<-[:PARTICIPATES_IN]-(:lCompany {id:2353462})
using index c:lCompany(id)
WITH distinct inter
MATCH inter-[:WORKED_IN|PARTICIPATES_IN]->(:lDeal)<-[:PARTICIPATES_IN]-(:lCompany)<-[:WRITTEN_ABOUT]-(a:lArticle {articleId:13194153})
USING INDEX a:lArticle(articleId)
RETURN inter;
它减少了中间结果的数量,即你有多少不同的inter
,以减少后续查询部分必须完成的工作量。
看一下你有多少行与总行数也总是很有趣。
请分享数字和计划,这两个查询返回:
PROFILE
MATCH
(inter)-[:WORKED_IN|PARTICIPATES_IN]->(deal:lDeal)<-[:PARTICIPATES_IN]-(c:lCompany {id:2353462})
using index c:lCompany(id)
RETURN count(*), count(distinct inter), count(distinct deal), count(distinct c);
PROFILE
MATCH inter-[:WORKED_IN|PARTICIPATES_IN]->(deal:lDeal)<-[:PARTICIPATES_IN]-(c:lCompany)<-[:WRITTEN_ABOUT]-(a:lArticle {articleId:13194153})
USING INDEX a:lArticle(articleId)
RETURN count(*), count(distinct inter), count(distinct deal), count(distinct a), count(distinct c);