【问题标题】:Neo4j schema denormalizationNeo4j 模式非规范化
【发布时间】:2015-08-07 07:59:28
【问题描述】:

在我的 Neo4j 应用程序中,我有一个产品、产品特性和投票列表(具有双倍权重),每个产品都具有特定特性。

为了按特征列表的平均投票权重对产品列表进行排序,我需要执行一个复杂的运行时 Cypher 查询,该查询将计算每个产品特征列表的平均权重总和。

这是我当前的 Cypher 查询:

MATCH (parentP:Product)-[:CONTAINS]->(childP:Product)
WHERE id(parentP) = {productId}
WITH childP
OPTIONAL MATCH (p:Product)<-[:VOTED_FOR]-(v:Vote)-[:VOTED_ON]->(c:Characteristic)
WHERE id(p) = id(childP) AND id(c) IN {characteristicIds}
WITH childP, c, avg(v.weight) as weight
RETURN childP AS product, sum(weight) as weight
ORDER BY weight DESC

我知道 Neo4j 的图形遍历速度非常快,但对于聚合(求和、计数、平均等)却没有那么好。我的系统可以为每个产品的每个特征提供大量投票列表。

请帮助我对这种结构进行去规范化,以避免因大量投票而出现任何性能问题。

Brian 查询的 PROFILE 输出:

Cypher 版本:CYPHER 2.2,规划器:COST。 1482 毫秒内总共 374933 次 db 命中。

【问题讨论】:

  • 也许您可以分享一个示例数据库来帮助我们执行查询?
  • 我已经添加了示例数据库和查询
  • 您希望查询运行多快?我在您的数据库上的第一次运行需要 2.1 秒,而在第一次查询之后需要大约 0.5 秒
  • 这是一个小型示例数据库..真正的数据库要大得多..我想让这个模式/查询独立于投票列表大小的性能

标签: neo4j cypher spring-data-neo4j graph-databases


【解决方案1】:

我不知道我会说 Neo4j 不适合聚合。您可以通过在第二场比赛中特别包含您的 childP 来帮助它节省一些工作:

MATCH (parentP)-[:CONTAINS]->(childP:Product)
WHERE id(parentP) = {productId}
OPTIONAL MATCH childP<-[:VOTED_FOR]-(v:Vote)-[:VOTED_ON]->(c)
WHERE id(c) IN {characteristicIds}
WITH childP, c, avg(v.weight) as weight
RETURN childP AS product, sum(weight) as weight
ORDER BY weight DESC

不过,我想确保我理解您的要求。这个查询是否表现不佳?您是否试图防止它在未来表现不佳?

【讨论】:

  • 感谢您的回答! Rik Van Bruggen 在“Learning Neo4j”电子书中提到了聚合性能 - neo4j.com/book-learning-neo4j (第 40 页) - “如果您试图将不需要大量加入或需要的大量事物、有效集合放在一起在这些集合上进行大量聚合(求和、计数、平均等),那么与其他数据库管理系统相比,图数据库的性能将不那么理想”
  • 另外,当我为每个产品的每个特性添加 1 票时,一切正常。如果每个产品的每个特性都获得 100 票,我可以看到减速。
  • 是的,我想与其他一些数据库相比,它会慢一些。我同意阿尔伯特的观点,你应该做一些分析。我还要做的一件事是将我的查询中的 WITHs 更改为 RETURNs 并删除其余部分以查看性能缓慢的地方。
  • 也许您可以为 Brian 的慢速案例查询附加一个查询计划?您可以在 shell 或浏览器中使用 PROFILE 预先查询。
  • 当然,我已经在我的问题正文中添加了带有查询计划的图像
【解决方案2】:

如果我们谈论性能问题,附加分析信息会很有用:http://neo4j.com/docs/stable/how-do-i-profile-a-query.html

然后将更容易决定在哪里采取行动。

【讨论】:

    【解决方案3】:

    你也可以试试:

    MATCH (c:Characteristic) WHERE id(c) IN {characteristicIds} 
    WITH collect(c) as characteristics
    
    MATCH (parentP:Product)-[:CONTAINS]->(childP:Product)
    WHERE id(parentP) = {productId}
    OPTIONAL MATCH childP<-[:VOTED_FOR]-(v:Vote)
    WITH childP, v, head(filter(c in characteristics WHERE (v)-[:VOTED_ON]->(c))) as c
    WHERE c is not null
    WITH childP, c, avg(v.weight) as weight
    RETURN childP AS product, sum(weight) as weight
    ORDER BY weight DESC
    

    由于对产品的投票比对每个特征的投票要少得多,因此我们从这些开始,然后检查特征。没有分贝很难说。

    【讨论】:

    • 此查询的 PROFILE 输出 - Cypher 版本:CYPHER 2.2,planner:COST。 1624443 总 db hits in 4303 ms。
    • 我希望它对这部分使用优化的ExpandInto操作`WHERE (v)-[:VOTED_ON]->(c)`
    • 但是仍然没有示例数据库,这很难提供帮助:)
    猜你喜欢
    • 2016-12-14
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-12
    • 2016-05-30
    • 2013-08-21
    • 2016-05-13
    相关资源
    最近更新 更多