导入数据

本教程提供了详细示例,以说明使用命令 neo4j-admin database import 从 CSV 文件导入数据的功能。该导入命令用于从 CSV 文件加载大量数据,并支持对正在运行或已停止的 Neo4j 数据库管理系统进行完整和增量导入。

neo4j-admin database import 命令不创建数据库,该命令仅导入数据并使其可用于数据库。在执行 neo4j-admin database import 命令之前,数据库不得存在,且数据库应在此之后创建。如果数据库已存在,该命令将以错误消息退出。

关系通过连接节点 ID 创建,每个节点应具有唯一的 ID,以便在节点之间创建关系时可以引用。在以下示例中,节点 ID 作为属性存储在节点上。如果您不希望 ID 在导入完成后作为属性持久化,则不要在 :ID 字段中指定属性名称。

这些示例展示了如何在独立 Neo4j 数据库管理系统中导入数据。它们使用

  • Neo4j 压缩包(Unix 控制台应用程序)。

  • $NEO4J_HOME 作为当前工作目录。

  • 默认数据库 neo4j

  • Neo4j 安装的 import 目录,用于存储所有 CSV 文件。但是,CSV 文件可以位于您文件系统的任何目录中。

  • UNIX 风格的路径。

  • 命令 neo4j-admin database import

实用技巧
  • CSV 文件头格式的详细信息可在CSV 文件头格式处找到。

  • 要显示可用数据库,请对 system 数据库使用 Cypher 查询 SHOW DATABASES

  • 要删除数据库,请对 system 数据库使用 Cypher 查询 DROP DATABASE database_name

  • 要创建数据库,请对 system 数据库使用 Cypher 查询 CREATE DATABASE database_name

导入小型数据集

在此示例中,您将导入一个包含节点和关系的小型数据集。该数据集被拆分为三个 CSV 文件,每个文件都有一个描述数据的标题行。

数据

该数据集包含有关电影、演员和角色的信息。电影和演员的数据存储为节点,角色存储为关系。

您要导入数据的文件是

  • movies.csv

  • actors.csv

  • roles.csv

movies.csv 中的每部电影都有一个 ID、一个 title 和一个 year,作为属性存储在节点中。movies.csv 中的所有节点还具有标签 Movie。一个节点可以有多个标签,正如您在 movies.csv 中所看到的,有些节点也具有标签 Sequel。节点标签是可选的,它们对于将节点分组到集合中非常有用,其中所有具有特定标签的节点都属于同一个集合。

movies.csv
movieId:ID,title,year:int,:LABEL
tt0133093,"The Matrix",1999,Movie
tt0234215,"The Matrix Reloaded",2003,Movie;Sequel
tt0242653,"The Matrix Revolutions",2003,Movie;Sequel

actors.csv 中的演员数据包括一个 ID 和一个 name,作为属性存储在节点中。在这种情况下,ID 是演员姓名的缩写。actors.csv 中的所有节点都具有标签 Actor

actors.csv
personId:ID,name,:LABEL
keanu,"Keanu Reeves",Actor
laurence,"Laurence Fishburne",Actor
carrieanne,"Carrie-Anne Moss",Actor

roles.csv 中的角色数据只有一个属性,即 role。角色由连接演员节点与电影节点的关系数据表示。

关系数据有三个必填字段

  1. :START_ID — 引用节点的 ID。

  2. :END_ID — 引用节点的 ID。

  3. :TYPE — 关系类型。

要在两个节点之间创建关系,actors.csvmovies.csv 中定义的 ID 将用于 :START_ID:END_ID 字段。您还需要为 :TYPE 字段提供一个关系类型(在此示例中为 ACTED_IN)。

