我们试图使用Neo4j中数据的余弦相似度构建一个在线推荐器(协同过滤用户-用户)。
**不同的是输入数据集是布尔偏好(而不是评级)**对于100万用户X~700产品。例如。User_ID,Product_ID,偏好11,48989399,1
为用户和产品创建节点,索引为id(user_id,product_id)
我试着写一个密码查询来根据公式获得前20个最近的邻居
相似性=(两个用户都喜欢的产品)/sqrt(用户喜欢的产品数1)*sqrt(用户喜欢的产品数2)
以下是查询:
MATCH (a:Users)-[d]->() using index a:Users(id) where a.id =1
WITH a.id as user1, count(d) as user1_prod
MATCH (a:Users)-[]->()<-[dd]-others using index a:Users(id) where a.id =1
WITH user1, user1_prod, others, count(dd) as intersect
MATCH others-[b1]->() with user1, others.id as user2, intersect, user1_prod, count(b1) as user2_prod
WITH user1, user2, intersect/(sqrt(user1_prod) * sqrt(user2_prod)) as similarity
RETURN user2, similarity order by similarity desc limit 20;
查询在接近22秒后返回结果,产品推荐可扩展且快速。
有没有更好的方法来编写相似性的密码,因为图形在未来的场景中可能会更密集。
详细信息:内核版本Neo4j-图形数据库内核(neo4j-core),版本:2.1.6
772 772节点
mapped_memory3078M
CentOS 6.6版(最终版)
如果您将其重写为Neo4j服务器扩展会更快,那么您可以使用node. get学位()
,这是对节点学位的恒定时间检索。
核心代码如下所示,您可以通过提取用于获取每个用户的产品的函数来简化它。
Node user1 = db.findByLabelAndProperty(User,"id",1);
long likes1 = user1.getDegree(LIKES,OUTGOING);
Set<Node> products1 = new HashSet<>(likes1);
for (Relationship rel = user1.getRelationships(LIKES,OUTGOING)) {
products1.add(rel.getEndNode());
}
Node user2 = db.findByLabelAndProperty(User,"id",2);
long likes2 = user2.getDegree(LIKES,OUTGOING);
Set<Node> products2 = new HashSet<>(likes2);
for (Relationship rel = user2.getRelationships(LIKES,OUTGOING)) {
products2.add(rel.getEndNode());
}
products1.retainAll(products2);
return products1.size() / (sqrt(likes1) * sqrt(likes2));