2.1 导入 CSV 文件
Cypher中 LOAD CSV
的命令允许我们指定文件路径、标头与否、不同的值分隔符以及 Cypher 语句,用于我们如何在图形中对表格数据进行建模。
CSV 是逗号分隔值的文件,通常在 Excel 或其他电子表格工具中查看。可以有其他类型的值作为分隔符,但最标准的是逗号。如今,许多系统和流程已经将其数据转换为 CSV 格式,以便将文件输出到其他系统、人性化报告和其他需求。它是一种标准文件格式。
2.1.1 导入 CSV 文件的方法
有几种不同的方法可以将 CSV 数据导入 Neo4j,每种方法都有不同的标准和功能。您选择的选项取决于数据集大小,以及您对各种工具的熟悉程度。
让我们看看 Neo4j 读取和导入 CSV 文件的一些方法。
LOAD CSV
命令:此Cypher命令是一个很好的起点,可以处理中小型数据集(最多 1000 万条记录)。适用于任何设置,包括 AuraDB。neo4j-admin database import
命令:命令行工具可用于直接加载大型数据集。适用于 Neo4j Desktop、Neo4j EE Docker 镜像和本地安装。- Neo4j ETL 工具:Neo4j Labs 项目。有关更多详细信息和文档,请访问 Neo4j ETL 工具页面。
- Kettle 导入工具:映射和执行数据处理流的步骤,适用于非常大的数据集,尤其是在您已经熟悉使用此工具的情况下。适用于任何设置,包括 AuraDB。
在下面的部分中,您可以找到 LOAD CSV
Cypher 命令和 neo4j-admin database import
命令的简要视图、它们如何操作以及如何开始使用一般用例。对于将任何类型的数据导入到任何系统,数据质量也可能是一个问题,因此本节将介绍其中的一些潜在困难和克服这些困难的方法。
2.1.2 使用LOAD CSV命令导入
该 LOAD CSV
子句是 Cypher 查询语言的一部分。有关该 LOAD CSV
子句的更多信息,请参阅 LOAD CSV → Cypher 手册。它适用范围广泛。 LOAD CSV
不仅仅是一种基本的数据引入机制。它在一次操作中执行多个操作:
- 支持从 URI 加载/引入 CSV 数据。
- 将输入数据直接映射到复杂的图形/域结构中。
- 处理数据转换。
- 支持复杂的计算。
- 创建或合并实体、关系和结构。
为了更好地控制,您可以使用 Cypher Shell 而不是在 Neo4j 浏览器中运行 LOAD CSV
命令。关于Cypher Shell的更多信息,请参见《Cypher Shell→操作手册》。
2.1.2.1 读取 CSV 文件
LOAD CSV
可以处理本地和远程文件,并且每个文件都有一些语法。这可能很容易错过并最终导致访问错误,因此此处澄清了规则。
本地文件需要在文件名前加上前缀 file:///
来加载。
由于 AuraDB 是基于云的,因此这种本地文件方法不适用于 AuraDB。
出于安全原因,默认情况下,本地文件只能从 Neo4j 导入目录中读取,根据您的操作系统而有所不同。每个操作系统的文件位置都列在我们的 Neo4j 操作手册→文件位置中。建议将文件放在 Neo4j 的导入目录中,因为它可以保证环境的安全。但是,如果您需要访问其他位置的文件,您可以在我们的 Cypher 手册→ LOAD CSV 简介中找到要更改的设置。
Neo4j 发行版 | Default file location |
---|---|
Linux / macOS / Docker | <NEO4J_HOME>/import |
Windows | <NEO4J_HOME>/import |
Debian / RPM | /var/lib/neo4j/import |
Neo4j Desktop | From the Open dropdown menu of your active Neo4j DBMS, select Terminal, and run cd import . |
//Example 1 - file directly placed in import directory (import/data.csv)
LOAD CSV FROM "file:///data.csv"//Example 2 - file placed in subdirectory within import directory (import/northwind/customers.csv)
LOAD CSV FROM "file:///northwind/customers.csv"
Web 托管的文件可以直接使用其 URL 进行引用,例如 https://host/path/data.csv
。但是,必须设置权限,以便外部源可以读取文件。要从本地文件系统中读取文件,您需要检查配置 dbms.security.allow_csv_import_from_file_urls
是否设置为 true
。有关与联机文件导入相关的访问的详细信息,请参阅此知识库文章。但请记住,在 Neo4j v5 中,配置设置已被重命名,dbms.directories.import
被更改为 server.directories.import
.
//Example 1 - website
LOAD CSV FROM 'https://data.neo4j.com/northwind/customers.csv' //Example 2 - Google
LOAD CSV WITH HEADERS FROM 'https://docs.google.com/spreadsheets/d/<yourFilePath>/export?format=csv'
2.1.2.2 有关 LOAD CSV 的重要提示
需要注意:
- CSV 文件中的所有数据都以字符串形式读取,因此需要使用
toInteger()
、toFloat()
、split()
或类似的函数来转换值。 - 检查您的 Cypher import 语句是否有拼写错误。标签、属性名称、关系类型和变量区分大小写。
- 数据越干净,加载越容易。尝试在加载之前处理复杂的清理/操作。
2.1.2.3 使用 LOAD CSV 转换数据值
Cypher 具有一些清理和转换功能,可帮助清理数据。这些对于处理缺失数据或将字段拆分为图形的多个值非常有用。
首先,请记住 Neo4j 不存储 null 值。可以跳过 CSV 文件中的 null 或空字段,或将其替换为 LOAD CSV中的默认值。
假设你有这个companies.csv文件:
Id,Name,Location,Email,BusinessType
1,Neo4j,San Mateo,contact@neo4j.com,P
2,AAA,,info@aaa.com,
3,BBB,Chicago,,G
线上数据文件地址:https://docs.google.com/spreadsheets/d/e/2PACX-1vSBOKZ0dfP1QJD7YzaRH7o5SvFxFlmMsnvaXkNF4_t0gGnemenEHjBg7y3akOmUZIGmMryNlrlrwnfK/pub?output=csv
以下是导入此数据的一些示例。
// 跳过空值数据
LOAD CSV WITH HEADERS FROM 'file:///companies.csv' AS row
WITH row WHERE row.Id IS NOT NULL
MERGE (c:Company {companyId: row.Id});// clear data
MATCH (n:Company) DELETE n;// 为空值设置默认值
LOAD CSV WITH HEADERS FROM 'file:///companies.csv' AS row
MERGE (c:Company {companyId: row.Id, hqLocation: coalesce(row.Location, "Unknown")})// clear data
MATCH (n:Company) DELETE n;// 将空字符串转为null值(不存储)
LOAD CSV WITH HEADERS FROM 'file:///companies.csv' AS row
MERGE (c:Company {companyId: row.Id})
SET c.emailAddress = CASE trim(row.Email) WHEN "" THEN null ELSE row.Email END
接下来,如果 CSV 中有一个字段是要拆分的项目列表,则可以使用 Cypher split() 函数分隔单元格中的数组。
假设你有这个employees.csv文件:
Id,Name,Skills,Email
1,Joe Smith,Cypher:Java:JavaScript,joe@neo4j.com
2,Mary Jones,Java,mary@neo4j.com
3,Trevor Scott,Java:JavaScript,trevor@neo4j.com
线上文件地址:https://docs.google.com/spreadsheets/d/e/2PACX-1vT3T-aocniTs91ZI12pc5VUAJo0JK9kqzf3So7XV9EAOVdcYMmbKyS1bSRYdPqNu_AdI-AzO2Rfxu5v/pub?output=csv
导入数据
LOAD CSV WITH HEADERS FROM 'file:///employees.csv' AS row
MERGE (e:Employee {employeeId: row.Id, email: row.Email})
WITH e, row
UNWIND split(row.Skills, ':') AS skill
MERGE (s:Skill {name: skill})
MERGE (e)-[r:HAS_EXPERIENCE]->(s)// 查询
match (e:Employee)-[r:HAS_EXPERIENCE]->(s:Skill) return e,r,s
当我们检查空值或空字符串时,条件转换可以通过 CASE
来实现。
// clear data
MATCH (n:Company) DELETE n;//set businessType property based on shortened value in CSV
LOAD CSV WITH HEADERS FROM 'file:///companies.csv' AS row
WITH row WHERE row.Id IS NOT NULL
WITH row,
(CASE row.BusinessTypeWHEN 'P' THEN 'Public'WHEN 'R' THEN 'Private'WHEN 'G' THEN 'Government'ELSE 'Other' END) AS type
MERGE (c:Company {companyId: row.Id, hqLocation: coalesce(row.Location, "Unknown")})
SET c.emailAddress = CASE trim(row.Email) WHEN "" THEN null ELSE row.Email END
SET c.businessType = type
RETURN *
2.1.2.4 优化 LOAD CSV 以提高性能
通常,有一些方法可以提高数据加载期间的性能,这在处理大量数据或复杂加载时特别有用。
为了改进在图形中插入或更新唯一实体(使用 MERGE 或 MATCH 更新),您可以为计划合并或匹配的每个标签和属性创建声明的索引和约束。
为了获得最佳性能,请
MATCH
和MERGE
在具有索引主键属性的单个标签上。
假设您使用前面的 companies.csv 文件,现在您有一个包含人员及其工作公司的people.csv文件:
employeeId,Name,Company
1,Bob Smith,1
2,Joe Jones,3
3,Susan Scott,2
4,Karen White,1
线上文件地址:https://docs.google.com/spreadsheets/d/e/2PACX-1vSz77w7NFnLy8eelAxAhr10L4O9p-5jtQ17uFcbNvYesGO-12wuBo0EbvgMCxC8aWcFHPp8_JDZgryp/pub?output=csv
还应将节点和关系的创建分开处理。例如,可以用以下方式代替
MERGE (e:Employee {employeeId: row.employeeId})
MERGE (c:Company {companyId: row.companyId})
MERGE (e)-[r:WORKS_FOR]->(c)
可以这样写:
// clear data
MATCH (n)
DETACH DELETE n;// 加载Employee节点
LOAD CSV WITH HEADERS FROM 'file:///people.csv' AS row
MERGE (e:Employee {employeeId: row.employeeId, name: row.Name})
RETURN count(e);// 加载Company节点
LOAD CSV WITH HEADERS FROM 'file:///companies.csv' AS row
WITH row WHERE row.Id IS NOT NULL
WITH row,
(CASE row.BusinessTypeWHEN 'P' THEN 'Public'WHEN 'R' THEN 'Private'WHEN 'G' THEN 'Government'ELSE 'Other' END) AS type
MERGE (c:Company {companyId: row.Id, hqLocation: coalesce(row.Location, "Unknown")})
SET c.emailAddress = CASE trim(row.Email) WHEN "" THEN null ELSE row.Email END
SET c.businessType = type
RETURN count(c);// 创建关系
LOAD CSV WITH HEADERS FROM 'file:///people.csv' AS row
MATCH (e:Employee {employeeId: row.employeeId})
MATCH (c:Company {companyId: row.Company})
MERGE (e)-[:WORKS_FOR]->(c)
RETURN *;
这样,load一次只执行一段导入,并且可以快速有效地处理大量数据,从而减少繁重的处理。
当加载的数据量过大而无法放入内存时,可以使用几种不同的方法来应对数据加载期间内存不足的问题。
-
使用
CALL { ... } IN TRANSACTIONS
将导入批量分段进行。。可以在
LOAD CSV
子句之后添加此子查询,以告诉 Cypher 在清除内存和事务状态之前只处理这么多行的文件。有关详细信息,请参阅 Cypher Manual → Subqueries。LOAD CSV FROM 'file:///people.csv' AS line CALL {WITH lineMATCH (e:Employee {id: line[0]})CREATE (e)-[:REL {prop: line[1]}]->(e) } IN TRANSACTIONS OF 100000 ROWS;
-
避开 Eager 操作
某些语句拉取的行数超出了必要的行数,从而预先添加了额外的处理。为了避免这种情况,您可以对查询运行 PROFILE ,以查看它们是否使用
Eager
加载,然后修改查询或在同一文件上运行多次,这样就不会出现这种情况了。有关Eager
操作符的更多信息 ,请详细参见 Cypher manual → Execution plan operators in detail -
调整堆和内存上的数据库配置,以避免页面错误。
为了帮助处理大量事务,您可以增加数据库的某些配置设置并重新启动实例以使其生效。通常,每 2 GB 堆可以在单个事务中创建或更新 100 万条记录。在
neo4j.conf
:server.memory.heap.initial_size
和server.memory.heap.max_size
: 设置为至少 4G。server.memory.pagecache.size
:理想情况下,值足够大,可以将整个数据库保留在内存中。
2.1.3 neo4j-admin database import 命令
命令详情:https://neo4j.com/docs/operations-manual/current/tools/neo4j-admin/neo4j-admin-import/
LOAD CSV
非常适合导入中小型数据集(最多 1000 万条记录)。对于大于此值的数据集,可以使用以下 neo4j-admin database import
命令。这允许您通过指定节点文件和关系文件将 CSV 数据导入未使用的数据库。
该 neo4j-admin database import
命令只能用于初始图形填充。
假设您想将订单数据通过 neo4j-admin database import
导入 到 Neo4j 实例中。请注意,以下某些 CSV 文件包含标头,而某些文件具有单独的头文件。如果要执行导入,请将它们放在 Neo4j 实例的导入文件夹中。
customers.csv
customerId:ID(Customer), name
23, Delicatessen Inc
42, Delicious Bakery
products.csv( 有一个产品节点,具有 ID 为 11,名称为 Chocolate,价格为 10 的产品,并且它属于 Product 和 Food 这两个标签 )
productId:ID(Product), name, price, :LABEL
11,Chocolate,10,Product;Food
orders_header.csv
orderId:ID(Order),date,total,customerId:IGNORE
customer_orders_header.csv(:START_ID(Customer) 表示关系起点为 Customer,:END_ID(Order) 表示关系终点为 Order,date:IGNORE 和 total:IGNORE 则表示在创建关系时忽略日期和总价这两个属性 )
:END_ID(Order),date:IGNORE,total:IGNORE,:START_ID(Customer)
orders1.csv
1041,2020-05-10,130,23
orders2.csv
1042,2020-05-12,20,42
order_details.csv
:START_ID(Order),amount,price,:END_ID(Product)
1041,13,130,11
1042,2,20,11
neo4j-admin database import
命令有两种模式:
- full — 用于最初将数据导入不存在的空数据库。
- incremental — 用于以增量方式将数据导入现有数据库。
该工具位于 <neo4j-instance-location>/bin/neo4j-admin
中 ,您可以在终端窗口中运行该命令,在该窗口中导航到 Neo4j 实例的import目录。
以下是在 Neo4j 5.x 中导入上述 CSV 文件的示例。必须指定数据库的名称。在本例中,我们指定订单。
bin/neo4j-admin database import full--nodes=Customer=import/customers.csv--nodes=import/products.csv --nodes=Order=import/orders_header.csv, import/orders1.csv, import/orders2.csv--relationships=CONTAINS=import/order_details.csv--relationships=ORDERED=import/customer_orders_header.csv, import/orders1.csv, import/orders2.csv--trim-strings=true orders
您必须在一行中指定此脚本的参数。此处显示换行符是为了便于阅读。
运行该命令时,它将导入数据并将其提供给数据库。neo4j-admin 数据库导入命令不会创建新数据库。
重复的--nodes
和--relationships
参数是同一实体的多个(可能拆分)CSV 文件的组,即具有相同的列结构。
每个组的所有文件都被视为可以串联为一个大文件。组的第一个文件或单独的单行文件中的标题行是必需的。将标头放在单独的文件中比将其放在数 GB 的文本文件中更容易处理和编辑。还支持压缩文件。
--id-type=string
: 所有:ID
列都包含字母数字值(针对纯数字 ID 进行了优化)。- customers.csv 直接作为带有 :Customer 标签的节点导入,属性直接从文件中提取。
Product
节点遵循相同的模式,节点标签取自文件中的:LABEL
列。Order
节点取自三个文件,一个标头文件和两个内容文件。- 从
order_details.csv
中创建类型为:CONTAINS
的行项目关系,通过 ID 将订单与所含产品联系起来。 - 再次使用订单 CSV 文件将订单与客户连接起来,但这次使用了不同的标题,即
:IGNORE
是不相关的列。
列名用于节点和关系的属性名称。特定列上有特定标记:
name:ID
:全局 ID 列,用于在以后重新连接时查找节点。- 如果省略属性名称,则不会存储它(临时),这就是所指的 --id-type 。
- 如果跨实体有重复的 ID,则必须在括号中提供实体 (id-group),例如 :ID(Order) 。
- 如果您的 ID 是全局唯一的,则可以将其关闭。
:LABEL
:节点的标签列。多个标签可以通过分隔符分隔。:START_ID
,:END_ID
:引用节点 ID 的关系文件列。对于 id-groups,请使用:END_ID(Order)
。:START_ID(Customer)
表示关系起点为 Customer,:END_ID(Order)
表示关系终点为 Order:TYPE
:列指定关系类型。- 所有其他列都被视为属性,但如果为空或用
:IGNORE
批注,则跳过。date:IGNORE 和 total:IGNORE 则表示在创建关系时忽略日期和总价这两个属性。 - 可以通过在名称后加上
:INT
、:BOOLEAN
等指示符来进行类型转换。
2.1.4 CSV 数据质量
常见陷阱
-
标题与数据不一致(缺少或过多列、标题中的分隔符不同)。
验证标头是否与文件中的数据匹配。在此阶段调整格式、分隔符、列等将在以后节省大量时间。
-
整个文件中多余或缺少引号。
非引号文本中间的独立双引号或单引号或引号文本中的非转义引号可能会导致读取文件以进行加载时出现问题。最好转义或删除杂散引号。正确转义的文档在 Cypher 样式指南中。
-
文件中的特殊字符或换行符。
在处理文件中的特殊字符时,应确保为其加上引号或将其删除。对于有引号或无引号字段中的换行符,要么为其加上引号,要么将其删除。
-
不一致的换行符。
计算机不能很好地处理的一件事是数据不一致。确保换行符始终保持一致。我们建议选择 Unix 样式以兼容 Linux 系统(导入工具的通用格式)。
-
二进制零、文件开头的 BOM 字节顺序标记(2 个 UTF-8 字节)或其他非文本字符。
任何不寻常的字符或特定于工具的格式有时隐藏在应用程序工具中,但在基本编辑器中很容易显现。如果您在文件中遇到这些类型的字符,最好将它们完全删除。
如上所述,某些应用程序有特殊的格式设置,使文档看起来更美观,但这些隐藏的额外代码是普通文件阅读器和脚本无法处理的。还有一些时候,对于数据量很大的文件,很难发现微小的语法变化或进行大范围的调整。
为了处理这些类型的情况或常规数据清理,有许多工具可以帮助您检查和验证 CSV 数据文件。
基本工具(如 hexdump、vi、emacs、UltraEdit 和 Notepad++)适用于处理用于编辑和操作文件的基于快捷方式的命令。但是,还有其他更有效或用户友好的选项可用于帮助数据清理和格式化。
-
Cypher:Cypher 看到的就是将要导入的内容,因此您可以利用它来发挥自己的优势。在不创建图形结构的情况下使用
LOAD CSV
仅输出样本、计数或分布,以便可以检测不正确的标题列计数、分隔符、引号、转义或标题名称拼写。// assert correct line count LOAD CSV FROM "file-url" AS line RETURN count(*);// check first 5 line-sample with header-mapping LOAD CSV WITH HEADERS FROM "file-url" AS line RETURN line LIMIT 5;
-
CSVKit:一组 Python 工具,可为您的 CSV 文件提供统计信息 (csvstat)、搜索 (csvgrep) 等。
-
CSVLint:用于验证 CSV 文件的在线服务。您可以上传文件或提供 URL 来加载它。
-
Papa Parse:一个用于 CSV 解析的综合 Javascript 库,允许您流式传输 CSV 数据并提供良好的、人类可读的问题错误报告。
2.2 通过REST API导入JSON数据
https://neo4j.com/docs/getting-started/data-import/json-rest-api-import/
我们可以将大量基于 JSON 的 Web API 导入到 Neo4j 中,并且可以使用其中一个LOAD JSON程序从这些 API 中检索数据并将其转换为可供 Cypher使用的映射值。
APOC 用户指南提供了一个工作示例,展示了如何将数据从 StackOverflow 导入 Neo4j。