如何 return 每个节点属性的最大计数

How to return max counts per another node's properties

我需要计算一个作曲家的作品每十年被演奏了多少次,然后return只计算每十年演奏次数最多的一首曲子。

除了过滤每十年最高计数之外的所有内容,此密码器可以执行所有操作。

match (c:Composer)-[:CREATED_BY]-(w:Work)<-[*..2]-(prog:Program) 
WHERE c.lastname =~ '(?i).*stravinsky.*' 
WITH w.title AS Title, prog.title AS Program, LEFT(prog.date, 3)+"0" AS Decade
RETURN Decade, Title, COUNT(Program) AS Total
ORDER BY Decade, Total DESC, Title

几个小时以来,我一直在努力解决这个问题,但找不到解决方案。

这似乎 return 您正在寻找的东西,但它可能可以改进。

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

它只有 return 每个十年的一个结果,但没有考虑到联系,所以我觉得有点不完整。如果我想出好的东西,我会考虑如何去做并编辑。

我将此字符串与 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 Query Planner 设置为 Cypher 2.1,如果第一行是 MATCH (c:Composer)-[r:CREATED_BY]-(w)<-[r2:REL_TYPE]-(prog),则性能最佳。仅在第一个节点上使用标签来帮助 WHERE 完成其工作。始终始终始终使用节点和 rel 标识符。
  • 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.