这似乎返回了您正在寻找的内容,但可能还可以改进。
MATCH (c:Composer)-[r:CREATED_BY]-(w:Work)<-[*..2]-(prog:Program)
WHERE c.lastname =~ '(?i).*stravinsky.*'
WITH LEFT(prog.date, 3)+"0" AS Decade, w.title AS Title, COUNT(prog.title) AS Total
ORDER BY Decade, Total DESC, Title
RETURN Decade, HEAD(COLLECT(Total)) AS Total, HEAD(COLLECT(Title)) AS Title
ORDER BY Decade
它每十年只返回一个结果,但没有考虑关系,所以对我来说感觉有点不完整。如果我想出一些好的东西,我会考虑如何做到这一点并进行编辑。
我用这个字符串http://graphgen.neoxygen.io http://graphgen.neoxygen.io在本地生成样本数据。
(c:Composer {firstname: firstName, lastname: lastName} *10)<-[:CREATED_BY *n..1]-(w:Work {title: progLanguage} *75)<-[:PERFORMED *n..1]-(prog:Program {title: catchPhrase, date: date} *400)
胜利 编辑
这是上述查询的原始版本,当存在平局时将显示多个作品。
MATCH (c:Composer)-[r:CREATED_BY]-(w:Work)<-[*..2]-(prog:Program)
WHERE c.lastname =~ '(?i).*stravinsky.*'
WITH LEFT(prog.date, 3)+"0" AS Decade, w.title AS Title, COUNT(prog.title) AS Total
ORDER BY Decade, Total DESC, Title
WITH Decade, Title, Total, HEAD(COLLECT(Total)) AS PerformedTotal
WITH Decade, [title in COLLECT(Title) WHERE Total = PerformedTotal] as Title, Total, PerformedTotal
ORDER BY PerformedTotal DESC
return Decade, HEAD(COLLECT(PerformedTotal)) as Totals, HEAD(COLLECT(Title)) as Titles
ORDER BY Decade
我觉得应该可以重构它,但我似乎无法简化它。
我有很多关于写这个答案的过程的笔记。即使它不完全是您正在寻找的内容,这也是 TLDR,因为它仍然很有趣。
- 如果可以的话,摆脱模糊搜索,找到一种方法来索引该属性或使用外部索引(如 Elasticsearch)。当您使用该正则表达式时,您的性能会受到巨大影响。
- Neo4j 2.2.M02 中存在一个错误,如果出现以下情况,该错误会导致查询崩溃:
<-[*..2]-
几乎被更改为其他任何内容。如果将 Cypher 查询计划器设置为Cypher 2.1
,如果第一行是,性能最好MATCH (c:Composer)-[r:CREATED_BY]-(w)<-[r2:REL_TYPE]-(prog)
。仅在第一个节点上使用标签来帮助WHERE
做好它的工作。始终始终使用节点和相关标识符。
- Cypher 有一些令人惊讶的行为。那整个
[title in COLLECT(Title) WHERE Total = PerformedTotal]
正在使用同一行后面的变量。如果我把它们拉出来,它就会崩溃。
更令人惊讶的行为是它不可能按照我期望的方式重构。我希望这样做,但不能:
MATCH (c:Composer)-[r:CREATED_BY]-(w:Work)<-[*..2]-(prog:Program)
WHERE c.lastname =~ '(?i).*stravinsky.*'
WITH LEFT(prog.date, 3)+"0" AS Decade, w.title AS Title, COUNT(prog.title) AS Total
ORDER BY Decade, Total DESC, Title
WITH Decade, [title in COLLECT(Title) WHERE Total = HEAD(COLLECT(Total))] as Title, Total, HEAD(COLLECT(Total)) AS PerformedTotal
ORDER BY PerformedTotal DESC
return Decade, HEAD(COLLECT(PerformedTotal)) as Totals, HEAD(COLLECT(Title)) as Titles
ORDER BY Decade
另一个编辑:如何加快速度
如果您的查询可能采用一些潜在路径,但您想避免[*..2]
,您可以通过为其提供有关尝试查找匹配项时应采取的路径的详细信息来加快速度。这是否更快实际上取决于它可以采取多少个分支,这将是死胡同。如果您可以只给它两个或三个路径,以便它可以完全忽略六个其他关系,它可能会抵消过滤和稍后发生的事情。当然,如果路径足够复杂,这可能会带来更多麻烦。
您应该将其弹出到 neo4j-shell 中并添加到前面PROFILE
,在末尾添加一个分号,然后查看数据库访问次数以确定哪个最适合您的数据集。
MATCH (c:Composer)-[r:CREATED_BY]-(w)
WHERE c.lastname =~ '(?i).*Denesik.*'
OPTIONAL MATCH (w)-[r2:CONNECTED_TO]-(this_node)<-[r3:ONE_MORE]-(prog1)
OPTIONAL MATCH (w)<-[r4:PERFORMED]-(prog2)
OPTIONAL MATCH (w)-[r5:THIS_REL]->(this_node)-[r6:AGAIN_WITH_THE_RELS]->(prog3)
WITH FILTER(program in [prog1, prog2, prog3] WHERE program IS NOT NULL) AS progarray, w.title AS Title
UNWIND(progarray) as prog
WITH LEFT(prog.date, 3)+"0" AS Decade, COUNT(prog.title) AS Total, Title
ORDER BY Decade, Total DESC, Title
WITH Decade, Title, Total, HEAD(COLLECT(Total)) AS PerformedTotal
WITH Decade, [title in COLLECT(Title) WHERE Total = PerformedTotal] as Title, Total, PerformedTotal
ORDER BY PerformedTotal DESC
return Decade, HEAD(COLLECT(PerformedTotal)) as Totals, HEAD(COLLECT(Title)) as Titles
ORDER BY Decade;
最棘手的部分是,如果我们重用prog
变量,它将把每个可选匹配的结果拖到下一个,本质上是试图过滤,并且我们不会得到完全独立的路径。 (为什么我们能够重用w
现在有点超出我的能力...)不过没关系。我们获取结果,将它们放入数组中,过滤空结果,然后将其展开回包含所有有效结果的单个变量。之后,我们继续正常进行。
在我的测试中,使用正确的数据集似乎可以显着加快速度。 YMMV。