教程:创建图数据模型

本教程旨在帮助您理解如何根据数据预期用途对其进行建模。您将以电影示例数据集作为主要资源。

如需了解数据建模基础的交互式课程,请参阅GraphAcademy

定义领域

在本教程中,您将使用电影示例数据集,该领域包括电影、在电影中表演或执导的人,以及给电影评分的用户。正是这些实体之间的连接(关系)让您获得了有关领域的数据洞察。

定义用例

定义领域后,您需要识别应用程序的用例。换句话说,您试图回答哪些问题?

您可以列出**问题清单**,以帮助您识别应用程序用例。这些问题将帮助您定义应用程序所需的内容,以及图中必须包含哪些数据。

对于本教程,您的应用程序应该能够回答以下问题

  • 哪些人参演了电影?

  • 哪位人执导了电影?

  • 一个人参演了哪些电影?

  • 有多少用户给电影评了分?

  • 谁是参演电影中最年轻的人?

  • 一个人在电影中扮演了什么角色?

  • 根据 IMDb,某特定年份评分最高的电影是哪一部?

  • 演员参演了哪些戏剧电影?

  • 哪些用户给电影评了5分?

定义目的

在为应用程序设计图数据模型时,您可能需要数据模型和实例模型。

数据模型

数据模型描述了领域中的节点和关系,并包括标签、类型和属性。它不包含任何数据,但显示了回答用例可能需要哪些信息。

在此阶段,您可以选择使用无代码工具来可视化您的计划。例如,使用Arrows.app,您可以草拟一个包含节点标签、关系类型和属性的数据模型。

考虑到您的示例领域和初始问题,您可以列出第一个模型中需要包含的信息

  • 区分参演电影的人、执导电影的人和给电影评分的人。

  • 给出了哪些评分、有多少评分以及何时提交的。

  • 演员在电影中扮演的角色以及他们的年龄。

  • 电影的类型。

  • 等等。

请注意,在模型中,标签、关系类型和属性键遵循特定的语法。在 Cypher® 中,这些被称为标识符,并且与字符串值一样,它们是区分大小写的。

有关更多信息,请参阅 Cypher 风格指南。虽然不是强制性的,但建议:

  • 标签首字母大写并应使用驼峰命名法(例如,PersonMovieImdbUser)。

  • 关系类型应使用全大写字母和下划线作为分隔符(例如,DIRECTEDACTED_IN)。

  • 节点或关系的属性键**不**应大写,可以使用驼峰命名法(例如 nameuserID)。

在创建初始模型的这个阶段,请关注模型的高层设计,即您的实体如何连接。定义实体步骤描述了如何在图中分配特定信息(例如,作为节点、关系、属性等)的更详细视图。

实例模型

实例模型是存储和处理在实际模型中的数据的表示。您可以使用实例模型来针对您的用例进行测试。

要创建实例模型,您需要一些示例数据并将其加载到您选择的部署中。当前的示例是一个小但具有代表性的数据集。

CREATE (Apollo13:Movie {title: 'Apollo 13', tmdbID: 568, released: '1995-06-30', imdbRating: 7.6, genres: ['Drama', 'Adventure', 'IMAX']})
CREATE (TomH:Person {name: 'Tom Hanks', tmdbID: 31, born: '1956-07-09'})
CREATE (MegR:Person {name: 'Meg Ryan', tmdbID: 5344, born: '1961-11-19'})
CREATE (DannyD:Person {name: 'Danny DeVito', tmdbID: 518, born: '1944-11-17'})
CREATE (JackN:Person {name: 'Jack Nicholson', tmdbID: 514, born: '1937-04-22'})
CREATE (SleeplessInSeattle:Movie {title: 'Sleepless in Seattle', tmdbID: 858, released: '1993-06-25', imdbRating: 6.8, genres: ['Comedy', 'Drama', 'Romance']})
CREATE (Hoffa:Movie {title: 'Hoffa', tmdbID: 10410, released: '1992-12-25', imdbRating: 6.6, genres: ['Crime', 'Drama']})

此处使用的数据可以在电影示例数据集中找到,也可在 Browser 和 Aura 指南中获取。但是,为了练习数据建模,建议您使用 Cypher 手动添加数据。

定义实体

实例模型可帮助您预览数据将如何作为节点、关系和属性存储。下一步是用更多细节细化您的模型。

标签

