neo4j 模式反规范化
Neo4j schema denormalization
在我的 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 次数据库命中。
我不知道我会说 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
不过,我想确保我理解您的要求。这个查询性能不佳吗?您是否正在努力防止它在未来表现不佳?
如果我们谈论的是性能问题,附上分析信息会很有用:http://neo4j.com/docs/stable/how-do-i-profile-a-query.html
然后会更容易决定在哪里行动。
您也可以试试:
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
由于对产品的投票比对每个特征的投票少得多,我们从这些开始,然后根据特征进行检查。没有数据库就很难说了。
在我的 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 次数据库命中。
我不知道我会说 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
不过,我想确保我理解您的要求。这个查询性能不佳吗?您是否正在努力防止它在未来表现不佳?
如果我们谈论的是性能问题,附上分析信息会很有用:http://neo4j.com/docs/stable/how-do-i-profile-a-query.html
然后会更容易决定在哪里行动。
您也可以试试:
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
由于对产品的投票比对每个特征的投票少得多,我们从这些开始,然后根据特征进行检查。没有数据库就很难说了。