在 neo4J 中导入 json
Importing json in neo4J
[问题 - 下面是我的最终解决方案]
我想将包含我的数据的 json 文件导入 Neo4J。
但是,它超级慢。
Json 文件的结构如下
{
"graph": {
"nodes": [
{ "id": 3510982, "labels": ["XXX"], "properties": { ... } },
{ "id": 3510983, "labels": ["XYY"], "properties": { ... } },
{ "id": 3510984, "labels": ["XZZ"], "properties": { ... } },
...
],
"relationships": [
{ "type": "bla", "startNode": 3510983, "endNode": 3510982, "properties": {} },
{ "type": "bla", "startNode": 3510984, "endNode": 3510982, "properties": {} },
....
]
}
}
与此处提出的类似:。
通过查看答案。
我发现我可以使用
CALL apoc.load.json("file:///test.json") YIELD value AS row
WITH row, row.graph.nodes AS nodes
UNWIND nodes AS node
CALL apoc.create.node(node.labels, node.properties) YIELD node AS n
SET n.id = node.id
然后
CALL apoc.load.json("file:///test.json") YIELD value AS row
with row
UNWIND row.graph.relationships AS rel
MATCH (a) WHERE a.id = rel.endNode
MATCH (b) WHERE b.id = rel.startNode
CALL apoc.create.relationship(a, rel.type, rel.properties, b) YIELD rel AS r
return *
(我必须分两次做,否则它们是由于两个 unwind
而导致的关系重复)。
但这太慢了,因为我有很多实体,而且我怀疑程序会针对每个关系搜索所有实体。
同时,我知道"startNode": 3510983
指的是一个节点。
所以问题是:它是否存在以使用 id 作为索引或其他方式来加速导入过程?
Note that my nodes have differents types. So I did not find a way to create an index for all of them, and I suppose that would be too huge (memory)
[我的解决方案]
CALL apoc.load.json('file:///test.json') YIELD value
WITH value.graph.nodes AS nodes, value.graph.relationships AS rels
UNWIND nodes AS n
CALL apoc.create.node(n.labels, apoc.map.setKey(n.properties, 'id', n.id)) YIELD node
WITH rels, COLLECT({id: n.id, node: node, labels:labels(node)}) AS nMap
UNWIND rels AS r
MATCH (w{id:r.startNode})
MATCH (y{id:r.endNode})
CALL apoc.create.relationship(w, r.type, r.properties, y) YIELD rel
RETURN rel
[编辑]
这种方法可能更有效:
CALL apoc.load.json("file:///test.json") YIELD value
WITH value.graph.nodes AS nodes, value.graph.relationships AS rels
UNWIND nodes AS n
CALL apoc.create.node(n.labels, apoc.map.setKey(n.properties, 'id', n.id)) YIELD node
WITH rels, apoc.map.mergeList(COLLECT({id: n.id, node: node})) AS nMap
UNWIND rels AS r
CALL apoc.create.relationship(nMap[r.startNode], r.type, r.properties, nMap[r.endNode]) YIELD rel
RETURN rel
此查询根本不使用 MATCH
(并且不需要索引),因为它仅依赖于从导入的节点 ID 到创建的节点的内存映射。但是,如果有大量导入节点,此查询 可能 运行 内存不足。
它还通过使用 apoc.map.setKey 将 id
属性 添加到 n.properties
来避免调用 SET
。
2个UNWIND
不会导致笛卡尔积,因为这个查询使用aggregating function COLLECT
(在第二个UNWIND
之前)压缩所有前面的行合二为一(因为分组键 rels
是单例)。
您是否尝试过在 LOAD JSON 之前索引节点?这可能是站不住脚的,因为您有多个节点标签。但是如果它们是有限的,你可以创建占位符节点,创建和索引然后删除占位符。在此之后,运行 LOAD Json
Create (n:YourLabel{indx:'xxx'})
create index on: YourLabel(indx)
match (n:YourLabel) delete n
索引将加快匹配或合并
[问题 - 下面是我的最终解决方案]
我想将包含我的数据的 json 文件导入 Neo4J。 但是,它超级慢。
Json 文件的结构如下
{
"graph": {
"nodes": [
{ "id": 3510982, "labels": ["XXX"], "properties": { ... } },
{ "id": 3510983, "labels": ["XYY"], "properties": { ... } },
{ "id": 3510984, "labels": ["XZZ"], "properties": { ... } },
...
],
"relationships": [
{ "type": "bla", "startNode": 3510983, "endNode": 3510982, "properties": {} },
{ "type": "bla", "startNode": 3510984, "endNode": 3510982, "properties": {} },
....
]
}
}
与此处提出的类似:
通过查看答案。 我发现我可以使用
CALL apoc.load.json("file:///test.json") YIELD value AS row
WITH row, row.graph.nodes AS nodes
UNWIND nodes AS node
CALL apoc.create.node(node.labels, node.properties) YIELD node AS n
SET n.id = node.id
然后
CALL apoc.load.json("file:///test.json") YIELD value AS row
with row
UNWIND row.graph.relationships AS rel
MATCH (a) WHERE a.id = rel.endNode
MATCH (b) WHERE b.id = rel.startNode
CALL apoc.create.relationship(a, rel.type, rel.properties, b) YIELD rel AS r
return *
(我必须分两次做,否则它们是由于两个 unwind
而导致的关系重复)。
但这太慢了,因为我有很多实体,而且我怀疑程序会针对每个关系搜索所有实体。
同时,我知道"startNode": 3510983
指的是一个节点。
所以问题是:它是否存在以使用 id 作为索引或其他方式来加速导入过程?
Note that my nodes have differents types. So I did not find a way to create an index for all of them, and I suppose that would be too huge (memory)
[我的解决方案]
CALL apoc.load.json('file:///test.json') YIELD value
WITH value.graph.nodes AS nodes, value.graph.relationships AS rels
UNWIND nodes AS n
CALL apoc.create.node(n.labels, apoc.map.setKey(n.properties, 'id', n.id)) YIELD node
WITH rels, COLLECT({id: n.id, node: node, labels:labels(node)}) AS nMap
UNWIND rels AS r
MATCH (w{id:r.startNode})
MATCH (y{id:r.endNode})
CALL apoc.create.relationship(w, r.type, r.properties, y) YIELD rel
RETURN rel
[编辑]
这种方法可能更有效:
CALL apoc.load.json("file:///test.json") YIELD value
WITH value.graph.nodes AS nodes, value.graph.relationships AS rels
UNWIND nodes AS n
CALL apoc.create.node(n.labels, apoc.map.setKey(n.properties, 'id', n.id)) YIELD node
WITH rels, apoc.map.mergeList(COLLECT({id: n.id, node: node})) AS nMap
UNWIND rels AS r
CALL apoc.create.relationship(nMap[r.startNode], r.type, r.properties, nMap[r.endNode]) YIELD rel
RETURN rel
此查询根本不使用 MATCH
(并且不需要索引),因为它仅依赖于从导入的节点 ID 到创建的节点的内存映射。但是,如果有大量导入节点,此查询 可能 运行 内存不足。
它还通过使用 apoc.map.setKey 将 id
属性 添加到 n.properties
来避免调用 SET
。
2个UNWIND
不会导致笛卡尔积,因为这个查询使用aggregating function COLLECT
(在第二个UNWIND
之前)压缩所有前面的行合二为一(因为分组键 rels
是单例)。
您是否尝试过在 LOAD JSON 之前索引节点?这可能是站不住脚的,因为您有多个节点标签。但是如果它们是有限的,你可以创建占位符节点,创建和索引然后删除占位符。在此之后,运行 LOAD Json
Create (n:YourLabel{indx:'xxx'})
create index on: YourLabel(indx)
match (n:YourLabel) delete n
索引将加快匹配或合并