应用程序用例中的主要名词在您的模型中表示为节点,并可用作**节点标签**。例如:

  • 哪个参演了电影

  • 有多少用户电影评了分?

因此,初始模型中的节点是 **Person**、**Movie** 和 **User**。请注意,创建模型是一个迭代过程,在重构之后,您的模型可能会有所不同。

图数据库概念中了解有关标签的更多信息。

节点属性

您可以使用节点属性来:

锚点(查询的起点)
MATCH (p:Person {name: 'Tom Hanks'})-[:ACTED_IN]-(m:Movie)
RETURN m
遍历图(导航)
MATCH (p:Person)-[:ACTED_IN]-(m:Movie {title: 'Apollo 13'})-[:RATED]-(u:User)
RETURN p,u
从查询中返回数据
MATCH (p:Person {name: 'Tom Hanks'})-[:ACTED_IN]-(m:Movie)
RETURN m.title, m.released

有了这些属性,更容易可视化您需要从图中获取什么来回答用例问题。例如:

用例 所需步骤 查询示例

哪些人参演了电影?

  • 按其**标题**检索电影。

  • 返回演员的**姓名**。

MATCH (m:Movie {title:'Hoffa'})<-[r:ACTED_IN]-(p:Person)
RETURN p.name

哪位人执导了电影?

  • 按其**标题**检索电影。

  • 返回导演的**姓名**。

MATCH (m:Movie {title:'Hoffa'})<-[r:DIRECTED]-(p:Person)
RETURN p.name

一个人参演了哪些电影?

  • 按其**姓名**检索人。

  • 返回电影的**标题**。

MATCH (p:Person {name:'Tom Hanks'})-[:ACTED_IN]->(m:Movie)
RETURN m.title

谁是参演电影中最年轻的人?

  • 按其**标题**检索电影。

  • 评估演员的**年龄**。

  • 返回年龄最小的演员的**姓名**。

MATCH (m:Movie {title:'Sleepless in Seattle'})<-[r:ACTED_IN]-(p:Person)
RETURN p.name, p.born
ORDER BY p.born ASC
LIMIT 1

根据 IMDb,某特定年份评分最高的电影是哪一部?

  • 检索某特定年份**上映**的所有电影。

  • 评估 IMDb 评分

  • 返回评分最高的电影的电影**标题**。

MATCH (m:Movie {release:date('1995')})
RETURN m.title, m.imdbRating
ORDER BY m.imdbRating DESC
LIMIT 1

唯一标识符

在 Cypher 中,可以创建两个具有完全相同数据的不同节点。然而,从数据管理和模型角度来看,不同的节点应该包含不同的数据。您可以使用**唯一标识符**来确保每个节点都是一个独立且独特的实体。

在初始实例模型中,这些是为 Movies 节点设置的属性:

  • Movie.title (字符串)

  • Movie.tmdbID (整数)

  • Movie.released (日期)

  • Movie.imdbRating (0-10 之间的小数)

  • Movie.genres (字符串列表)

以及 Person 节点:

  • Person.name (字符串)

  • Person.tmdbID (整数)

  • Person.born (日期)

Movie 节点属性 tmdbID 是唯一标识符的一个很好的例子,因为数据库中可能存在标题相同的不同电影,但该属性将不同,因此可作为唯一标识符。

强烈建议您通过使用唯一性约束来强制执行唯一标识符。有关此主题的更多信息,请参阅Cypher → 创建属性唯一性约束

关系

关系是节点之间的连接,这些连接是您用例中的动词。

  • 哪个人参演了电影?

  • 哪个人执导了电影?

乍一看,连接似乎很简单,但它们的微观和宏观设计可以说是图性能中最关键的因素。首先,将关系视为“连接是动词”的视角运作良好,但随着模型的推进,您还将学习其他重要的考量因素。

命名

为图中的关系选择好的名称(类型)并尽可能具体,以便 Neo4j 仅遍历相关的连接,这一点很重要。

例如,与其使用通用关系类型(例如 CONNECTED_TO)连接两个节点,不如更具体、更直观地描述这些实体连接的方式。

对于本教程示例,您可以将关系定义为:

  • ACTED_IN

  • DIRECTED

有了这些选项,您就可以规划关系的走向了。

关系方向

所有关系都必须有方向。创建时,关系需要明确指定其方向,或者通过模式的从左到右顺序推断。

在示例用例中,必须创建 ACTED_IN 关系,使其从 Person 节点指向 Movie 节点。

