Neo4j图数据建模基础|使用特定关系
  iwbGD3gmtxyT 2023年11月02日 65 0

在本文中,我们将学习:

  • 为什么特定的关系是有益的。
  • 动态创建关系以特定化图中的关系。

一、使用特定关系

(一)图中的关系

Neo4j作为本机图数据库实现,以便快速实现遍历关系。


在某些情况下,基于关系类型而不是节点中的属性来查询图形更为有效。


让我们看一个新的用例:

用例#12:演员在特定年份演了哪些电影?

我们可以针对当前图执行下面的查询:

MATCH (p:Actor)-[:ACTED_IN]-(m:Movie)
WHERE p.name = 'Tom Hanks' AND
m.released STARTS WITH '1995'
RETURN m.title AS Movie

返回结果将是:Apollo 13

那么,问题来了:如果Tom Hanks在1995年演了50部电影如何查询呢?自然,查询需要检索Tom Hanks主演的所有电影,然后检查released属性的值。如果汤姆·汉克斯总共出演了1000部电影,又如何呢?那么,又需要评估所有这些电影节点。

下面是另一个新用例:

用例#13:哪些演员或导演在特定年份工作?

同样,我们可以对当前图形执行下面的查询:

MATCH (p:Person)--(m:Movie)
WHERE m.released STARTS WITH '1995'
RETURN DISTINCT p.name as `Actor or Director`

返回值将是:Tom Hanks 和 Martin Scorsese

此查询的性能更差,因为为了返回结果,必须检索所有电影节点。可以想象,如果图表包含数百万部电影,那么这将是一个非常昂贵的查询。

(二)重构以专门化关系

关系的遍历速度很快,并且不会占用图形中的大量空间。在前两个查询中,数据模型将受益于节点之间的专门关系。

因此,例如,除了ACTED_INDIRECTED关系之外,我们还可以添加包含特定年份信息的关系。

  • ACTED_IN_1992
  • ACTED_IN_1993
  • ACTED_IN_1995
  • DIRECTED_1992
  • DIRECTED_1995

首先,对于大型电影图来说,似乎有很多关系,但如果最新的两个查询都是重要的用例,那么这是值得做的。

下面是我们的实例模型目前的样子:

Neo4j图数据建模基础|使用特定关系_用例


在我们特定化关系的大多数情况下,我们会保留原始的泛型关系,因为现有查询仍然需要使用它们。

重构图以添加这些特定关系的代码中可以使用APOC库来实现。

下面是重构图中ACTED_IN关系的代码,将在接下来的任务中执行:

MATCH (n:Actor)-[r:ACTED_IN]->(m:Movie)
CALL apoc.merge.relationship(n,
'ACTED_IN_' + left(m.released,4),
{},
m ) YIELD rel
RETURN COUNT(*) AS `Number of relationships merged`

其中使用了apoc.merge.relationship过程,允许我们在图中动态创建关系。它使用电影节点的released属性中最左边的4个字符来创建关系的名称。

重构的结果是,前两个查询可以被重写,对于大型图来说,它们的性能肯定会更好:

以下是第一个查询的重写形式:

MATCH (p:Actor)-[:ACTED_IN_1995]-(m:Movie)
WHERE p.name = 'Tom Hanks'
RETURN m.title AS Movie

对于此查询,将遍历特定的关系,但检索到的电影节点较少。

下面是我们重写第二个查询的样子:

MATCH (p:Person)-[:ACTED_IN_1995|DIRECTED_1995]-()
RETURN p.name as `Actor or Director`

对于此查询,因为年份是关系类型,所以我们根本不需要检索任何电影节点。

二、特定化ACTED_IN和DIRECTED 关系

接下来,我们将继续修改实例模型以匹配下面的图。此图中使用了特定的ACTED_IN 和 DIRECTED关系。

Neo4j图数据建模基础|使用特定关系_用例_02

实现这一目标,需要两步操作:


  • 重构所有的ACTED_IN 关系
  • 重构所有的 DIRECTED关系

(一)重构所有的ACTED_IN 关系

执行以下代码,根据每个节点发布属性的年份创建一组新的关系。

例如,阿波罗13号于1995年上映,因此将在阿波罗13号和电影中的任何演员之间创建一个额外的ACTED\u in\u 1995。

MATCH (n:Actor)-[:ACTED_IN]->(m:Movie)
CALL apoc.merge.relationship(n,
'ACTED_IN_' + left(m.released,4),
{},
{},
m ,
{}
) YIELD rel
RETURN count(*) AS `Number of relationships merged`;

它应该创建5个关系。

通过此重构,我们现在可以确认重写的查询适用于用例:

用例#12:演员在特定年份演了哪些电影?

为了验证查询是否已成功运行,我们可以尝试使用新创建的ACTED_IN_1995关系来查看Tom Hanks在1995年发布的电影中扮演的角色。

MATCH (p:Actor)-[:ACTED_IN_1995]->(m:Movie)
WHERE p.name = 'Tom Hanks'
RETURN m.title AS Movie

返回结果只有一部电影:Apollo 13


(二)重构所有的 DIRECTED关系

我们可以使用相同的方法在导演和电影之间创建DIRECTED_{year}关系。

修改刚刚运行的代码以匹配以下模式。

MATCH (n:Director)-[:DIRECTED]→(m:Movie)

然后修改过程调用,将关系的前缀更改为DIRECTED_

它应该创建2个关系。

(三)测试模型

通过这次重构和之前的重构,我们现在可以确认重写的查询适用于用例:

用例#12:演员在特定年份演了哪些电影?

MATCH (p:Person)-[:ACTED_IN_1995|DIRECTED_1995]->()
RETURN p.name as `Actor or Director`

返回结果是:Tom Hanks 和 Martin Scorsese

三、特定化RATED 关系

在上面的任务中,我们向ACTED_IN和DIRECTED关系的图中添加了许多特定的关系。实现此目标需要3个步骤。

在我们当前的图中,用户节点和电影节点之间存在RATED关系。

假设我们想要改进此查询的性能,于是出现下面的新任务要求:

用例#9:哪些用户给电影的评分为5?

(一)为什么要建立特定的关系?

让我们举一个实际的例子。运行下面的Cypher代码,我们不妨用电影Apollo 13测试此用例。

MATCH (u:User)-[r:RATED]->(m:Movie)
WHERE m.title = 'Apollo 13' AND
r.rating = 5
RETURN u.name as Reviewer

返回一个用户:Sandy Jones

如果图中有数千个用户呢。此查询需要遍历所有RATED关系并评估RATED属性。对于大型图,求值越多意味着查询处理时间越长。

在本次挑战中,您将专门化RATED关系以反映RATED。与重构不同,重构中我们从节点中删除了genres 和 languages 属性,我们不会从RATED关系中删除RATED属性。这是因为我们可能需要它来进行查询,该查询具有对关系的引用,并且需要返回评级值。

下面是我们将重构的实例模型:

Neo4j图数据建模基础|使用特定关系_返回结果_03

(二)创建特定的RATED_{rating}关系

要通过此挑战,必须使用上面介绍中获得的知识,并使用apoc.merge.relationship合并图中的关系。

您必须搜索的模式是:

MATCH (u:User)-[r:RATED]→(m:Movie)

作为第二个参数传递的关系类型应为:

'RATED_'+ r.rating


引用

​https://graphacademy.neo4j.com/courses/modeling-fundamentals/7-using-specific-relationships/1-specific-relationships/​

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
iwbGD3gmtxyT