如何使用不同边的属性进行计算

问题描述 投票:0回答:3

我正在为推荐系统制作图表,并为用户、类别和产品添加顶点,并添加边来表示它们之间的联系。一种产品可能与类别有联系,并将评级作为它们的属性。用户还可以对每个类别进行评分。所以,它是这样的:

-- 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,用户购买或消费该产品的可能性就越大。

但是,我如何检索与人和产品相关的每个边缘评级并用它进行此类计算?

postgresql cypher graph-theory apache-age opencypher
3个回答
2
投票

以下查询应该适用于这种情况

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

其他都好


1
投票

这样的事情可能对你有用:

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

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);

我添加了另一个产品(类别 C 的评级为 0,类别 A 的评级为 1,类别 H 的评级为 3)并且此查询给了我这些结果:

© www.soinside.com 2019 - 2024. All rights reserved.