要添加所有 ACTED_INDIRECTED 关系,您可以使用此语句:

MERGE (TomH)-[:ACTED_IN]->(Apollo13)
MERGE (TomH)-[:ACTED_IN]->(SleeplessInSeattle)
MERGE (MegR)-[:ACTED_IN]->(SleeplessInSeattle)
MERGE (DannyD)-[:ACTED_IN]->(Hoffa)
MERGE (DannyD)-[:DIRECTED]->(Hoffa)
MERGE (JackN)-[:ACTED_IN]->(Hoffa)

您的图现在应该看起来像这样:

您始终可以使用查询 MATCH (n) RETURN n 来查看您的图是什么样子。

关系属性

关系的属性用于丰富两个节点的关联方式。当您需要知道两个节点**如何**关联而不仅仅是它们关联时,您可以使用关系属性进一步定义该关系。

示例问题“一个人在电影中扮演了什么角色?”可以通过 ACTED_IN 关系中的属性 roles 来回答。

请注意,关于角色的信息需要在检索之前添加到图中。您可以为此使用此 Cypher 语句:

MERGE (TomH)-[:ACTED_IN {roles:'Jim Lovell'}]->(Apollo13)
MERGE (TomH)-[:ACTED_IN {roles:'Sam Baldwin'}]->(SleeplessInSeattle)
MERGE (MegR)-[:ACTED_IN {roles:'Annie Reed'}]->(SleeplessInSeattle)
MERGE (DannyD)-[:ACTED_IN {roles:'Robert "Bobby" Ciaro'}]->(Hoffa)
MERGE (JackN)-[:ACTED_IN {roles:'Hoffa'}]->(Hoffa)

然后,为了找出汤姆·汉克斯在《阿波罗13号》中扮演的角色,您可以使用以下语句:

MATCH (p:Person {name:'Tom Hanks'})-[r:ACTED_IN]->(m:Movie {title:'Apollo 13'})
RETURN r.roles

添加新的关系属性后,您的图现在应该看起来像这样:

添加更多数据

现在您已经创建了节点之间的第一个连接,是时候向图中添加更多信息了。这样,您可以回答更多问题,例如:

  • 有多少用户给电影评了分?

  • 哪些用户给电影评了5分?

要回答这些问题,您的图中需要有关于用户及其评分的信息,这意味着您的数据模型将发生变化。请注意,随着新数据(例如 ACTED_IN 关系中的 roles 属性)的添加,您的初始数据模型已经在此过程中进行了更新。

您可以首先将用户添加到图中:

MERGE (Sandy:User {name: 'Sandy Jones', userID: 1})
MERGE (Clinton:User {name: 'Clinton Spencer, userID: 2'})

虽然可以将用户信息添加为 Person 节点,但建议将他们与演员和导演分开,因为他们与 Movie 节点的关系不同。

然后,通过包含 rating 属性的 RATED 关系将 User 节点连接到 Movie 节点。

MERGE (Sandy)-[:RATED {rating:5}]->(Apollo13)
MERGE (Sandy)-[:RATED {rating:4}]->(SleeplessInSeattle)
MERGE (Clinton)-[:RATED {rating:3}]->(Apollo13)
MERGE (Clinton)-[:RATED {rating:3}]->(SleeplessInSeattle)
MERGE (Clinton)-[:RATED {rating:3}]->(Hoffa)

您的图现在应该看起来像这样:

测试模型

在用一小部分测试数据填充图以实现数据模型后,您现在应该对其进行测试,以确保它满足每个用例

例如,如果您想测试用例“哪些人参演了电影?”,您可以运行以下查询:

MATCH (p:Person)-[:ACTED_IN]-(m:Movie)
WHERE m.title = 'Sleepless in Seattle'
RETURN p.name

这只是一个简单的测试示例。在您遍历用例时,您可能会想到需要向图中添加更多数据以完成测试。

此外,请确保用于测试用例的 Cypher 语句是正确的。编写错误的查询可能会导致您认为数据模型已失败。

例如,在测试中使用不正确的节点标签可能会让您认为数据不存在于图中。

此时,您还可以开始考虑图的可扩展性,以及如果您在具有数百万个节点和关系的图中编写相同的查询,其性能如何。

重构

下一步,重构,是在您完成图测试后进行调整。有关说明,请参阅教程:重构

© . All rights reserved.