教程:创建图数据模型
本教程旨在帮助您根据预期用途来构建数据模型。您将使用 电影示例数据集 作为主要参考。
|
如需参加关于数据建模基础知识的互动课程,请访问 GraphAcademy。 |
定义领域
在本教程中,您将使用 电影示例数据集。该领域包括电影、参演或执导电影的人员,以及为电影评分的用户。正是这些实体之间的连接(关系)为您提供了关于该领域的洞察。
定义用例
在定义好领域后,您需要明确应用程序的用例。换句话说,您想要回答哪些问题?
您可以列出一系列问题来帮助您识别应用程序的用例。这些问题将有助于您定义从应用程序中需要什么,以及图数据库中必须包含哪些数据。
对于本教程,您的应用程序应该能够回答以下问题:
-
哪些人参演了某部电影?
-
哪个人执导了某部电影?
-
一个人参演了哪些电影?
-
有多少用户为某部电影评分?
-
参演电影的人中最年轻的是谁?
-
一个人在电影中扮演了什么角色?
-
根据 IMDb 数据,某一年评分最高的电影是哪一部?
-
一个演员参演过哪些剧情片?
-
哪些用户给某部电影打了 5 分?
定义目的
在为应用程序设计图数据模型时,您可能既需要数据模型,也需要实例模型。
数据模型
数据模型描述了领域中的节点和关系,并包括标签、类型和属性。它不包含任何具体数据,但展示了回答用例所需的信息。
在此阶段,您可以选择使用 无代码工具 来可视化您的计划。例如,使用 Arrows.app,您可以草拟一个包含节点标签、关系类型和属性的数据模型。
结合您的示例领域和初步问题,您可以列出第一个模型中需要包含的信息:
-
区分参演电影的人、执导电影的人以及为电影评分的人。
-
给出了哪些评分、评分数量以及提交时间。
-
演员在电影中扮演的角色及其年龄。
-
电影的类型。
-
等等。
请注意,在模型中,标签、关系类型和属性键遵循特定的语法。在 Cypher® 中,这些被称为标识符,它们区分大小写(字符串值也区分大小写)。
有关详细信息,请参阅 Cypher 样式指南。虽然不是强制性的,但建议遵循:
-
标签首字母大写,并应使用驼峰命名法(例如:
Person,Movie,ImdbUser)。 -
关系类型应全部大写,并使用下划线作为分隔符(例如:
DIRECTED,ACTED_IN)。 -
节点或关系的属性键不大写,可以使用驼峰命名法(例如:
name,userID)。
|
在创建初始模型的这个阶段,请专注于模型的高级设计,即实体如何连接。“定义实体”步骤描述了关于如何在图中分配特定信息(例如,作为节点、关系、属性等)的更详细视图。 |
实例模型
实例模型是实际模型中存储和处理的数据的表示。您可以使用实例模型针对用例进行测试。
要创建实例模型,您需要有一些示例数据并将其加载到您选择的 部署环境 中。当前的示例是一个小型但具有代表性的数据集。
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']})
|
此处使用的数据可以在 电影示例数据集 中找到,该数据集也可在浏览器和 Aura 指南中获取。但是,为了练习数据建模,建议您使用 Cypher 手动添加数据。 |
定义实体
实例模型有助于您预览数据将如何作为节点、关系和属性进行存储。下一步是使用更多细节来完善您的模型。
标签
应用程序用例中的主名词在模型中表示为节点,并可用作节点标签。例如:
-
哪个 人 (Person) 参演了某部 电影 (Movie)?
-
有多少 用户 (User) 为某部 电影 (Movie) 评分?
因此,您初始模型中的节点为 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
通过这些属性,可以更轻松地可视化从图中获取什么信息来回答用例问题。例如:
| 用例 | 所需步骤 | 查询示例 |
|---|---|---|
哪些人参演了某部电影? |
|
|
哪个人执导了某部电影? |
|
|
一个人参演了哪些电影? |
|
|
参演电影的人中最年轻的是谁? |
|
|
根据 IMDb,某一年评分最高的电影是哪一部? |
|
|
唯一标识符
在 Cypher 中,可以创建两个数据完全相同的不同节点。然而,从数据管理和模型的角度来看,不同的节点应该包含不同的数据。您可以使用唯一标识符来确保每个节点都是一个独立且可区分的实体。
在初始实例模型中,这些是为 Movie 节点设置的属性:
-
Movie.title(字符串) -
Movie.tmdbID(整数) -
Movie.released(日期) -
Movie.imdbRating(0-10 之间的小数) -
Movie.genres(字符串列表)
对于 Person 节点:
-
Person.name(字符串) -
Person.tmdbID(整数) -
Person.born(日期)
Movie 节点的属性 tmdbID 是唯一标识符的一个很好的例子,因为数据库中可能有不同电影具有相同的标题,但该属性将不同,从而充当唯一标识符。
|
强烈建议您通过使用唯一性约束来强制执行唯一标识符。阅读更多关于此主题的内容,请参阅 Cypher → 创建属性唯一性约束。 |
关系
关系是节点之间的连接,这些连接是您用例中的动词:
-
哪个人 参演 (acted in) 了某部电影?
-
哪个人 执导 (directed) 了某部电影?
乍一看,连接似乎很简单,但它们的微观和宏观设计可以说是图数据库性能中最关键的因素。首先,将关系视为“连接即动词”非常有效,但随着您模型设计能力的提升,您会学到其他重要的考量因素。
命名
为图中的关系选择好的名称(类型)非常重要,并且要尽可能具体,以便 Neo4j 只遍历相关的连接。
例如,与其使用通用关系类型(如 CONNECTED_TO)连接两个节点,不如更具体、更直观地描述这些实体连接的方式。
对于本教程示例,您可以将关系定义为:
-
ACTED_IN -
DIRECTED
有了这些选项,您已经可以规划关系的方向了。
关系方向
所有关系都必须有方向。创建时,关系需要明确指定其方向,或者由模式中从左到右的顺序推断得出。
在示例用例中,必须创建从 Person 节点指向 Movie 节点的 ACTED_IN 关系。
要添加所有 ACTED_IN 和 DIRECTED 关系,您可以使用此语句:
MATCH (TomH:Person {name:'Tom Hanks'})
MATCH (MegR:Person {name:'Meg Ryan'})
MATCH (DannyD:Person {name:'Danny DeVitto'})
MATCH (JackN:Person {name:'Jack Nicholson'})
MATCH (Apollo13:Movie {title:'Apollo 13'})
MATCH (SleeplessInSeattle:Movie {title:'Sleepless in Seattle'})
MATCH (Hoffa:Movie {title:'Hoffa'})
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)
现在您的图应该看起来像这样:
|
您可以随时使用查询 |
关系属性
关系的属性用于丰富两个节点的关联方式。当您不仅需要知道两个节点是否相关,还需要知道它们如何相关时,可以使用关系属性来进一步定义这种关系。
示例问题“一个人在电影中扮演了什么角色?”可以通过 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)
然后,为了找出 Tom Hanks 在《阿波罗 13 号》(Apollo 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'})
|
虽然可以将用户信息添加为 |
然后,通过包含 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 语句是正确的。编写错误的查询可能会导致误认为数据模型失败。
例如,在测试中使用错误的节点标签可能会让您以为数据在图中不存在。
此时,您还可以开始考虑图的扩展性,以及如果在包含数百万个节点和关系的图中编写相同的查询,其 性能表现 会如何。
重构
下一步,重构,是在测试完图之后进行调整。有关说明,请参阅 教程:重构图数据模型。