roles.csv
:START_ID,role,:END_ID,:TYPE
keanu,"Neo",tt0133093,ACTED_IN
keanu,"Neo",tt0234215,ACTED_IN
keanu,"Neo",tt0242653,ACTED_IN
laurence,"Morpheus",tt0133093,ACTED_IN
laurence,"Morpheus",tt0234215,ACTED_IN
laurence,"Morpheus",tt0242653,ACTED_IN
carrieanne,"Trinity",tt0133093,ACTED_IN
carrieanne,"Trinity",tt0234215,ACTED_IN
carrieanne,"Trinity",tt0242653,ACTED_IN

导入数据

  • 节点数据的路径通过 --nodes 选项定义。

  • 关系数据的路径通过 --relationships 选项定义。

调用 neo4j-admin database import 将如下所示

shell
bin/neo4j-admin database import full neo4j --nodes=import/movies.csv --nodes=import/actors.csv --relationships=import/roles.csv

查询数据

要查询数据,请启动 Neo4j。

默认用户名和密码均为 neo4j

shell
bin/neo4j start

要查询图中的导入数据,请尝试一个简单的 Cypher 查询。

shell
bin/cypher-shell --database=neo4j "MATCH (n) RETURN count(n) as nodes"

停止 Neo4j。

shell
bin/neo4j stop

CSV 文件分隔符

如果您的数据不符合默认格式,您可以自定义导入工具使用的配置选项(参见选项)。

CSV 文件头格式的详细信息可在CSV 文件头格式处找到。

数据

以下 CSV 文件具有

  • --delimiter=";"

  • --array-delimiter="U+007C" (U+007C 是字符 | 的 Unicode 码点)

  • --quote="'"

movies2.csv
movieId:ID;title;year:int;:LABEL
tt0133093;'The Matrix';1999;Movie
tt0234215;'The Matrix Reloaded';2003;Movie|Sequel
tt0242653;'The Matrix Revolutions';2003;Movie|Sequel
actors2.csv
personId:ID;name;:LABEL
keanu;'Keanu Reeves';Actor
laurence;'Laurence Fishburne';Actor
carrieanne;'Carrie-Anne Moss';Actor
roles2.csv
:START_ID;role;:END_ID;:TYPE
keanu;'Neo';tt0133093;ACTED_IN
keanu;'Neo';tt0234215;ACTED_IN
keanu;'Neo';tt0242653;ACTED_IN
laurence;'Morpheus';tt0133093;ACTED_IN
laurence;'Morpheus';tt0234215;ACTED_IN
laurence;'Morpheus';tt0242653;ACTED_IN
carrieanne;'Trinity';tt0133093;ACTED_IN
carrieanne;'Trinity';tt0234215;ACTED_IN
carrieanne;'Trinity';tt0242653;ACTED_IN

导入数据

调用 neo4j-admin database import 将如下所示

shell
bin/neo4j-admin database import full neo4j --delimiter=";" --array-delimiter="U+007C" --quote="'" --nodes=import/movies2.csv --nodes=import/actors2.csv --relationships=import/roles2.csv

使用单独的头文件

当处理非常大的 CSV 文件时,将头放在单独的文件中会更方便。这样可以更容易地编辑头,因为您无需为了更改它而打开一个巨大的数据文件。头文件必须在每个文件组中的其余文件之前指定。

导入工具还可以处理单文件压缩档案,例如

  • --nodes=import/nodes.csv.gz

  • --relationships=import/relationships.zip

数据

您将使用与上一个示例相同的数据集,但头位于单独的文件中。

movies3-header.csv
movieId:ID,title,year:int,:LABEL
movies3.csv
tt0133093,"The Matrix",1999,Movie
tt0234215,"The Matrix Reloaded",2003,Movie;Sequel
tt0242653,"The Matrix Revolutions",2003,Movie;Sequel
actors3-header.csv
personId:ID,name,:LABEL
actors3.csv
keanu,"Keanu Reeves",Actor
laurence,"Laurence Fishburne",Actor
carrieanne,"Carrie-Anne Moss",Actor
roles3-header.csv
:START_ID,role,:END_ID,:TYPE
roles3.csv
keanu,"Neo",tt0133093,ACTED_IN
keanu,"Neo",tt0234215,ACTED_IN
keanu,"Neo",tt0242653,ACTED_IN
laurence,"Morpheus",tt0133093,ACTED_IN
laurence,"Morpheus",tt0234215,ACTED_IN
laurence,"Morpheus",tt0242653,ACTED_IN
carrieanne,"Trinity",tt0133093,ACTED_IN
carrieanne,"Trinity",tt0234215,ACTED_IN
carrieanne,"Trinity",tt0242653,ACTED_IN

