2

我正在使用嵌入在 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 模块来满足我的推荐需求(使用预计算、过滤、后处理等)。我想过并行化这个,但社区版不支持集群。现在,随着系统中的用户数量与日俱增,我需要考虑一个可扩展的解决方案。

任何人都可以在这里帮助我,了解如何优化查询。

4

1 回答 1

0

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

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

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

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

于 2018-02-15T20:48:48.747 回答