导入数据

本教程提供了详细示例,旨在说明使用命令 neo4j-admin database import 从 CSV 文件导入数据的功能。该导入命令用于从 CSV 文件加载大量数据,并支持向运行中或已停止的 Neo4j DBMS 进行全量和增量导入。

neo4j-admin database import 命令不会创建数据库,它仅负责导入数据并使其可供数据库使用。在执行 neo4j-admin database import 命令之前,数据库必须不存在,且应在导入后创建数据库。如果数据库已存在,该命令将退出并显示错误消息。

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

以下示例展示了如何在独立的 Neo4j DBMS 中导入数据。它们使用:

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

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

  • 默认数据库 neo4j

  • Neo4j 安装目录下的 import 文件夹来存储所有 CSV 文件。不过,CSV 文件也可以位于文件系统的任何目录下。

  • UNIX 风格的路径。

  • neo4j-admin database import full 命令。

实用提示
  • 关于 CSV 文件头格式的详细信息,请参阅 CSV 头格式

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

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

  • 要创建数据库,请使用 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 中的演员数据由 IDname 组成,存储为节点中的属性。此处的 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.*"

正则表达式的使用不应与 文件通配符 (globbing) 混淆。

表达式 .* 的意思是:“零个或多个除换行符以外的任何字符”。因此,正则表达式 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 的节点被视为损坏节点。此类节点是否被跳过由 --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