导入数据

调用 neo4j-admin database import 将如下所示

文件组的标题行,无论是该组中文件的第一行还是专用标题文件,都必须是文件组中的第一行。

shell
bin/neo4j-admin database import full neo4j --nodes=import/movies3-header.csv,import/movies3.csv --nodes=import/actors3-header.csv,import/actors3.csv --relationships=import/roles3-header.csv,import/roles3.csv

多个输入文件

除了使用单独的头文件外,您还可以提供多个节点或关系文件。此类输入组中的文件可以使用多个匹配字符串来指定,这些字符串以 , 分隔,其中每个匹配的字符串可以是精确的文件名,也可以是匹配一个或多个文件的正则表达式。多个匹配的文件将根据其字符和包含数字的文件名的自然数字排序顺序进行排序。

数据

movies4-header.csv
movieId:ID,title,year:int,:LABEL
movies4-part1.csv
tt0133093,"The Matrix",1999,Movie
tt0234215,"The Matrix Reloaded",2003,Movie;Sequel
movies4-part2.csv
tt0242653,"The Matrix Revolutions",2003,Movie;Sequel
actors4-header.csv
personId:ID,name,:LABEL
actors4-part1.csv
keanu,"Keanu Reeves",Actor
laurence,"Laurence Fishburne",Actor
actors4-part2.csv
carrieanne,"Carrie-Anne Moss",Actor
roles4-header.csv
:START_ID,role,:END_ID,:TYPE
roles4-part1.csv
keanu,"Neo",tt0133093,ACTED_IN
keanu,"Neo",tt0234215,ACTED_IN
keanu,"Neo",tt0242653,ACTED_IN
laurence,"Morpheus",tt0133093,ACTED_IN
laurence,"Morpheus",tt0234215,ACTED_IN
roles4-part2.csv
laurence,"Morpheus",tt0242653,ACTED_IN
carrieanne,"Trinity",tt0133093,ACTED_IN
carrieanne,"Trinity",tt0234215,ACTED_IN
carrieanne,"Trinity",tt0242653,ACTED_IN

导入数据

调用 neo4j-admin database import 将如下所示

shell
bin/neo4j-admin database import full neo4j --nodes=import/movies4-header.csv,import/movies4-part1.csv,import/movies4-part2.csv --nodes=import/actors4-header.csv,import/actors4-part1.csv,import/actors4-part2.csv --relationships=import/roles4-header.csv,import/roles4-part1.csv,import/roles4-part2.csv

正则表达式

当有许多数据源文件时,可以使用正则表达式指定文件名。每个匹配正则表达式的文件名都将被包含在内。

如果使用单独的头文件,为了使导入正常工作,头文件必须是文件组中的第一个。当使用正则表达式指定输入文件时,文件列表将根据匹配表达式的文件名进行排序。匹配会识别文件名中的数字,并相应地进行排序,无需用零填充。

示例 1. 匹配顺序

例如,假设您有以下文件

  • movies4-header.csv

  • movies4-data1.csv

  • movies4-data2.csv

  • movies4-data12.csv

如果您使用正则表达式 movies4.*,排序会将头文件放在最后,导致导入失败。更好的替代方法是显式命名头文件,并使用仅匹配数据文件名的正则表达式。例如:--nodes "import/movies4-header.csv,movies-data.*" 将实现此目的。

使用正则表达式导入数据,对 neo4j-admin database import 的调用可以简化为

