教程目录 引自:https://neo4j.com/docs/getting-started/data-modeling/tutorial-data-modeling/
教程:创建图数据模型
本教程旨在帮助您根据预期用途对数据进行建模。您将使用电影示例数据集作为主要资源。
有关数据建模基础的交互式课程,请参阅 GraphAcademy。
定义领域
在本教程中,您将使用电影示例数据集。领域包括电影、出演或导演电影的人,以及对电影进行评分的用户。通过这些实体之间的连接(关系),您可以发现领域中的洞察。
定义用例
在定义领域后,您需要确定应用程序的用例。换句话说,您需要回答哪些问题?
您可以列出问题来帮助确定应用程序的用例。这些问题将帮助您定义应用程序的需求以及图中必须包含的数据。
在本教程中,您的应用程序应能够回答以下问题:
- 哪些人出演了一部电影?
- 哪个人导演了一部电影?
- 某人出演了哪些电影?
- 有多少用户对一部电影进行了评分?
- 谁是出演电影的最年轻的人?
- 某人在电影中扮演了什么角色?
- 根据 IMDb,某一年评分最高的电影是哪部?
- 某演员出演了哪些剧情片?
- 哪些用户给某部电影打了 5 分?
定义目的
在为应用程序设计图数据模型时,您可能需要数据模型和实例模型。
数据模型
数据模型描述了领域中的节点和关系,包括标签、类型和属性。它不包含任何数据,但显示了回答用例所需的信息。
在此阶段,您可以选择使用无代码工具来可视化您的计划。例如,使用 Arrows.app,您可以绘制包含节点标签、关系类型和属性的数据模型:
示例数据模型包括表示人和电影的两个节点,通过两种关系连接。
根据示例领域和初始问题,您可以列出初始模型中需要的信息:
- 区分出演电影、导演电影和评分电影的人。
- 评分的内容、数量以及提交时间。
- 演员在电影中扮演的角色及其年龄。
- 电影的类型。
注意,在模型中,标签、关系类型和属性键遵循特定语法。在 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']})
建议手动使用 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 中,可以创建两个具有完全相同数据的节点。然而,从数据管理和模型角度来看,不同的节点应包含不同的数据。您可以使用唯一标识符确保每个节点都是独立且可区分的实体。
例如,Movie.tmdbID
是一个很好的唯一标识符,因为数据库中可能有不同的电影具有相同的标题,但 tmdbID
属性将不同,从而充当唯一标识符。
建议通过使用唯一性约束来强制执行唯一标识符。有关更多信息,请参阅 Cypher → 创建属性唯一性约束.
关系
关系是节点之间的连接,这些连接是用例中的动词:
- 哪些人出演了一部电影?
- 哪些人导演了一部电影?
命名
为图中的关系选择好的名称(类型)非常重要,并尽可能具体,以便 Neo4j 仅遍历相关连接。
例如,与其使用通用的关系类型(如 CONNECTED_TO
),更倾向于使用更具体且直观的方式描述实体之间的连接。
在本教程示例中,您可以定义以下关系:
ACTED_IN
DIRECTED
关系方向
所有关系必须有方向。在创建时,关系需要显式指定方向,或者通过模式的从左到右顺序推断方向。
在示例用例中,
ACTED_IN
关系必须从 Person
节点指向 Movie
节点:
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
来回答:
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)
查询示例:
MATCH (p:Person {name:'Tom Hanks'})-[r:ACTED_IN]->(m:Movie {title:'Apollo 13'})
RETURN r.roles
添加更多数据
现在您已经创建了节点之间的初始连接,是时候向图中添加更多信息了。例如:
- 有多少用户对一部电影进行了评分?
- 哪些用户给某部电影打了 5 分?
为此,您需要在图中添加用户及其评分信息,这意味着数据模型的更改。
添加用户节点
MERGE (Sandy:User {name: 'Sandy Jones', userID: 1})
MERGE (Clinton:User {name: 'Clinton Spencer', userID: 2})
建议将用户信息与演员和导演分开,因为它们与电影节点的关系不同。
添加评分关系
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 语句正确。错误的查询可能导致错误地认为数据模型失败。
重构
完成测试后,下一步是进行调整。有关说明,请参阅 教程:重构。