4.3 数据导入与导出 Neo4j 数据导入与导出详解:代码实践与应用 4.3 数据导入 数据导入是将外部数据源加载到 Neo4j 图数据库中的过程。Neo4j 提供了多种数据导入方式,以适应不同的数据规模、格式和应用场景。在 Neo4j 版本中,主要的数据导入方法包括 工具、Cypher 语句 、以及通过 Neo4j 驱动程序编程导入。 4.3.1 工具:批量导入的利器 是 Neo4j 官方提供的命令行工具,专为大规模批量数据导入设计。它直接操作数据库存储文件,绕过 Cypher 查询引擎,因此导入速度非常快,效率极高。适用于初始数据库构建、数据仓库迁移等需要快速导入大量数据的场景。 代码实践: 工具需要以命令行方式执行,并指定一系列参数来描述数据文件、数据库结构和导入配置。
数据导入是将外部数据源加载到 Neo4j 图数据库中的过程。Neo4j 提供了多种数据导入方式,以适应不同的数据规模、格式和应用场景。在 Neo4j 版本中,主要的数据导入方法包括 neo4j-admin import 工具、Cypher 语句 LOAD CSV、以及通过 Neo4j 驱动程序编程导入。
neo4j-admin import 工具:批量导入的利器neo4j-admin import 是 Neo4j 官方提供的命令行工具,专为大规模批量数据导入设计。它直接操作数据库存储文件,绕过 Cypher 查询引擎,因此导入速度非常快,效率极高。适用于初始数据库构建、数据仓库迁移等需要快速导入大量数据的场景。
代码实践:
neo4j-admin import 工具需要以命令行方式执行,并指定一系列参数来描述数据文件、数据库结构和导入配置。以下是一个典型的 neo4j-admin import 命令示例,用于从 CSV 文件导入节点和关系:
neo4j-admin import \ --database=mydb \ --nodes="nodes.csv" \ --relationships="relationships.csv" \ --nodes:Person="person_nodes.csv,header=true,id=personId" \ --relationships:KNOWS="knows_relationships.csv,header=true,from=sourcePersonId,to=targetPersonId"
参数详解:
--database=mydb: 指定要导入数据的数据库名称,默认为 neo4j 数据库。
--nodes="nodes.csv": 指定节点数据的主文件,用于定义所有节点的通用属性。
--relationships="relationships.csv": 指定关系数据的主文件,用于定义所有关系的通用属性。
--nodes:<Label>="<nodes_file>,header=true,id=<node_id_property>": 定义特定标签 <Label> 的节点数据文件,可以指定多个标签。
<nodes_file>: CSV 节点数据文件的路径。
header=true: 表示 CSV 文件第一行是列头。
id=<node_id_property>: 指定 CSV 文件中作为节点唯一标识的列名。
--relationships:<RelationshipType>="<relationships_file>,header=true,from=<source_node_id_property>,to=<target_node_id_property>": 定义特定关系类型 <RelationshipType> 的关系数据文件,可以指定多个关系类型。
<relationships_file>: CSV 关系数据文件的路径。
header=true: 表示 CSV 文件第一行是列头。
from=<source_node_id_property>: 指定 CSV 文件中作为关系起始节点标识的列名。
to=<target_node_id_property>: 指定 CSV 文件中作为关系目标节点标识的列名。
数据文件格式:
neo4j-admin import 主要支持 CSV 格式的数据文件。CSV 文件需要按照特定的格式组织数据,以便工具正确解析。
节点文件 (nodes.csv, person_nodes.csv):
personId,name,age,city 1,Alice,30,New York 2,Bob,25,London 3,Charlie,35,Paris
第一行通常是列头,定义属性名称。
后续行是节点数据,每列对应一个属性值。
--id 参数指定的列必须是节点唯一的标识符。
关系文件 (relationships.csv, knows_relationships.csv):
sourcePersonId,targetPersonId,since 1,2,2020 1,3,2021 2,3,2022
第一行通常是列头,定义属性名称。
后续行是关系数据,每列对应一个属性值。
--from 和 --to 参数指定的列分别表示起始节点和目标节点的标识符,这些标识符需要与节点文件中定义的标识符相匹配。
Graph TD 图示导入流程:
内容详解:
neo4j-admin import 工具的工作原理可以概括为以下步骤:
解析命令行参数: 工具首先解析用户提供的命令行参数,包括数据库名称、数据文件路径、节点和关系定义等。
读取数据文件: 根据指定的路径读取 CSV 数据文件,并根据 header=true 参数判断是否跳过首行。
创建节点和关系: 根据节点和关系的定义,将 CSV 数据转换为 Neo4j 内部的节点和关系数据结构。
对于节点,根据 --nodes:<Label> 定义创建具有特定标签的节点,并设置属性。
对于关系,根据 --relationships:<RelationshipType> 定义创建特定关系类型的关系,并连接起始节点和目标节点。
写入数据库存储: 将创建的节点和关系直接写入 Neo4j 数据库的存储文件。由于是直接写入存储,避免了 Cypher 查询引擎的开销,因此导入速度非常快。
注意事项:
neo4j-admin import 工具需要在 Neo4j 服务停止的情况下执行,因为它直接操作数据库存储文件。
导入过程中会清空目标数据库,因此请务必备份重要数据。
该工具适用于全新数据库的初始化导入,不适合对现有数据库进行增量更新。
数据文件需要严格按照规定的 CSV 格式组织,否则可能导致导入失败或数据错误。
LOAD CSV:灵活的在线导入Cypher 语句 LOAD CSV 允许在 Neo4j 服务运行的情况下,通过 Cypher 查询语言从 CSV 文件导入数据。与 neo4j-admin import 相比,LOAD CSV 更加灵活,可以在导入过程中进行数据转换、过滤和关联,适用于增量数据导入、数据清洗和复杂数据转换的场景。
代码实践:
// 从本地 CSV 文件导入节点 LOAD CSV WITH HEADERS FROM 'file:///person_nodes.csv' AS row CREATE (p:Person {personId: toInteger(row.personId), name: row.name, age: toInteger(row.age), city: row.city}); // 从本地 CSV 文件导入关系,并匹配已存在的节点 LOAD CSV WITH HEADERS FROM 'file:///knows_relationships.csv' AS row MATCH (p1:Person {personId: toInteger(row.sourcePersonId)}) MATCH (p2:Person {personId: toInteger(row.targetPersonId)}) CREATE (p1)-[:KNOWS {since: toInteger(row.since)}]->(p2);
参数详解:
LOAD CSV WITH HEADERS FROM 'file:///person_nodes.csv' AS row: 指定要加载的 CSV 文件路径和别名。
LOAD CSV: 关键字,表示加载 CSV 数据。
WITH HEADERS: 可选参数,表示 CSV 文件包含列头,Cypher 会自动将列头作为属性名。
FROM 'file:///person_nodes.csv': 指定 CSV 文件路径,file:/// 表示本地文件系统,需要将文件放置在 Neo4j 服务器的 import 目录下(可在 neo4j.conf 中配置 dbms.directories.import)。也可以使用 http:// 或 https:// 路径加载远程 CSV 文件。
AS row: 为每一行 CSV 数据指定别名 row,可以通过 row.<列名> 访问每一列的值。
CREATE (p:Person {personId: toInteger(row.personId), ... }): 使用 CREATE 语句创建节点或关系,并使用 row.<列名> 访问 CSV 行数据,设置节点或关系的属性。
toInteger(), toFloat(), toString() 等函数用于将 CSV 字符串类型的数据转换为 Neo4j 需要的数据类型。MATCH (p1:Person {personId: toInteger(row.sourcePersonId)}): 使用 MATCH 语句匹配已存在的节点,用于创建节点之间的关系。
Graph TD 图示导入流程:
内容详解:
LOAD CSV 的工作原理可以概括为以下步骤:
Cypher 查询解析: Neo4j 的 Cypher 查询引擎解析 LOAD CSV 语句。
读取 CSV 文件: 根据 FROM 子句指定的路径读取 CSV 文件,并根据 WITH HEADERS 参数处理列头。
逐行处理数据: 按行读取 CSV 数据,每一行数据通过 AS row 指定的别名传递给后续的 Cypher 语句。
执行 Cypher 语句: 对于每一行 CSV 数据,执行 LOAD CSV 语句块中的 Cypher 代码。
通常使用 CREATE 语句创建新的节点或关系。
可以使用 MATCH 语句匹配已存在的节点,并创建节点之间的关系。
可以使用 MERGE 语句进行节点或关系的合并操作,实现数据去重或更新。
写入数据库: Cypher 语句执行的结果(创建的节点或关系)被写入 Neo4j 数据库。
优势与特点:
在线导入: LOAD CSV 可以在 Neo4j 服务运行时执行,无需停止服务。
灵活性: 可以使用完整的 Cypher 语法进行数据处理,包括数据转换、过滤、关联、条件判断等。
增量导入: 可以用于向现有数据库导入增量数据,例如定期更新数据。
事务支持: LOAD CSV 操作在事务中执行,保证数据一致性。
局限性:
性能相对较低: 与 neo4j-admin import 相比,LOAD CSV 的导入速度较慢,因为需要经过 Cypher 查询引擎的处理。
不适合大规模初始导入: 对于大规模的初始数据导入,建议使用 neo4j-admin import 工具。
Neo4j 提供了多种语言的驱动程序(例如 Java, Python, JavaScript, .NET 等),允许开发者通过编程方式连接 Neo4j 数据库,并执行 Cypher 查询进行数据导入。这种方式更加灵活,可以集成到应用程序中,实现自动化数据导入流程。
代码实践 (Python 示例):
from neo4j import GraphDatabase uri = "bolt://localhost:7687" username = "neo4j" password = "password" driver = GraphDatabase.driver(uri, auth=(username, password)) def create_person_node(tx, person_id, name, age, city): query = """ CREATE (p:Person {personId: $person_id, name: $name, age: $age, city: $city}) """ tx.run(query, person_id=person_id, name=name, age=age, city=city) def create_knows_relationship(tx, source_person_id, target_person_id, since): query = """ MATCH (p1:Person {personId: $source_person_id}) MATCH (p2:Person {personId: $target_person_id}) CREATE (p1)-[:KNOWS {since: $since}]->(p2) """ tx.run(query, source_person_id=source_person_id, target_person_id=target_person_id, since=since) with driver.session() as session: # 导入节点数据 person_data = [ {"personId": 1, "name": "Alice", "age": 30, "city": "New York"}, {"personId": 2, "name": "Bob", "age": 25, "city": "London"}, {"personId": 3, "name": "Charlie", "age": 35, "city": "Paris"} ] for person in person_data: session.execute_write(create_person_node, person["personId"], person["name"], person["age"], person["city"]) # 导入关系数据 relationship_data = [ {"source_person_id": 1, "target_person_id": 2, "since": 2020}, {"source_person_id": 1, "target_person_id": 3, "since": 2021}, {"source_person_id": 2, "target_person_id": 3, "since": 2022} ] for relationship in relationship_data: session.execute_write(create_knows_relationship, relationship["source_person_id"], relationship["target_person_id"], relationship["since"]) driver.close()
代码详解:
连接数据库: 使用 GraphDatabase.driver() 方法创建数据库驱动程序实例,并指定 Neo4j 服务器的 URI 和认证信息。
创建会话: 使用 driver.session() 创建数据库会话,会话用于执行事务。
定义事务函数: 定义用于创建节点和关系的事务函数 (create_person_node, create_knows_relationship),在函数中使用 Cypher 查询语句,并通过参数化查询避免 SQL 注入风险。
执行事务: 使用 session.execute_write() 方法执行写事务,确保数据操作的原子性和一致性。
关闭驱动程序: 使用 driver.close() 关闭驱动程序,释放资源。
Graph TD 图示导入流程:
优势与特点:
高度灵活性: 可以根据应用程序的需求,自定义数据导入逻辑,进行复杂的数据处理和业务逻辑集成。
自动化: 可以将数据导入流程集成到应用程序中,实现自动化数据导入。
实时性: 可以实现实时数据导入,例如从消息队列或流式数据源导入数据。
局限性:
开发复杂度较高: 需要编写代码来实现数据导入逻辑,相对于 neo4j-admin import 和 LOAD CSV,开发复杂度较高。
性能相对较低: 批量导入性能通常不如 neo4j-admin import,但可以通过优化 Cypher 查询和事务处理来提升性能。
APOC (Awesome Procedures on Cypher) 库是 Neo4j 的一个强大的扩展库,提供了大量的实用程序和函数,其中包括丰富的数据导入功能。APOC 提供了多种导入过程,例如从 JSON、XML、JDBC 数据源导入数据,以及更高级的 CSV 导入功能。
代码实践 (APOC CSV 导入示例):
// 使用 APOC 从 CSV 文件导入节点和关系 CALL apoc.load.csv('person_nodes.csv', {header:true}) YIELD lineNo, row CREATE (p:Person {personId: toInteger(row.personId), name: row.name, age: toInteger(row.age), city: row.city}); CALL apoc.load.csv('knows_relationships.csv', {header:true}) YIELD lineNo, row MATCH (p1:Person {personId: toInteger(row.sourcePersonId)}) MATCH (p2:Person {personId: toInteger(row.targetPersonId)}) CREATE (p1)-[:KNOWS {since: toInteger(row.since)}]->(p2);
代码详解:
CALL apoc.load.csv('person_nodes.csv', {header:true}) YIELD lineNo, row: 调用 APOC 的 apoc.load.csv 过程,加载 CSV 文件。
'person_nodes.csv': CSV 文件路径。
{header:true}: 配置项,表示 CSV 文件包含列头。
YIELD lineNo, row: 将 apoc.load.csv 过程的输出结果(行号 lineNo 和行数据 row)返回,以便后续 Cypher 语句使用。
后续的 CREATE 和 MATCH 语句与 LOAD CSV 的用法类似。
APOC 导入的优势:
更多数据源支持: APOC 提供了从 JSON, XML, JDBC 等多种数据源导入数据的过程。
更强大的 CSV 导入功能: APOC 的 CSV 导入过程提供了更多配置选项,例如自定义分隔符、引号符、错误处理等。
数据转换和处理能力: APOC 提供了丰富的函数和程序,可以在导入过程中进行更复杂的数据转换和处理。
数据导出是将 Neo4j 图数据库中的数据导出到外部文件或系统的过程。Neo4j 提供了多种数据导出方式,以满足不同的数据备份、迁移和集成需求。在 Neo4j 版本中,主要的数据导出方法包括 neo4j-admin dump 工具、Cypher 语句 EXPORT CSV (通过 APOC 或 Neo4j 的导出功能),以及通过 Neo4j 驱动程序编程导出。
neo4j-admin dump 工具:全库备份与迁移neo4j-admin dump 是 Neo4j 官方提供的命令行工具,用于全库备份和数据库迁移。它将整个 Neo4j 数据库(包括所有节点、关系、索引、约束等)导出到一个压缩文件中,可以用于数据库备份、恢复和迁移到不同的 Neo4j 环境。
代码实践:
neo4j-admin dump --database=mydb --to=mydb.dump
参数详解:
--database=mydb: 指定要导出的数据库名称,默认为 neo4j 数据库。
--to=mydb.dump: 指定导出文件的路径和名称,导出的文件将是一个压缩的 .dump 文件。
Graph TD 图示导出流程:
内容详解:
neo4j-admin dump 工具的工作原理可以概括为以下步骤:
解析命令行参数: 工具首先解析用户提供的命令行参数,包括数据库名称和导出文件路径。
读取数据库存储: 工具直接读取 Neo4j 数据库的存储文件,获取数据库的所有数据和元数据。
序列化数据: 将数据库数据序列化为一种中间格式,例如 JSON 或二进制格式。
压缩数据: 对序列化后的数据进行压缩,减小导出文件的大小。
导出到 .dump 文件: 将压缩后的数据写入指定的 .dump 文件。
注意事项:
neo4j-admin dump 工具需要在 Neo4j 服务停止的情况下执行,因为它直接操作数据库存储文件。
导出的 .dump 文件可以用于 neo4j-admin load 工具进行数据库恢复或迁移。
EXPORT CSV (APOC 或 Neo4j 导出功能):查询结果导出Cypher 语句 EXPORT CSV (在 Neo4j 中可能需要借助 APOC 库或某些版本可能已提供内置导出功能) 允许将 Cypher 查询的结果导出为 CSV 文件。这种方式可以灵活地导出指定的数据子集,适用于数据分析、报表生成和与其他系统的数据集成场景。
代码实践 (APOC CSV 导出示例):
// 使用 APOC 将所有 Person 节点导出为 CSV 文件 CALL apoc.export.csv.query( "MATCH (p:Person) RETURN p.personId AS personId, p.name AS name, p.age AS age, p.city AS city", "person_nodes_exported.csv", {} ); // 使用 APOC 将 Person 节点和 KNOWS 关系导出为 CSV 文件 CALL apoc.export.csv.query( "MATCH (p1:Person)-[r:KNOWS]->(p2:Person) RETURN p1.personId AS sourcePersonId, p2.personId AS targetPersonId, r.since AS since", "knows_relationships_exported.csv", {} );
代码详解:
CALL apoc.export.csv.query( ... ): 调用 APOC 的 apoc.export.csv.query 过程,执行 Cypher 查询并将结果导出为 CSV 文件。
第一个参数是 Cypher 查询语句,用于指定要导出的数据。
第二个参数是导出 CSV 文件的路径和名称。
第三个参数是配置项,例如可以设置分隔符、引号符等。
RETURN p.personId AS personId, ...: 在 Cypher 查询语句中使用 RETURN 子句指定要导出的列,并使用 AS 关键字为列指定别名,作为 CSV 文件的列头。
Graph TD 图示导出流程:
内容详解:
EXPORT CSV 的工作原理可以概括为以下步骤:
Cypher 查询解析: Neo4j 的 Cypher 查询引擎解析 EXPORT CSV 语句。
执行 Cypher 查询: 执行 EXPORT CSV 语句中指定的 Cypher 查询,获取要导出的数据结果集。
格式化为 CSV: 将查询结果集格式化为 CSV 格式,将每一行结果转换为 CSV 行,并根据列名生成 CSV 列头。
写入 CSV 文件: 将 CSV 数据写入指定的 CSV 文件。
优势与特点:
灵活的数据导出: 可以使用 Cypher 查询灵活地选择要导出的数据子集,并进行数据转换和格式化。
在线导出: EXPORT CSV 可以在 Neo4j 服务运行时执行,无需停止服务。
多种导出格式 (APOC): APOC 还提供了导出为 JSON, GraphML, graphSON 等多种格式的功能。
局限性:
性能受查询复杂度影响: 导出性能取决于 Cypher 查询的复杂度和数据量。
不适合全库备份: EXPORT CSV 主要用于导出数据子集,不适合全库备份,全库备份应使用 neo4j-admin dump 工具。
与数据导入类似,Neo4j 驱动程序也支持通过编程方式执行 Cypher 查询,并将查询结果导出到外部文件或系统。这种方式更加灵活,可以集成到应用程序中,实现自动化数据导出流程。
代码实践 (Python 示例):
from neo4j import GraphDatabase import csv uri = "bolt://localhost:7687" username = "neo4j" password = "password" driver = GraphDatabase.driver(uri, auth=(username, password)) def export_person_nodes_to_csv(tx, csv_file_path): query = """ MATCH (p:Person) RETURN p.personId AS personId, p.name AS name, p.age AS age, p.city AS city """ result = tx.run(query) with open(csv_file_path, 'w', newline='') as csvfile: csv_writer = csv.writer(csvfile) csv_writer.writerow(result.keys()) # 写入列头 for record in result: csv_writer.writerow(record.values()) with driver.session() as session: session.execute_read(export_person_nodes_to_csv, "person_nodes_exported_programmatically.csv") driver.close()
代码详解:
连接数据库、创建会话、定义事务函数、关闭驱动程序: 与编程导入类似。
执行 Cypher 查询: 在事务函数 export_person_nodes_to_csv 中,使用 tx.run(query) 执行 Cypher 查询,获取查询结果 result。
写入 CSV 文件: 使用 Python 的 csv 模块将查询结果写入 CSV 文件。
result.keys() 获取查询结果的列名,作为 CSV 列头。
record.values() 获取每一行查询结果的值,作为 CSV 行数据。
Graph TD 图示导出流程:
优势与特点:
高度灵活性: 可以根据应用程序的需求,自定义数据导出逻辑,进行复杂的数据处理和业务逻辑集成。
自动化: 可以将数据导出流程集成到应用程序中,实现自动化数据导出。
实时性: 可以实现实时数据导出,例如将数据导出到实时数据分析系统。
局限性:
开发复杂度较高: 需要编写代码来实现数据导出逻辑,相对于 neo4j-admin dump 和 EXPORT CSV,开发复杂度较高。
性能相对较低: 批量导出性能可能不如 neo4j-admin dump 和 EXPORT CSV,但可以通过优化 Cypher 查询和数据处理来提升性能。
选择合适的工具: 根据数据规模、导入/导出场景和性能要求,选择合适的导入/导出工具。
大规模初始导入: neo4j-admin import
增量数据导入、数据清洗、复杂数据转换: LOAD CSV 或 APOC 导入
全库备份与迁移: neo4j-admin dump
数据分析、报表生成、数据集成、数据子集导出: EXPORT CSV (APOC 或 Neo4j 功能) 或 驱动程序编程导出
自动化、实时数据导入/导出、复杂业务逻辑集成: 驱动程序编程导入/导出
数据预处理: 在数据导入前,进行数据清洗、转换和验证,确保数据质量和一致性。