shell
bin/neo4j-admin database import full neo4j --nodes="import/movies4-header.csv,import/movies4-part.*" --nodes="import/actors4-header.csv,import/actors4-part.*" --relationships="import/roles4-header.csv,import/roles4-part.*"

正则表达式的使用不应与文件全局匹配混淆。

表达式 .* 意味着:“零个或多个除换行符以外的任何字符”。因此,正则表达式 movies4.* 将列出所有以 movies4 开头的文件。相反,使用文件全局匹配时,ls movies4.* 将列出所有以 movies4. 开头的文件。

另一个需要注意的重要区别是排序顺序。正则表达式匹配的结果会将文件 movies4-part2.csv 放在文件 movies4-part12.csv 之前。如果在包含上述列出文件的目录中执行 ls movies4-part*,文件 movies4-part12.csv 将在文件 movies4-part2.csv 之前列出。

为每个节点使用相同的标签

如果您想为节点文件中的每个节点使用相同的节点标签,可以通过将适当的值指定为 neo4j-admin database import 的选项来实现。这样就不需要在头文件中指定 :LABEL 列,并且每行(节点)都将应用命令行选项中指定的标签。

示例 2. 指定节点标签选项

--nodes=LabelOne:LabelTwo=import/example-header.csv,import/example-data1.csv

可以将文件中提供的标签和命令行中提供的标签都应用于节点。

数据

在此示例中,您希望 movies5a.csv 中指定的每个节点都带有标签 Movie,并且在 sequels5a.csv 中指定的节点上放置标签 MovieSequel

movies5a.csv
movieId:ID,title,year:int
tt0133093,"The Matrix",1999
sequels5a.csv
movieId:ID,title,year:int
tt0234215,"The Matrix Reloaded",2003
tt0242653,"The Matrix Revolutions",2003
actors5a.csv
personId:ID,name
keanu,"Keanu Reeves"
laurence,"Laurence Fishburne"
carrieanne,"Carrie-Anne Moss"
roles5a.csv
:START_ID,role,:END_ID,:TYPE
keanu,"Neo",tt0133093,ACTED_IN
keanu,"Neo",tt0234215,ACTED_IN
keanu,"Neo",tt0242653,ACTED_IN
laurence,"Morpheus",tt0133093,ACTED_IN
laurence,"Morpheus",tt0234215,ACTED_IN
laurence,"Morpheus",tt0242653,ACTED_IN
carrieanne,"Trinity",tt0133093,ACTED_IN
carrieanne,"Trinity",tt0234215,ACTED_IN
carrieanne,"Trinity",tt0242653,ACTED_IN

导入数据

调用 neo4j-admin database import 将如下所示

shell
bin/neo4j-admin database import full neo4j --nodes=Movie=import/movies5a.csv --nodes=Movie:Sequel=import/sequels5a.csv --nodes=Actor=import/actors5a.csv --relationships=import/roles5a.csv

为每个关系使用相同的关系类型

如果您想为关系文件中的每个关系使用相同的关系类型,可以通过将适当的值指定为 neo4j-admin database import 的选项来实现。

示例 3. 指定关系类型选项

--relationships=TYPE=import/example-header.csv,import/example-data1.csv

如果您在命令行和关系文件中都提供了关系类型,则将应用文件中的类型。

数据

在此示例中,您希望 ACTED_IN 关系类型应用于 roles5b.csv 中指定的每个关系。

movies5b.csv
movieId:ID,title,year:int,:LABEL
tt0133093,"The Matrix",1999,Movie
tt0234215,"The Matrix Reloaded",2003,Movie;Sequel
tt0242653,"The Matrix Revolutions",2003,Movie;Sequel
actors5b.csv
personId:ID,name,:LABEL
keanu,"Keanu Reeves",Actor
laurence,"Laurence Fishburne",Actor
carrieanne,"Carrie-Anne Moss",Actor
roles5b.csv
:START_ID,role,:END_ID
keanu,"Neo",tt0133093
keanu,"Neo",tt0234215
keanu,"Neo",tt0242653
laurence,"Morpheus",tt0133093
laurence,"Morpheus",tt0234215
laurence,"Morpheus",tt0242653
carrieanne,"Trinity",tt0133093
carrieanne,"Trinity",tt0234215
carrieanne,"Trinity",tt0242653

