【问题标题】:How to improve performance of two chained aggregations in neo4j query如何提高 Neo4j 查询中两个链式聚合的性能
【发布时间】:2016-08-18 22:04:28
【问题描述】:

假设我有一个性质的 neo4j 图:

create (SK:Author {name:'Stephen King'}), (JK:Author {name:'J.K. Rowling'}), (DS:Author {name:'Dr. Seuss'}), (TS:Book {name:'The Stand'}), (HP:Book {name:'Harry Potter'}), (CH:Book {name:'Cat in the Hat'}), (SHINING:Book {name:'The Shining'}), (PAF:Genre {name:'Post-Apocalyptic fiction'}), (F:Genre {name:'Fantasy'}), (C:Genre {name:'Childrens'}), (HORROR:Genre {name:'Horror'}), (SK)<-[:WRITTEN_BY]-(TS)-[:CATEGORIZED_AS]->(PAF), (JK)<-[:WRITTEN_BY]-(HP)-[:CATEGORIZED_AS]->(F), (DS)<-[:WRITTEN_BY]-(CH)-[:CATEGORIZED_AS]->(C), (SK)<-[:WRITTEN_BY]-(SHINING)-[:CATEGORIZED_AS]->(HORROR)

Neo4j 控制台链接:http://console.neo4j.org/r/2d69kq

我有大约 53,000 个作者节点、600 万个书籍节点和 9,000 个流派节点。

对于这样的查询:

match (b:Book)-[:WRITTEN_BY]->(a:Author)
where a.name in ['Stephen King', 'J.K. Rowling']
with a, collect(b) as bs
unwind bs as book
match (g:Genre)<-[r:CATEGORIZED_AS]-(book)
where id(g) in [13, 14, 15, 16]
with a, count(distinct book) as book_count_author, collect(book) as bs
unwind bs as book
match (g:Genre)<-[r:CATEGORIZED_AS]-(book)
where id(g) in [13, 14, 15, 16]
return a.name, g.name, count(distinct book) as book_count_genre, book_count_author

大约需要 12 秒才能完成。我试图用几种不同的方式重写查询并使用索引提示,但无法找出任何让它更快的方法。有什么想法吗?显然这个例子被简化了,但我确实有相应属性的索引。

以下是链式聚合的示例结果:

我需要两个聚合。第一个是作者的书籍数量,受第二场比赛中指定类型的限制。第二个计数是每个作者在每个类型中的书籍,再次受到相同类型的限制。

【问题讨论】:

  • 您的 id 对于我们这些试图在我们自己的系统上重新创建它的人来说是不可移植的(neo4j 内部 ID 永远不应该在外部使用,因为它们可能会更改,并且 id 可以被系统重用)。请修改您的查询以不使用 id 进行匹配。
  • 您能否也显示索引和约束的架构?
  • Re: ids,你可以使用链接的neo4j控制台,应该保留ids。这不是我的真实模式,但具有代表性。我无法分享真实的架构。我确实对正在使用的列有索引,并且在执行配置文件中看不到任何扫描。
  • 所以让我看看我是否理解您的要求...book_count_genre 应该是该类型的书籍总数,与作者无关,而 book_count_author 是给定的该类型的书籍数量作者?
  • 我包含的表格是我期望的结果。 book_count_author 是作者在所有受限类型中所写书籍的总数。 book_count_genre 是在所有受限类型中按类型和作者分类的图书数量。

标签: neo4j


【解决方案1】:

假设您在 :Author.name 上有一个索引(或存在约束),您可能可以使用这个:

match (book:Book)-[:WRITTEN_BY]->(a:Author)
where a.name in ['Stephen King', 'J.K. Rowling']
with a, book
match (g:Genre)<-[:CATEGORIZED_AS]-(book)
return a, g, size((g)<-[:CATEGORIZED_AS]-()) as book_count_genre, count(book) as book_count_author

收集和展开可能会很昂贵,尽量避免它。请注意,您可以找到模式的大小来获取模式的计数,否则无法通过给定列的节点上的计数来检索该模式。

编辑

为明确要求修改查询

book_count_genre - 任何作者的该类型书籍的数量

book_count_author - 给定作者所写的该类型书籍的数量

【讨论】:

  • 不确定这是否有效,因为我需要 book_count_author 受 (Genre)
  • 也许您可以在描述中准确添加您想要什么样的输出,以及它是如何被限制的。查询只能显示您尝试过的内容,但可能无法完全捕捉意图。
  • 你说得对,对不起,我已经按描述进行了编辑,以描述我需要的 2 个计数。这两个计数都需要受指定的作者和流派的限制。
  • 我修改了我的查询,它应该可以满足您的要求。
【解决方案2】:

@InverseFalcon 说了什么。

您可以进一步优化它:

MATCH (g:Genre)<-[r:CATEGORIZED_AS]-(book:Book)-[:WRITTEN_BY]->(a:Author) 
WHERE a.name in ['Stephen King', 'J.K. Rowling'] 
  AND g.name IN ['Post-Apocalyptic fiction','Childrens','Horror','Fantasy'] 
WITH a, g, count(distinct book) as  book_count_author_genre 
RETURN a.name, collect({ genre: g.name, count: book_count_author_genre}), 
       sum(book_count_author_genre) as book_count_author

您可能需要为作者和流派使用索引提示

如果您使用 id 进行查找,它会更快。

【讨论】:

    猜你喜欢
    • 2020-05-06
    • 1970-01-01
    • 2019-01-25
    • 2019-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-11
    • 2020-01-10
    相关资源
    最近更新 更多