教程:创建图数据模型
本教程旨在帮助您理解如何根据数据预期用途对其进行建模。您将以电影示例数据集作为主要资源。
如需了解数据建模基础的交互式课程,请参阅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']})
此处使用的数据可以在电影示例数据集中找到,也可在 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
有了这些属性,更容易可视化您需要从图中获取什么来回答用例问题。例如:
用例 | 所需步骤 | 查询示例 |
---|---|---|
哪些人参演了电影? |
|
|
哪位人执导了电影? |
|
|
一个人参演了哪些电影? |
|
|
谁是参演电影中最年轻的人? |
|
|
根据 IMDb,某特定年份评分最高的电影是哪一部? |
|
|
唯一标识符
在 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_IN
和 DIRECTED
关系,您可以使用此语句:
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)
然后,为了找出汤姆·汉克斯在《阿波罗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 语句是正确的。编写错误的查询可能会导致您认为数据模型已失败。
例如,在测试中使用不正确的节点标签可能会让您认为数据不存在于图中。
此时,您还可以开始考虑图的可扩展性,以及如果您在具有数百万个节点和关系的图中编写相同的查询,其性能如何。
重构
下一步,重构,是在您完成图测试后进行调整。有关说明,请参阅教程:重构。