导入数据

调用 neo4j-admin database import 将如下所示

shell
bin/neo4j-admin database import full neo4j --nodes=import/movies5b.csv --nodes=import/actors5b.csv --relationships=ACTED_IN=import/roles5b.csv

属性

节点和关系可以拥有属性。属性类型在 CSV 标题行中指定,参见CSV 文件头格式

数据

以下示例创建了一个小型图,其中包含一个演员和一部电影,通过一个关系连接。

关系上有一个 roles 属性,其中包含演员在电影中扮演的角色数组

movies6.csv
movieId:ID,title,year:int,:LABEL
tt0099892,"Joe Versus the Volcano",1990,Movie
actors6.csv
personId:ID,name,:LABEL
meg,"Meg Ryan",Actor
roles6.csv
:START_ID,roles:string[],:END_ID,:TYPE
meg,"DeDe;Angelica Graynamore;Patricia Graynamore",tt0099892,ACTED_IN

导入数据

调用 neo4j-admin database import 将如下所示

shell
bin/neo4j-admin database import full neo4j --nodes=import/movies6.csv --nodes=import/actors6.csv --relationships=import/roles6.csv

ID 空间

导入工具假设标识符在所有节点文件中都是唯一的。对于使用顺序、自动递增或其他冲突标识符的数据集来说,可能并非如此。这些数据集可以定义 ID 空间,其中标识符在各自的 ID 空间内是唯一的。

在节点 ID 仅在文件内唯一的情况下,使用 ID 空间是确保所有节点文件唯一性的一种方式。请参见使用 ID 空间

neo4j-admin database import 处理的每个节点,如果要连接到任何关系中,都必须提供一个 ID。节点 ID 用于在创建关系时查找起始节点和结束节点。

节点头还可以包含多个 ID 列,其中关系数据引用所有这些列的复合值。这也意味着使用 string 作为 id-type。对于每个 ID 列,您可以指定将其值存储为不同的节点属性。但是,复合值不能作为节点属性存储。

示例 4. ID 空间

要为 movieId:ID 定义 ID 空间 Movie-ID,请使用语法 movieId:ID(Movie-ID)

数据

例如,如果电影和人物都使用顺序标识符,那么您将定义 MovieActor ID 空间。

movies7.csv
movieId:ID(Movie-ID),title,year:int,:LABEL
1,"The Matrix",1999,Movie
2,"The Matrix Reloaded",2003,Movie;Sequel
3,"The Matrix Revolutions",2003,Movie;Sequel
actors7.csv
personId:ID(Actor-ID),name,:LABEL
1,"Keanu Reeves",Actor
2,"Laurence Fishburne",Actor
3,"Carrie-Anne Moss",Actor

您还需要在关系文件中引用相应的 ID 空间,以便它知道要连接哪些节点。

roles7.csv
:START_ID(Actor-ID),role,:END_ID(Movie-ID)
1,"Neo",1
1,"Neo",2
1,"Neo",3
2,"Morpheus",1
2,"Morpheus",2
2,"Morpheus",3
3,"Trinity",1
3,"Trinity",2
3,"Trinity",3

导入数据

调用 neo4j-admin database import 将如下所示

shell
bin/neo4j-admin database import full neo4j --nodes=import/movies7.csv --nodes=import/actors7.csv --relationships=ACTED_IN=import/roles7.csv

跳过引用缺失节点的关系

导入工具对不良实体(关系或节点)没有容忍度,会在第一个不良实体处导致导入失败。您可以明确指定希望它忽略包含不良实体的行。

