【问题标题】:Neo4j Recommendation Cypher Query OptimizationNeo4j 推荐 Cypher 查询优化
【发布时间】:2018-02-15 09:53:11
【问题描述】:

我正在使用嵌入在 Java 应用程序中的 Neo4j 社区版进行推荐。我制作了一个自定义函数,其中包含比较两个实体(即产品和用户)的复杂逻辑。这两个实体都作为图中的节点出现,并且每个都有超过 20 个属性用于比较目的。例如。我以以下格式调用此函数:

match (e:User {user_id:"some-id"}) with e
match (f:Product {product_id:"some-id"}) with e,f
return e,f,findComparisonValue(e,f) as pref_value; 

此函数调用平均需要大约 4-5 毫秒才能运行。现在,为了向特定用户推荐最佳产品,我编写了一个密码查询,它遍历所有产品,计算 pref_value 并对它们进行排名。我的密码查询如下所示:

MATCH (source:User) WHERE id(source)={id} with source 
MATCH (reco:Product) WHERE reco.is_active='t'  
with reco, source, findComparisonValue(source, reco) as score_result 
RETURN distinct reco, score_result.score as score, score_result.params as params, score_result.matched_keywords as matched_keywords 
order by score desc

关于图结构的一些见解:

Total Number of nodes: 2 million
Total Number of relationships: 20 million
Total Number of Users: 0.2 million
Total Number of Products: 1.8 million

上述密码查询需要 10 多秒,因为它正在遍历所有产品。在这个密码查询之上,我正在使用 graphaware-reco 模块来满足我的推荐需求(使用预计算、过滤、后处理等)。我想过并行化这个,但社区版不支持集群。现在,随着系统中的用户数量与日俱增,我需要考虑一个可扩展的解决方案。

谁能帮我看看如何优化查询。

【问题讨论】:

  • 根据您的描述,您似乎正在使用节点属性来计算两个节点之间的相似度。乍一看,我认为这不是正确的方法...也许您应该重新考虑您的模型并尝试使用 Cypher 将繁重的工作委托给 Neo4j 引擎。
  • 也许你应该使用节点和关系而不是属性。
  • 谢谢@BrunoPeres。我需要重新考虑如何使用关系而不是属性。然而,大多数属性都是实数(例如用户工资),因此不知道如何将这些信息转换为关系。有什么建议吗?

标签: neo4j cypher graphaware


【解决方案1】:

正如其他人所评论的那样,在单个查询中进行可能数百万次的重要计算将会很慢,并且没有利用 neo4j 的优势。您应该研究修改数据模型和计算,以便可以利用关系和/或索引。

与此同时,您的第二个查询有很多建议:

  1. 确保您已为:Product(is_active) 创建了index,这样就不必扫描所有产品。 (顺便说一句,如果该属性实际上应该是布尔值,那么请考虑将其设为布尔值而不是字符串。)

  2. RETURN 子句不需要DISTINCT 运算符,因为无论如何所有结果行都应该是不同的。这是因为每个 reco 值已经是不同的。删除该关键字应该会提高性能。

【讨论】:

  • 谢谢@cybersam。我已经索引了 is_active 属性并将尝试在查询中删除 distinct。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多