【问题标题】:Importing json in neo4J在 neo4J 中导入 json
【发布时间】:2020-04-27 15:20:36
【问题描述】:

[问题 - 下面是我的最终解决方案]

我想将包含我的数据的 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": {} },
    ....
        ]
    }
}

与此处建议的类似:How can I restore data from a previous result in the browser?

通过查看答案。 我发现我可以使用

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 指的是一个节点。 所以问题是:是否存在使用 ids 作为索引或其他东西来加速导入过程?

请注意,我的节点有不同的类型。所以我没有找到为所有这些创建索引的方法,我想那会太大(内存)

[我的解决方案]

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

【问题讨论】:

    标签: json neo4j neo4j-apoc


    【解决方案1】:

    [编辑]

    这种方法可能更有效:

    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.setKeyid 属性添加到n.properties 来避免调用SET

    2 UNWINDs 不会导致笛卡尔积,因为此查询使用 aggregating function COLLECT(在第二个 UNWIND 之前)将所有前面的行压缩为一个(因为分组键 @ 987654331@,是一个单例)。

    【讨论】:

    • 我收到了java.lang.NullPointerException。我相信这是因为nMap[r.startNode] 不起作用(或nMap[r.endNode])。我试图理解为什么,似乎Collect 创建了一个地图列表,而不仅仅是一个地图。所以,我尝试使用apoc.map.mergelist() 创建一个地图,但看起来我不知道该怎么做,因为它仍然不起作用......请注意,我确信 startNode 和 endNote 存在于我的 ID 中(在节点中)
    • 还要注意startNode 不是在节点集合中的位置。它只是 ID。
    • 我已通过使用apoc.map.mergeList 将地图列表转换为单个地图来修复查询。此外,nMap[r.startNode] 语法是您可以使用动态键访问映射值的方式,因此应该不是问题。
    • 您好,我遇到了另一个异常Expected Long(3511200) to be a org.neo4j.values.storable.TextValue, but it was a org.neo4j.values.storable.LongValue
    • 看起来n.id 是数字。尝试将COLLECT({id: n.id, node: node}) 更改为COLLECT({id: TOSTIRNG(n.id), node: node})。如果您仍然遇到同样的错误,您可能还必须在 r.startNoder.endNode 上使用 TOSTRING
    【解决方案2】:

    您是否尝试过在 LOAD JSON 之前索引节点?这可能站不住脚,因为您有多个节点标签。但是如果它们受到限制,您可以创建占位符节点,创建并索引然后删除占位符。在此之后,运行 LOAD Json

        Create (n:YourLabel{indx:'xxx'})
        create index on: YourLabel(indx)
        match (n:YourLabel) delete n
    

    索引将加速匹配或合并

    【讨论】:

    • 我考虑过索引。但是,我有多个标签,在加载之前我可能不知道它们。你如何创建占位符?
    • Placeholder created with: create (n:NodeName(param:'xxx'}) create index on: NodeName(param) match (n:NodeName(param:'xxx'}) delete n跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-02
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 2014-08-11
    相关资源
    最近更新 更多