有两种不同类型的不良输入

  1. 不良关系。

  2. 不良节点。

引用缺失节点 ID(无论是 :START_ID 还是 :END_ID)的关系被视为不良关系。是否跳过此类关系由 --skip-bad-relationships 标志控制,该标志可以取值 truefalse 或不带值(表示 true)。默认值为 false,这意味着任何不良关系都被视为错误并会导致导入失败。有关更多信息,请参见 --skip-bad-relationships 选项。

数据

在以下示例中,角色文件中引用了一个缺失的 emil 节点。

movies8a.csv
movieId:ID,title,year:int,:LABEL
tt0133093,"The Matrix",1999,Movie
tt0234215,"The Matrix Reloaded",2003,Movie;Sequel
tt0242653,"The Matrix Revolutions",2003,Movie;Sequel
actors8a.csv
personId:ID,name,:LABEL
keanu,"Keanu Reeves",Actor
laurence,"Laurence Fishburne",Actor
carrieanne,"Carrie-Anne Moss",Actor
roles8a.csv
:START_ID,role,:END_ID,:TYPE
keanu,"Neo",tt0133093,ACTED_IN
keanu,"Neo",tt0234215,ACTED_IN
keanu,"Neo",tt0242653,ACTED_IN
laurence,"Morpheus",tt0133093,ACTED_IN
laurence,"Morpheus",tt0234215,ACTED_IN
laurence,"Morpheus",tt0242653,ACTED_IN
carrieanne,"Trinity",tt0133093,ACTED_IN
carrieanne,"Trinity",tt0234215,ACTED_IN
carrieanne,"Trinity",tt0242653,ACTED_IN
emil,"Emil",tt0133093,ACTED_IN

导入数据

调用 neo4j-admin database import 将如下所示

shell
bin/neo4j-admin database import full neo4j --nodes=import/movies8a.csv --nodes=import/actors8a.csv --relationships=import/roles8a.csv

由于输入数据中存在不良关系,导入过程将失败。

让我们看看如果您附加 --skip-bad-relationships 标志会发生什么

shell
bin/neo4j-admin database import full neo4j --skip-bad-relationships --nodes=import/movies8a.csv --nodes=import/actors8a.csv --relationships=import/roles8a.csv

数据文件成功导入,不良关系被忽略。一条记录写入 import.report 文件。

忽略不良关系
InputRelationship:
   source: roles8a.csv:11
   properties: [role, Emil]
   startNode: emil (global id space)
   endNode: tt0133093 (global id space)
   type: ACTED_IN
 referring to missing node emil

跳过具有相同 ID 的节点

指定了 :ID 且该 ID 已在 ID 空间内指定过的节点被视为不良节点。是否跳过此类节点由 --skip-duplicate-nodes 标志控制,该标志可以取值 truefalse 或不带值(表示 true)。默认值为 false,这意味着任何重复节点都被视为错误并会导致导入失败。有关更多信息,请参见 --skip-duplicate-nodes 选项。

数据

在以下示例中,节点 ID laurence 在同一 ID 空间内被指定了两次。

actors8b.csv
personId:ID,name,:LABEL
keanu,"Keanu Reeves",Actor
laurence,"Laurence Fishburne",Actor
carrieanne,"Carrie-Anne Moss",Actor
laurence,"Laurence Harvey",Actor

导入数据

调用 neo4j-admin database import 将如下所示

shell
bin/neo4j-admin database import full neo4j --database=neo4j --nodes=import/actors8b.csv

由于输入数据中存在不良节点,导入过程将失败。

让我们看看如果您附加 --skip-duplicate-nodes 标志会发生什么

shell
bin/neo4j-admin database import full neo4j --skip-duplicate-nodes --nodes=import/actors8b.csv

数据文件成功导入,不良节点被忽略。一条记录写入 import.report 文件。

忽略不良节点
ID 'laurence' is defined more than once in global ID space, at least at actors8b.csv:3 and actors8b.csv:5