我正在为推荐系统制作图表,并为用户、类别和产品添加顶点,并添加边来表示它们之间的联系。一种产品可能与类别有联系,并将评级作为它们的属性。用户还可以对每个类别进行评分。所以,它是这样的:
-- User preferences.
SELECT * FROM cypher('RecommenderSystem', $$
MATCH (a:Person {name: 'Abigail'}), (A:Category), (C:Category), (H:Category)
WHERE A.name = 'A' AND C.name = 'C' AND H.name = 'H'
CREATE (a)-[:RATING {rating: 3}]->(C),
(a)-[:RATING {rating: 1}]->(A),
(a)-[:RATING {rating: 0}]->(H)
$$) AS (a agtype);
-- Products rating.
SELECT * FROM cypher('RecommenderSystem', $$
MATCH (product:Product {title: 'Product_Name'}), (A:Category), (C:Category), (H:Category)
WHERE A.name = 'A' AND C.name = 'C' AND H.name = 'H'
CREATE (product)-[:RATING {rating: 0}]->(C),
(product)-[:RATING {rating: 4}]->(A),
(product)-[:RATING {rating: 0}]->(H)
$$) AS (a agtype);
我的推荐系统基于内容过滤,它使用我们了解的关于人和产品的信息作为推荐的结缔组织。因此,为此,有必要进行如下计算:
[(user_rating_C x product_rating_C) + (user_rating_A x product_rating_A) + (user_rating_H x product_rating_H)] / (num_categories x max_rating)
。例如,Abigail 喜欢上面密码查询中的产品的可能性是:
[(3 x 0) + (1 x 4) + (0 x 0)] / (3 x 4) = 0.333 在 0 到 4 的范围内,她可能会讨厌该产品。越接近 4,用户购买或消费该产品的可能性就越大。
但是,我如何检索与人和产品相关的每个边缘评级并用它进行此类计算?
以下查询应该适用于这种情况
SELECT e1/(ct*4) AS factor FROM cypher('RecommenderSystem', $$
MATCH (u: Person)-[e1: RATING]->(v: Category)<-[e2: RATING]-(w:
Product), (c: Category) WITH e1, e2, COUNT(DISTINCT c) AS ct
RETURN SUM(e1.rating* e2.rating)::float, ct
$$) AS (e1 float, ct agtype);
这输出:
factor
-------------------
0.333333333333333
(1 row)
说明
您需要找到人和产品都使用 MATCH 子句设置评级的类别。一旦获得这些评级,这些评级的乘积之和将给出
[(user_rating_C x product_rating_C) + (user_rating_A x product_rating_A) + (user_rating_H x product_rating_H)]
现在除以
的乘积(num_categories x max_rating)
你得到
num_categories
使用COUNT(DISTINCT c)
我假设你已经知道max_rating
.
希望有帮助
编辑
我假设
num_categories
是指系统中类别的总数,而不是唯一与共同的人和产品相关联的类别。如果 num_categories
是与产品和共同人相关的类别数,则将您的 WITH
子句修改为
WITH e1, e2, COUNT(*) AS ct
其他都好
这样的事情可能对你有用:
WITH
'Abigail' AS perName,
[{c: 'A', p: 'prod_1'}, {c: 'C', p: 'prod_9'}, {c: 'H', p: 'prod_4'}] AS x
MATCH (per:Person)-[perRating:RATING]->(cat:Category)<-[prodRating:RATING]-(prod:Product)
WHERE per.name = perName AND ANY(i IN x WHERE cat.name = i.c AND prod.name = i.p)
WITH *, SUM(perRating.rating*prodRating.rating) AS total, MAX(prodRating.rating) AS maxProdRating
RETURN per, total/(SIZE(x) * maxProdRating) AS affinity
perName
是人名,x
是所需类别/产品名称对的列表,affinity
将是计算结果。
注意:即使在数据中找不到
x
中所有需要的对,此查询也会在分母中使用x
的大小。如果不需要,请调整查询。
[更新]
不幸的是,ANY谓词函数不是
openCypher
的一部分,因此Apache AGE不支持它。
更不幸的是,即使list comprehension是
openCypher
的一部分,AGE也不支持它。
但是,在
do支持列表理解的
openCypher
系统上,我们可以替换它:
ANY(i IN x WHERE cat.name = i.c AND prod.name = i.p)
像这样(我们不关心生成列表的内容,所以我们只使用任意
1
元素):
SIZE([i IN x WHERE cat.name = i.c AND prod.name = i.p | 1]) > 0
如果我没理解错的话,你想根据给定的公式计算用户对每个产品的评分:
[(user_rating_C x product_rating_C) + (user_rating_A x product_rating_A) + (user_rating_H x product_rating_H)] / (num_categories x max_rating)
。根据您的模型,max_rating
设置为 4(范围从 0 到 4)。要执行此计算,您可以使用以下查询:
SELECT * FROM cypher('RecommenderSystem', $$
MATCH (a: Person {name: 'Abigail'})-[r1: RATING]->(c: Category)<-[r2: RATING]-(p:Product)
WITH a.name AS person, p.title AS product,
SUM(r1.rating * r2.rating)/(count(c) * 4)::float AS rate
RETURN person AS a, product AS p, rate AS r
$$) AS (a agtype, p agtype, r float);