Neo4j批量导入提供了三个工具:load csv、neo4j-admin import、apoc。本文只介绍前两个方法,也是使用最多的方法,关于apoc的内容在后面介绍。load csv和neo4j-admin import的主要区别就是 load csv是在线导入方式,即Neo4j不需要停止运行,支持增量导入数据,本质是cypher语言;neo4j-admin import 导入数据必须是生成一个新库,而且必须重启Neo4j,不支持增量导入,一次性把所有数据都导入进去,本质是Neo4j自带的shell工具。另外需要注意的是 neo4j-admin import 的导入速度相比load csv非常快,个人认为可以快100倍往上。
一、load csv
1、配置
load csv的使用比较简单,只要把数据处理好,存储为文本格式(csv、txt、...)即可。在使用之前有一点需要注意,在配置文件中的配置项:dbms.directories.import=import 是设置导入文件的原始目录,一旦该选项被设置,所有从本地导入数据的起始路径都是该目录(Neo4j所在目录下的import目录),即使使用绝对目录也是无效的。
2、导入方式
假设有如下数据存在,文件名是artists-with-headers.csv,注意第一行是列名:
Id,Name,Year
1,ABBA,1992
2,Roxette,1986
3,Europe,1979
4,The Cardigans,1992
导入语句如下:
LOAD CSV WITH HEADERS FROM 'file:///artists-with-headers.csv' AS line FIELDTERMINATOR ','
CREATE (:Artist { name: line.Name, year: toInteger(line.Year)})
语法解释如下:
(1)LOAD CSV 是导入命令,必须包含。
(2)WITH HEADERS 表示数据文件中含有列名,如果文件中没有列名,则不要加该 关键词。
(3)FROM 表示文件地址,可以是本地文件,也可以是网络文件。如果是本地文件,则使用 file:///+本地文件路径,注意是以设置目录为当前目录。如果是网络文件,则后面直接使用url地址,如:https://neo4j.com/artists-fieldterminator.csv 。
(4)AS 表示读一行。
(5)FIELDTERMINATOR 表示列分隔符,默认是逗号,所以上面的语句也可以不加该选项,支持不可见字符,如:\u0003 。
(6)CREATE 语句就是正常的创建节点语句了。这里需要注意的是,如果文件中有列名,即指定了WITH HEADERS 关键词,则这里必须引用文件中的列名,有两种方法:line.Name 或者 line['Name'],不能使用 line[0] 这种用法。如果文件中没有列名,则只能使用 line[0] 引用。
3、设置PERIODIC COMMIT
在导入大文件的时候,可能因为内存限制,导入失败,此时我们需要设置提交数量,PERIODIC COMMIT 可以设置提交的行数。默认是1000行提交一次,用法如下,设置500行提交一次:
USING PERIODIC COMMIT 500
LOAD CSV WITH HEADERS FROM 'file:///artists-with-headers.csv' AS line FIELDTERMINATOR ','
CREATE (:Artist { name: line.Name, year: toInteger(line.Year)})
二、neo4j-admin import
neo4j-admin import 是Neo4j自身提供的一个shell工具,位于 bin 目录下。Neo4j也提供了另外一个导入shell工具:neo4j-import,但是后期该shell会被删除,不建议使用这个。
1、文件格式
使用 neo4j-admin import 导入数据,数据格式和 load csv略有不同,主要体现在列名上。neo4j-admin import 导入数据文件的列名既可以和数据写在一起,也可以单独写一个文件,在不熟悉或者对于大文件,都建议写在一个单独的文件中。因为使用 neo4j-admin import 导入文件一般都比较大,所以建议都把列名单独写一个文件,尤其对于大文件,这样修改列名非常方便。
节点文件
节点文件的格式和load csv一样,但是必须有一列作为 ID 列,既可以是属性,也可以不是。例如有如下数据,第一列是name,默认name都是唯一的;第二列是age;第三列是address;第四列是标签,表示所有节点的abel都是Person,这里也可以不写,在导入的时候指定。
s1,18,shanghai,Person
s2,19,beijing,Person
s3,20,hangzhou,Person
s4,21,chengdu,Person
上述数据的头文件如下:
name:ID,age:int,address,:LABEL
name后的 :ID 表示该列是ID列,也是属性name列,后面在建立关系的时候都是以该列值匹配的。如果该列只作为ID匹配,不作为属性值,则前面的name不写即可,务必注意所有节点的ID值都不能相同,即使是不同类型的节点,如果不同类型节点有相同ID值,参考后面处理方法。age后的 :int 表示该属性值类型是int。
边文件
边文件需要包含起点ID和终点ID,以及需要添加的属性和标签,同样标签也可以不添加,在导入的时候指定。有如下数据,前两列是起点ID和终点ID,第三列是属性值weight,第四列是标签:
s1,s2,1,F1
s2,s3,2,F1
s1,s3,3,F1
上述文件的头文件如下:
:START_ID,:END_ID,weight:int,:TYPE
:START_ID,:END_ID分别指定了起点ID和终点ID,这里的值必须是在前面节点ID中存在。:TYPE表示边的标签。
2、使用ID spaces
前面说过,一张图中,任意两个节点的ID都不是相同。但是,有时候可能我们的数据在两类不同的节点中可能会有相同的ID值,这时候可以使用 ID spaces解决。数据无需变动,只需修改头文件可。
节点头文件修改如下:
name:ID(Person-ID),age:int,address,:LABEL
边头文件修改如下:
:START_ID(Person-ID),:END_ID(Person-ID),weight:int,:TYPE
即通过ID spaces来标识不同类型的节点。
3、导入数据
准备好所有的节点文件和边文件以后就可以开始导入数据了,导入命令如下:
bin/neo4j-admin import \
--database testdb.db \
--delimiter "," \
--id-type INTEGER \
--nodes "import/person_header.csv,import/person.csv" \
--relationships "import/f1_header.csv,import/f1.csv"
关于上述字段的含义,参考下列解释:
neo4j-admin import 导入命令
--database 新建的库文件名称,如果不指定的话,默认是graph.db,必须确保 data/databases目录下没有同名数据库
--id-type ID类型,可以指定STRING、INTEGER、ACTUAL,默认是STRING,上述demo name就是STRING
--delimiter 分隔符,注意这里的分隔符不仅仅指数据文件的分隔符,也包括头文件的分隔符,默认不指定是逗号,上面demo可以不写
--nodes 节点文件,包括头文件和数据文件。如果有多个节点文件,写多个 --nodes 项
--relationships 边文件,包括头文件和数据文件,可以指定标签。如果有多个节点文件,写多个 --relationships 项
通常来说我们只会用到上述配置项,下面配置项很少用到:
--ignore-duplicate-nodes 如果有重复ID是否忽略,默认false
--ignore-missing-nodes 如果关系中有不存在的节点ID,是否忽略,默认false
--additional-config 指定配置文件
--mode 指定导入文件的类型,可选database和csv,表示从db文件导入还是csv文件
--from 如果mode使用了database ,则该选项指定db位置
--report-file 保存导入log信息,默认是import.report
--input-encoding 输入文件的编码,默认UTF-8
前面说过,可以不在数据文件中指定标签名,在导入的时候指定,个人也比较习惯使用这种方法。假设上述数据文件没有标签列,则导入命令可以这样写:
bin/neo4j-admin import \
--database testdb.db \
--delimiter "," \
--id-type INTEGER \
--nodes:Person "import/person_header.csv,import/person.csv" \
--relationships:F1 "import/f1_header.csv,import/f1.csv"
4、不可见字符输入
在导入数据的时候,经常遇到一个问题就是因为数据比较复杂找不到一个合适的字段分隔符,这里就会用到前文一中提到的不可见字符,不过需要注意的时,shell中输入不可见字符和数据库中是不同的,比如上文提到的不可见字符 \u0003,在shell中输入方式是:Ctrl+V+C。
5、导入多个文件
在某些情况下,我们会遇到需要导入多个文件的情况,比如Hadoop的生成文件或者Hive的导出文件,可能会有几百个文件。如果一个文件写一条nodes,则导入命令就会很长,不过neo4j-admin的import命令提供了正则功能,即模糊匹配。假如在data目录下的文件都是Person节点,则可以按照如下命令快速导入:
bin/neo4j-admin import \
--database testdb.db \
--delimiter "," \
--nodes:Person import/person_header.csv,import/data/.*
可以发现这种方式命令就比较简单。另外,--nodes和--relationships后的内容引号可以不写。