我正在使用嵌入在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毫秒才能运行。现在,为了向特定用户推荐最佳产品,我编写了一个cypher查询,它迭代所有产品,计算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
上面的cypher查询在迭代所有产品时花费的时间超过10秒。在这个密码查询之上,我使用graphaware-reco模块来满足我的推荐需求(使用预计算,过滤,后处理等)。我想过将其并行化,但社区版不支持群集。现在,随着系统中用户数量的日益增加,我需要考虑可扩展的解决方案。
有人可以帮我解决一下如何优化查询。
答案 0 :(得分:0)
正如其他人所评论的那样,在单个查询中进行数百万次重要计算会变得缓慢,并且不会利用neo4j的优势。您应该调查修改数据模型和计算,以便可以利用关系和/或索引。
与此同时,您的第二个问题需要提出一些建议:
确保您为:Product(is_active)
创建了index,因此无需扫描所有产品。 (顺便说一下,如果该属性实际上应该是一个布尔值,那么考虑将它设为布尔值而不是字符串。)
RETURN
子句不需要DISTINCT
运算符,因为无论如何所有结果行都应该是不同的。这是因为每个reco
值都已经不同了。删除该关键字可以提高效果。