导出到 Cypher 脚本
导出到 Cypher 过程将数据导出为 Cypher 语句,这些语句可用于将数据导入到另一个 Neo4j 实例。
导出节点时,如果节点标签不包含唯一约束,则导出器会向这些节点添加 如果节点标签确实有唯一约束,则将使用定义唯一约束的属性来确保唯一性。 |
可用过程
下表描述了可用过程
限定名称 | 类型 |
---|---|
apoc.export.cypher.all |
|
apoc.export.cypher.data |
|
apoc.export.cypher.graph |
|
apoc.export.cypher.query |
|
apoc.export.cypher.schema |
|
导出的标签按字母顺序排列。labels() 函数的输出未排序,请与 apoc.coll.sort() 结合使用。 |
配置参数
这些过程支持以下配置参数
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
format |
字符串 |
cypher-shell |
导出格式。支持以下值
|
cypherFormat |
字符串 |
create |
Cypher 更新操作类型。支持以下值
|
useOptimizations |
映射 |
|
用于 Cypher 语句生成的优化。
|
awaitForIndexes |
整数 |
300 |
当使用 |
saveIndexNames |
布尔值 |
false |
导出时保存名称索引 |
saveConstraintNames |
布尔值 |
false |
导出时保存名称约束 |
multipleRelationshipsWithType |
布尔值 |
false |
如果两个 |
导出到文件
默认情况下,导出到文件系统是禁用的。我们可以通过在 apoc.conf
中设置以下属性来启用它
apoc.export.file.enabled=true
有关访问 apoc.conf
的更多信息,请参阅配置选项章节。
如果我们尝试在未首先设置此属性的情况下使用任何导出过程,将收到以下错误消息
Failed to invoke procedure: Caused by: java.lang.RuntimeException: Export to files not enabled, please set apoc.export.file.enabled=true in your apoc.conf. Otherwise, if you are running in a cloud environment without filesystem access, use the |
导出文件会写入 import
目录,该目录由 server.directories.import
属性定义。这意味着我们提供的任何文件路径都是相对于此目录的。如果我们尝试写入绝对路径,例如 /tmp/filename
,将收到类似于以下内容的错误消息
Failed to invoke procedure: Caused by: java.io.FileNotFoundException: /path/to/neo4j/import/tmp/fileName (No such file or directory) |
我们可以通过在 apoc.conf
中设置以下属性来启用向文件系统上任何位置的写入
apoc.import.file.use_neo4j_config=false
Neo4j 现在将能够写入文件系统上的任何位置,因此在设置此属性之前,请确保这是您的意图。 |
导出流
如果不想导出到文件,可以通过提供 null
文件名来流式传输结果。
默认情况下,所有 Cypher 语句将以单行形式返回到 cypherStatements
列中。
CALL apoc.export.cypher.all(null);
如果要导出大型数据库,可以通过提供 streamStatements:true
配置并配置 batchSize
来将这些语句分批处理到多行中。
CALL apoc.export.cypher.all(null, {
streamStatements: true,
batchSize: 100
});
示例
本节包含使用导出到 Cypher 过程的示例。这些示例基于电影数据集,可以通过运行以下 Cypher 查询来导入
CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'})
CREATE (Keanu:Person {name:'Keanu Reeves', born:1964})
CREATE (Carrie:Person {name:'Carrie-Anne Moss', born:1967})
CREATE (Laurence:Person {name:'Laurence Fishburne', born:1961})
CREATE (Hugo:Person {name:'Hugo Weaving', born:1960})
CREATE (LillyW:Person {name:'Lilly Wachowski', born:1967})
CREATE (LanaW:Person {name:'Lana Wachowski', born:1965})
CREATE (JoelS:Person {name:'Joel Silver', born:1952})
CREATE
(Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix),
(Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix),
(Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix),
(Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix),
(LillyW)-[:DIRECTED]->(TheMatrix),
(LanaW)-[:DIRECTED]->(TheMatrix),
(JoelS)-[:PRODUCED]->(TheMatrix);
下面的 Neo4j Browser 可视化显示了导入的图
导出为 Cypher Shell 格式
默认情况下,导出到 Cypher 过程生成的 Cypher 语句采用 Cypher Shell 格式。
UNWIND_BATCH
优化,将整个数据库导出为默认 cypher-shell
格式的 all.cypher
文件// default config populated for illustration
CALL apoc.export.cypher.all("all.cypher", {
format: "cypher-shell",
useOptimizations: {type: "UNWIND_BATCH", unwindBatchSize: 20}
})
YIELD file, batches, source, format, nodes, relationships, properties, time, rows, batchSize
RETURN file, batches, source, format, nodes, relationships, properties, time, rows, batchSize;
file | batches | source | format | nodes | relationships | properties | time | rows | batchSize |
---|---|---|---|---|---|---|---|---|---|
"all.cypher" |
1 |
"database: nodes(8), rels(7)" |
"cypher" |
8 |
7 |
21 |
10 |
15 |
20000 |
以下显示了 all.cypher
的内容,并增加了额外的行以提高可读性
:begin
CREATE CONSTRAINT uniqueConstraint FOR (node:`UNIQUE IMPORT LABEL`) REQUIRE (node.`UNIQUE IMPORT ID`) IS UNIQUE;
:commit
:begin
UNWIND [{_id:0, properties:{tagline:"Welcome to the Real World", title:"The Matrix", released:1999}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Movie;
UNWIND [{_id:1, properties:{born:1964, name:"Keanu Reeves"}}, {_id:2, properties:{born:1967, name:"Carrie-Anne Moss"}}, {_id:3, properties:{born:1961, name:"Laurence Fishburne"}}, {_id:4, properties:{born:1960, name:"Hugo Weaving"}}, {_id:5, properties:{born:1967, name:"Lilly Wachowski"}}, {_id:6, properties:{born:1965, name:"Lana Wachowski"}}, {_id:7, properties:{born:1952, name:"Joel Silver"}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Person;
:commit
:begin
UNWIND [{start: {_id:1}, end: {_id:0}, properties:{roles:["Neo"]}}, {start: {_id:2}, end: {_id:0}, properties:{roles:["Trinity"]}}, {start: {_id:3}, end: {_id:0}, properties:{roles:["Morpheus"]}}, {start: {_id:4}, end: {_id:0}, properties:{roles:["Agent Smith"]}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:ACTED_IN]->(end) SET r += row.properties;
UNWIND [{start: {_id:7}, end: {_id:0}, properties:{}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:PRODUCED]->(end) SET r += row.properties;
UNWIND [{start: {_id:5}, end: {_id:0}, properties:{}}, {start: {_id:6}, end: {_id:0}, properties:{}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:DIRECTED]->(end) SET r += row.properties;
:commit
:begin
MATCH (n:`UNIQUE IMPORT LABEL`) WITH n LIMIT 20000 REMOVE n:`UNIQUE IMPORT LABEL` REMOVE n.`UNIQUE IMPORT ID`;
:commit
:begin
DROP CONSTRAINT uniqueConstraint;
:commit
此 Cypher 脚本执行 5 个事务,每个事务都由 :begin
和 :commit
命令包围。这些事务执行以下操作
-
在
UNIQUE IMPORT LABEL
标签和UNIQUE IMPORT ID
属性上创建唯一约束 -
导入
Person
和Movie
节点 -
在这些节点之间创建
ACTED_IN
、PRODUCED
和DIRECTED
关系 -
从节点中移除
UNIQUE IMPORT LABEL
标签和UNIQUE IMPORT ID
属性 -
删除
UNIQUE IMPORT LABEL
标签和UNIQUE IMPORT ID
属性上的唯一约束
此脚本可以使用 Cypher Shell 命令行工具执行。
例如,我们可以通过运行以下命令,将 all.cypher
的内容导入到 Neo4j Aura 数据库中
cat all.cypher | ./bin/cypher-shell -a <bolt-url> -u neo4j -p <password> --format verbose
请不要忘记将 <bolt-url> 和 <password> 替换为相应的凭据。 |
如果对空数据库运行此命令,将看到以下输出
0 rows available after 70 ms, consumed after another 0 ms
Added 1 constraints
0 rows available after 16 ms, consumed after another 0 ms
Added 2 nodes, Set 8 properties, Added 4 labels
0 rows available after 40 ms, consumed after another 0 ms
Added 14 nodes, Set 42 properties, Added 28 labels
0 rows available after 51 ms, consumed after another 0 ms
Created 8 relationships, Set 8 properties
0 rows available after 38 ms, consumed after another 0 ms
Created 2 relationships
0 rows available after 38 ms, consumed after another 0 ms
Created 4 relationships
0 rows available after 20 ms, consumed after another 0 ms
Set 16 properties, Removed 16 labels
0 rows available after 3 ms, consumed after another 0 ms
Removed 1 constraints
故障排除
如果您正在尝试导入失败,可以添加 另请检查您的 Neo4j 实例的内存配置,您可能需要通过在 我们还可以通过在命令前加上: |
如果我们没有文件系统访问权限,或者出于其他原因不想写入文件,我们可以流式传输回导出的语句。
cypherStatements
列CALL apoc.export.cypher.all(null, {
batchSize: 5,
streamStatements: true,
format: "cypher-shell",
useOptimizations: {type: "UNWIND_BATCH", unwindBatchSize: 5}
})
YIELD nodes, relationships, properties, cypherStatements
RETURN nodes, relationships, properties, cypherStatements;
nodes | relationships | properties | cypherStatements |
---|---|---|---|
|
|
|
":begin CREATE CONSTRAINT uniqueConstraint FOR (node:`UNIQUE IMPORT LABEL`) REQUIRE (node. |
|
|
|
":begin UNWIND [{start: {_id:35}, end: {_id:0}, properties:{roles:[\"Trinity\"]}}, {start: {_id:36}, end: {_id:0}, properties:{roles:[\"Morpheus\"]}}, {start: {_id:50}, end: {_id:1}, properties:{roles:[\"Agent Smith\"]}}, {start: {_id:40}, end: {_id:0}, properties:{roles:[\"Agent Smith\"]}}, {start: {_id:51}, end: {_id:1}, properties:{roles:[\"Neo\"]}}] AS row MATCH (start:`UNIQUE IMPORT LABEL`{ |
|
|
|
":begin MATCH (n:`UNIQUE IMPORT LABEL`) WITH n LIMIT 5 REMOVE n:`UNIQUE IMPORT LABEL` REMOVE n. |
然后,我们可以将 cypherStatements
列的内容(不包括双引号)复制/粘贴到 Cypher Shell 会话中,或者复制/粘贴到我们流式传输到 Cypher Shell 会话的本地文件中。
导出为 Neo4j Browser 友好格式
导出到 Cypher 过程支持 format: "plain"
配置,这对于以后使用 Neo4j Browser 导入非常有用。
all-plain.cypher
文件中CALL apoc.export.cypher.all("all-plain.cypher", {
format: "plain",
useOptimizations: {type: "UNWIND_BATCH", unwindBatchSize: 20}
})
YIELD file, batches, source, format, nodes, relationships, properties, time, rows, batchSize
RETURN file, batches, source, format, nodes, relationships, properties, time, rows, batchSize;
file | batches | source | format | nodes | relationships | properties | time | rows | batchSize |
---|---|---|---|---|---|---|---|---|---|
"all-plain.cypher" |
1 |
"database: nodes(8), rels(7)" |
"cypher" |
8 |
7 |
21 |
9 |
15 |
20000 |
以下显示了 all-plain.cypher
的内容,并增加了额外的行以提高可读性
CREATE CONSTRAINT uniqueConstraint FOR (node:`UNIQUE IMPORT LABEL`) REQUIRE (node.`UNIQUE IMPORT ID`) IS UNIQUE;
UNWIND [{_id:0, properties:{tagline:"Welcome to the Real World", title:"The Matrix", released:1999}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Movie;
UNWIND [{_id:1, properties:{born:1964, name:"Keanu Reeves"}}, {_id:2, properties:{born:1967, name:"Carrie-Anne Moss"}}, {_id:3, properties:{born:1961, name:"Laurence Fishburne"}}, {_id:4, properties:{born:1960, name:"Hugo Weaving"}}, {_id:5, properties:{born:1967, name:"Lilly Wachowski"}}, {_id:6, properties:{born:1965, name:"Lana Wachowski"}}, {_id:7, properties:{born:1952, name:"Joel Silver"}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Person;
UNWIND [{start: {_id:1}, end: {_id:0}, properties:{roles:["Neo"]}}, {start: {_id:2}, end: {_id:0}, properties:{roles:["Trinity"]}}, {start: {_id:3}, end: {_id:0}, properties:{roles:["Morpheus"]}}, {start: {_id:4}, end: {_id:0}, properties:{roles:["Agent Smith"]}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:ACTED_IN]->(end) SET r += row.properties;
UNWIND [{start: {_id:7}, end: {_id:0}, properties:{}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:PRODUCED]->(end) SET r += row.properties;
UNWIND [{start: {_id:5}, end: {_id:0}, properties:{}}, {start: {_id:6}, end: {_id:0}, properties:{}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:DIRECTED]->(end) SET r += row.properties;
MATCH (n:`UNIQUE IMPORT LABEL`) WITH n LIMIT 20000 REMOVE n:`UNIQUE IMPORT LABEL` REMOVE n.`UNIQUE IMPORT ID`;
DROP CONSTRAINT uniqueConstraint;
然后,我们可以将 all-plain.cypher
文件拖放到 Neo4j Browser 窗口中。此时应看到以下提示

如果单击 Paste in editor
,文件内容将出现在查询编辑器中

all-plain.cypher
内容的 Neo4j Browser 查询编辑器然后,我们可以按编辑器中的播放按钮,数据将被导入。
使用不同的 Cypher 更新格式导出
导出到 Cypher 过程使用 CREATE
、MATCH
和 MERGE
子句生成 Cypher 语句。格式由 cypherFormat
参数配置。支持以下值
-
create
- 仅使用CREATE
子句(默认) -
updateAll
- 使用MERGE
而非CREATE
-
addStructure
- 对节点使用MATCH
,对关系使用MERGE
-
updateStructure
- 对节点和关系使用MERGE
和MATCH
如果首次导出数据库,应使用默认的 create
格式,但对于后续导出,其他格式可能更合适。
create
格式,将 ACTED_IN
关系及相关节点导出到 export-cypher-format-create.cypher
文件中MATCH (person)-[r:ACTED_IN]->(movie)
WITH collect(DISTINCT person) + collect(DISTINCT movie) AS importNodes, collect(r) AS importRels
CALL apoc.export.cypher.data(importNodes, importRels,
"export-cypher-format-create.cypher",
{ format: "plain", cypherFormat: "create" })
YIELD file, batches, source, format, nodes, relationships, properties, time, rows, batchSize
RETURN file, batches, source, format, nodes, relationships, properties, time, rows, batchSize;
file | batches | source | format | nodes | relationships | properties | time | rows | batchSize |
---|---|---|---|---|---|---|---|---|---|
"export-cypher-format-create.cypher" |
1 |
"data: nodes(5), rels(4)" |
"cypher" |
5 |
4 |
15 |
2 |
9 |
20000 |
CREATE CONSTRAINT uniqueConstraint FOR (node:`UNIQUE IMPORT LABEL`) REQUIRE (node.`UNIQUE IMPORT ID`) IS UNIQUE;
UNWIND [{_id:0, properties:{tagline:"Welcome to the Real World", title:"The Matrix", released:1999}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Movie;
UNWIND [{_id:7, properties:{born:1967, name:"Carrie-Anne Moss"}},
{_id:80, properties:{born:1960, name:"Hugo Weaving"}},
{_id:27, properties:{born:1964, name:"Keanu Reeves"}},
{_id:44, properties:{born:1961, name:"Laurence Fishburne"}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Person;
UNWIND [{start: {_id:27}, end: {_id:0}, properties:{roles:["Neo"]}},
{start: {_id:7}, end: {_id:0}, properties:{roles:["Trinity"]}},
{start: {_id:44}, end: {_id:0}, properties:{roles:["Morpheus"]}},
{start: {_id:80}, end: {_id:0}, properties:{roles:["Agent Smith"]}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:ACTED_IN]->(end) SET r += row.properties;
MATCH (n:`UNIQUE IMPORT LABEL`) WITH n LIMIT 20000 REMOVE n:`UNIQUE IMPORT LABEL` REMOVE n.`UNIQUE IMPORT ID`;
DROP CONSTRAINT uniqueConstraint;
所有图实体的创建都使用 Cypher CREATE
子句。如果这些实体可能已存在于目标数据库中,我们可以选择使用另一种格式。使用 cypherFormat: "updateAll"
意味着在创建实体时将使用 MERGE
子句而非 CREATE
。
updateAll
格式,将 ACTED_IN
关系及相关节点导出到 export-cypher-format-create.cypher
文件中MATCH (person)-[r:ACTED_IN]->(movie)
WITH collect(DISTINCT person) + collect(DISTINCT movie) AS importNodes, collect(r) AS importRels
CALL apoc.export.cypher.data(importNodes, importRels,
"export-cypher-format-updateAll.cypher",
{ format: "plain", cypherFormat: "updateAll" })
YIELD file, batches, source, format, nodes, relationships, properties, time, rows, batchSize
RETURN file, batches, source, format, nodes, relationships, properties, time, rows, batchSize;
file | batches | source | format | nodes | relationships | properties | time | rows | batchSize |
---|---|---|---|---|---|---|---|---|---|
"export-cypher-format-updateAll.cypher" |
1 |
"data: nodes(5), rels(4)" |
"cypher" |
5 |
4 |
15 |
8 |
9 |
20000 |
CREATE CONSTRAINT uniqueConstraint FOR (node:`UNIQUE IMPORT LABEL`) REQUIRE (node.`UNIQUE IMPORT ID`) IS UNIQUE;
UNWIND [{_id:0, properties:{tagline:"Welcome to the Real World", title:"The Matrix", released:1999}}] AS row
MERGE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Movie;
UNWIND [{_id:80, properties:{born:1960, name:"Hugo Weaving"}},
{_id:7, properties:{born:1967, name:"Carrie-Anne Moss"}},
{_id:44, properties:{born:1961, name:"Laurence Fishburne"}},
{_id:27, properties:{born:1964, name:"Keanu Reeves"}}] AS row
MERGE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Person;
UNWIND [{start: {_id:27}, end: {_id:0}, properties:{roles:["Neo"]}},
{start: {_id:7}, end: {_id:0}, properties:{roles:["Trinity"]}},
{start: {_id:44}, end: {_id:0}, properties:{roles:["Morpheus"]}},
{start: {_id:80}, end: {_id:0}, properties:{roles:["Agent Smith"]}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
MERGE (start)-[r:ACTED_IN]->(end) SET r += row.properties;
MATCH (n:`UNIQUE IMPORT LABEL`) WITH n LIMIT 20000 REMOVE n:`UNIQUE IMPORT LABEL` REMOVE n.`UNIQUE IMPORT ID`;
DROP CONSTRAINT uniqueConstraint;
如果目标数据库中已存在节点,我们可以使用 cypherFormat: "addStructure"
为仅关系创建 Cypher CREATE
语句。
addStructure
格式,将 ACTED_IN
关系及相关节点导出到 export-cypher-format-addStructure.cypher
文件中MATCH (person)-[r:ACTED_IN]->(movie)
WITH collect(DISTINCT person) + collect(DISTINCT movie) AS importNodes, collect(r) AS importRels
CALL apoc.export.cypher.data(importNodes, importRels,
"export-cypher-format-addStructure.cypher",
{ format: "plain", cypherFormat: "addStructure" })
YIELD file, batches, source, format, nodes, relationships, properties, time, rows, batchSize
RETURN file, batches, source, format, nodes, relationships, properties, time, rows, batchSize;
file | batches | source | format | nodes | relationships | properties | time | rows | batchSize |
---|---|---|---|---|---|---|---|---|---|
"export-cypher-format-addStructure.cypher" |
1 |
"data: nodes(5), rels(4)" |
"cypher" |
5 |
4 |
15 |
4 |
9 |
20000 |
UNWIND [{_id:0, properties:{tagline:"Welcome to the Real World", title:"The Matrix", released:1999}}] AS row
MERGE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) ON CREATE SET n += row.properties SET n:Movie;
UNWIND [{_id:7, properties:{born:1967, name:"Carrie-Anne Moss"}},
{_id:27, properties:{born:1964, name:"Keanu Reeves"}},
{_id:80, properties:{born:1960, name:"Hugo Weaving"}},
{_id:44, properties:{born:1961, name:"Laurence Fishburne"}}] AS row
MERGE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) ON CREATE SET n += row.properties SET n:Person;
UNWIND [{start: {_id:27}, end: {_id:0}, properties:{roles:["Neo"]}},
{start: {_id:7}, end: {_id:0}, properties:{roles:["Trinity"]}},
{start: {_id:44}, end: {_id:0}, properties:{roles:["Morpheus"]}},
{start: {_id:80}, end: {_id:0}, properties:{roles:["Agent Smith"]}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:ACTED_IN]->(end) SET r += row.properties;
在此示例中,我们使用 MERGE
子句创建节点(如果不存在),并且仅在节点不存在时才创建属性。在此示例中,关系不存在于目标数据库中,需要创建。
如果这些关系确实存在但需要更新属性,我们可以使用 cypherFormat: "updateStructure"
来创建导入脚本。
updateStructure
格式,将 ACTED_IN
关系及相关节点导出到 export-cypher-format-updateStructure.cypher
文件中MATCH (person)-[r:ACTED_IN]->(movie)
WITH collect(DISTINCT person) + collect(DISTINCT movie) AS importNodes, collect(r) AS importRels
CALL apoc.export.cypher.data(importNodes, importRels,
"export-cypher-format-updateStructure.cypher",
{ format: "plain", cypherFormat: "updateStructure" })
YIELD file, batches, source, format, nodes, relationships, properties, time, rows, batchSize
RETURN file, batches, source, format, nodes, relationships, properties, time, rows, batchSize;
file | batches | source | format | nodes | relationships | properties | time | rows | batchSize |
---|---|---|---|---|---|---|---|---|---|
"export-cypher-format-updateStructure.cypher" |
1 |
"data: nodes(5), rels(4)" |
"cypher" |
0 |
4 |
4 |
2 |
4 |
20000 |
UNWIND [{start: {_id:27}, end: {_id:0}, properties:{roles:["Neo"]}},
{start: {_id:7}, end: {_id:0}, properties:{roles:["Trinity"]}},
{start: {_id:44}, end: {_id:0}, properties:{roles:["Morpheus"]}},
{start: {_id:80}, end: {_id:0}, properties:{roles:["Agent Smith"]}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
MERGE (start)-[r:ACTED_IN]->(end) SET r += row.properties;
导出到多个文件或列
导出到 Cypher 过程都支持写入多个文件或多个列。我们可以通过传入配置 separateFiles: true
来启用此模式
ACTED_IN
关系和相应节点导出到以 actedIn
为前缀的文件中CALL apoc.export.cypher.query(
"MATCH ()-[r:ACTED_IN]->()
RETURN *",
"actedIn.cypher",
{ format: "cypher-shell", separateFiles: true })
YIELD file, batches, source, format, nodes, relationships, time, rows, batchSize
RETURN file, batches, source, format, nodes, relationships, time, rows, batchSize;
file | batches | source | format | nodes | relationships | time | rows | batchSize |
---|---|---|---|---|---|---|---|---|
"actedIn.cypher" |
1 |
"statement: nodes(10), rels(8)" |
"cypher" |
10 |
8 |
3 |
18 |
20000 |
这将导致创建以下文件
名称 | 大小(字节) | 行数 |
---|---|---|
actedIn.cleanup.cypher |
234 |
6 |
actedIn.nodes.cypher |
893 |
6 |
actedIn.relationships.cypher |
757 |
6 |
actedIn.schema.cypher |
109 |
3 |
每个文件都包含图的一个特定部分。让我们看看它们的内容
:begin
MATCH (n:`UNIQUE IMPORT LABEL`) WITH n LIMIT 20000 REMOVE n:`UNIQUE IMPORT LABEL` REMOVE n.`UNIQUE IMPORT ID`;
:commit
:begin
DROP CONSTRAINT uniqueConstraint;
:commit
:begin
UNWIND [{_id:28, properties:{tagline:"Welcome to the Real World", title:"The Matrix", released:1999}}, {_id:37, properties:{tagline:"Welcome to the Real World", title:"The Matrix", released:1999}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Movie;
UNWIND [{_id:31, properties:{born:1961, name:"Laurence Fishburne"}}, {_id:30, properties:{born:1967, name:"Carrie-Anne Moss"}}, {_id:42, properties:{born:1964, name:"Keanu Reeves"}}, {_id:0, properties:{born:1960, name:"Hugo Weaving"}}, {_id:29, properties:{born:1964, name:"Keanu Reeves"}}, {_id:38, properties:{born:1960, name:"Hugo Weaving"}}, {_id:43, properties:{born:1967, name:"Carrie-Anne Moss"}}, {_id:57, properties:{born:1961, name:"Laurence Fishburne"}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Person;
:commit
:begin
UNWIND [{start: {_id:31}, end: {_id:28}, properties:{roles:["Morpheus"]}}, {start: {_id:42}, end: {_id:37}, properties:{roles:["Neo"]}}, {start: {_id:38}, end: {_id:37}, properties:{roles:["Agent Smith"]}}, {start: {_id:0}, end: {_id:28}, properties:{roles:["Agent Smith"]}}, {start: {_id:29}, end: {_id:28}, properties:{roles:["Neo"]}}, {start: {_id:43}, end: {_id:37}, properties:{roles:["Trinity"]}}, {start: {_id:30}, end: {_id:28}, properties:{roles:["Trinity"]}}, {start: {_id:57}, end: {_id:37}, properties:{roles:["Morpheus"]}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:ACTED_IN]->(end) SET r += row.properties;
:commit
:begin
CREATE CONSTRAINT uniqueConstraint FOR (node:`UNIQUE IMPORT LABEL`) REQUIRE (node.`UNIQUE IMPORT ID`) IS UNIQUE;
:commit
然后,我们可以将这些文件应用到我们的目标 Neo4j 实例,方法是将它们的内容流式传输到 Cypher Shell 中,或者使用 运行 Cypher 片段 中描述的过程。
返回导出语句流时,也可以使用 separateFiles
。结果将出现在名为 nodeStatements
、relationshipStatements
、cleanupStatements
和 schemaStatements
的列中,而不是 cypherStatements
。
ACTED_IN
关系和相应节点的流CALL apoc.export.cypher.query(
"MATCH ()-[r:ACTED_IN]->()
RETURN *",
null,
{ format: "cypher-shell", separateFiles: true })
YIELD nodes, relationships, properties, nodeStatements, relationshipStatements, cleanupStatements, schemaStatements
RETURN nodes, relationships, properties, nodeStatements, relationshipStatements, cleanupStatements, schemaStatements;
nodes | relationships | properties | nodeStatements | relationshipStatements | cleanupStatements | schemaStatements |
---|---|---|---|---|---|---|
10 |
8 |
30 |
":begin UNWIND [{_id:28, properties:{tagline:\"Welcome to the Real World\", title:\"The Matrix\", released:1999}}, {_id:37, properties:{tagline:\"Welcome to the Real World\", title:\"The Matrix\", released:1999}}] AS row CREATE (n:`UNIQUE IMPORT LABEL`{ |
":begin UNWIND [{start: {_id:31}, end: {_id:28}, properties:{roles:[\"Morpheus\"]}}, {start: {_id:38}, end: {_id:37}, properties:{roles:[\"Agent Smith\"]}}, {start: {_id:0}, end: {_id:28}, properties:{roles:[\"Agent Smith\"]}}, {start: {_id:30}, end: {_id:28}, properties:{roles:[\"Trinity\"]}}, {start: {_id:29}, end: {_id:28}, properties:{roles:[\"Neo\"]}}, {start: {_id:43}, end: {_id:37}, properties:{roles:[\"Trinity\"]}}, {start: {_id:42}, end: {_id:37}, properties:{roles:[\"Neo\"]}}, {start: {_id:57}, end: {_id:37}, properties:{roles:[\"Morpheus\"]}}] AS row MATCH (start:`UNIQUE IMPORT LABEL`{ |
":begin MATCH (n:`UNIQUE IMPORT LABEL`) WITH n LIMIT 20000 REMOVE n:`UNIQUE IMPORT LABEL` REMOVE n. |
":begin CREATE CONSTRAINT uniqueConstraint FOR (node:`UNIQUE IMPORT LABEL`) REQUIRE (node. |
然后,我们可以将这些列的每个内容(不包括双引号)复制/粘贴到 Cypher Shell 会话中,或者复制/粘贴到我们流式传输到 Cypher Shell 会话的本地文件中。如果想导出可以粘贴到 Neo4j Browser 查询编辑器中的 Cypher 语句,需要使用配置 format: "plain"
,如导出为 Neo4j Browser 友好格式所述。
导出具有相同类型的多个关系
使用以下数据集
create (pers:Person {name: 'MyName'})-[:WORKS_FOR {id: 1}]->(proj:Project {a: 1}),
(pers)-[:WORKS_FOR {id: 2}]->(proj),
(pers)-[:WORKS_FOR {id: 2}]->(proj),
(pers)-[:WORKS_FOR {id: 3}]->(proj),
(pers)-[:WORKS_FOR {id: 4}]->(proj),
(pers)-[:WORKS_FOR {id: 5}]->(proj),
(pers)-[:IS_TEAM_MEMBER_OF {name: 'aaa'}]->(:Team {name: 'one'}),
(pers)-[:IS_TEAM_MEMBER_OF {name: 'eee'}]->(:Team {name: 'two'})
我们可以看到,在 :Person
和 :Project
节点之间,存在多个相同类型的关系 (WORKS_FOR
)。
我们可以看到,在 :Person
和 :Project
节点之间,存在多个相同类型的关系(WORKS_FOR
)。
在这些情况下,如果通过 MERGE
子句导出关系,必须使用配置 {multipleRelationshipsWithType: true}
,否则将无法区分它们,并且导出的脚本只会创建一个 WORKS_FOR
关系。
CALL apoc.export.cypher.all(null, {stream: true, multipleRelationshipsWithType: true}) YIELD cypherStatements
cypherStatements |
---|
":begin CREATE CONSTRAINT ON (node:`UNIQUE IMPORT LABEL`) ASSERT (node.`UNIQUE IMPORT ID`) IS UNIQUE; :commit CALL db.awaitIndexes(300); :begin UNWIND [{_id:1, properties:{a:1}}] AS row CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Project; UNWIND [{_id:2, properties:{name:"one"}}, {_id:3, properties:{name:"two"}}] AS row CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Team; UNWIND [{_id:0, properties:{name:"MyName"}}] AS row CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Person; :commit :begin UNWIND [{start: {_id:0}, end: {_id:2}, properties:{name:"aaa"}}, {start: {_id:0}, end: {_id:3}, properties:{name:"eee"}}] AS row MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id}) MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id}) CREATE (start)-[r:IS_TEAM_MEMBER_OF]→(end) SET r += row.properties; UNWIND [{start: {_id:0}, id: 0, end: {_id:1}, properties:{id:1}}, {start: {_id:0}, id: 1, end: {_id:1}, properties:{id:2}}, {start: {_id:0}, id: 2, end: {_id:1}, properties:{id:2}}, {start: {_id:0}, id: 3, end: {_id:1}, properties:{id:3}}, {start: {_id:0}, id: 4, end: {_id:1}, properties:{id:4}}, {start: {_id:0}, id: 5, end: {_id:1}, properties:{id:5}}] AS row MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id}) MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id}) CREATE (start)-[r:WORKS_FOR{`UNIQUE IMPORT ID REL`:row.id}]→(end) SET r += row.properties; :commit :begin MATCH (n:`UNIQUE IMPORT LABEL`) WITH n LIMIT 20000 REMOVE n:`UNIQUE IMPORT LABEL` REMOVE n.`UNIQUE IMPORT ID`; :commit :begin DROP CONSTRAINT ON (node:`UNIQUE IMPORT LABEL`) ASSERT (node.`UNIQUE IMPORT ID`) IS UNIQUE; :commit " |