【问题标题】:How to avoid duplicate while creating node using apoc.periodic.iterate for csv load neo4j?使用 apoc.periodic.iterate 为 csv 加载 neo4j 创建节点时如何避免重复?
【发布时间】:2021-03-22 10:19:55
【问题描述】:

我必须从 CSV 文件创建节点。由于文件太大,我正在使用 apoc.periodic.iterate 函数来读取文件。 CSV 具有重复条目,并且由于并行处理而创建了重复节点。如何确保即使使用并行处理也不会创建重复节点。

CALL apoc.periodic.iterate('LOAD CSV WITH HEADERS FROM "file:///DATA.csv" AS payload return payload',
'MERGE (l:PERSON {name :payload.name})
 ON CREATE SET 
              l.pid = payload.id,             
              l.createdDate= timestamp(),
              l.lastModifiedDate= timestamp()             
 ON MATCH SET 
              l.lastModifiedDate= timestamp()',
    {batchSize:500, parallel:true, concurrency: 4});

【问题讨论】:

    标签: csv neo4j cypher neo4j-apoc


    【解决方案1】:

    对于并行执行,您需要对 :PERSON(name) 设置唯一约束,因为唯一约束具有模式锁,可防止在这种情况下重复创建。

    如果名称不是唯一的,则禁用并行导入或清理您的数据,以免重复。

    您还可以在 MERGE 之前锁定单个节点以保证互斥,但这与禁用并行执行具有相同的效果,因此将并行切换为 false 是更好的选择。

    编辑

    所以您在这里遇到的问题是您的 MERGE 没有唯一约束支持。为了实现这一点,约束的属性和标签必须存在于模式中,如果你只在 ON CREATE 或 ON MATCH 部分中使用它们,它将不起作用。 p>

    所以如果你的约束是:PERSON(pid),那么你的模式应该是:

    MERGE (l:PERSON {pid:payload.id})
    

    然后您可以在 ON CREATE 部分设置名称。

    如果名称应该是唯一的,那么您可以通过在 :PERSON(name) 上创建唯一约束来获得相同的效果

    虽然您可以在查询中使用 EXPLAIN 来获取查询计划,但由于这是一个查询字符串,您需要进行一些剪切和粘贴操作以查看相关查询的计划,并进行少量添加在顶部,以便查询可以编译。你可以试试这个:

    EXPLAIN
    WITH $payload as payload
    MERGE (l:PERSON {name :payload.name})
     ON CREATE SET 
                  l.pid = payload.id,             
                  l.createdDate= timestamp(),
                  l.lastModifiedDate= timestamp()             
     ON MATCH SET 
                  l.lastModifiedDate= timestamp()
    

    您希望在计划中看到 NodeUniqueIndexSeek(Locking) 运算符,以便 MERGE 正常工作并使用正确的锁定来防止重复。

    如果您看到NodeIndexSeek,则仅使用了一个索引,它不会防止重复,因为没有任何东西可以锁定来保证互斥。你需要那个独特的约束。

    如果 NodeByLabelScan 存在,那就更糟了,因为您没有唯一约束或支持 MERGE 的索引。如果之前执行时间对您来说是个问题,那可能是因为它正在执行标签扫描,这对于加载来说根本性能不佳。

    【讨论】:

    • 我对 pid 有限制,因此如果 CSV 中存在重复条目并且脚本尝试创建节点,则会失败并跳过整个批处理。
    • 如果我们将并行切换为 false,那么完整 csv 的执行时间将会增加。 CSV 有大约 10 万条记录。
    • 那么你应该在 pid 上进行 MERGE,而不是在名称上(所以交换它们以便 pid 在模式中,并且在创建时设置名称),这应该会让你得到你想要的行为。此外,处理 10 万条记录最多只需要几秒钟,只需要确保您有一个索引(或唯一约束)来支持该 MERGE。
    • 名称对于所有节点也是唯一的,问题不在于约束。 Scenerio 就像 CSV 中有重复的条目并且节点没有在 DB 中退出。现在两个重复条目都由不同的批次选择,所以即使在使用合并之后,这两个批次都会尝试创建节点并且会引发冲突。
    • 由唯一约束支持的 MERGE 可以正常工作。如果它没有唯一约束的支持(如果 pid 不在模式中,您对 :PERSON(pid) 的约束将无济于事),那么您将获得当前面临的行为。您可以在更新查询的修改版本上使用 EXPLAIN 来查看其计划(以 WITH $payload as payload 为前缀以使其编译),您希望在查询计划中看到 NodeUniqueIndexSeek(Locking)
    猜你喜欢
    • 2018-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-17
    • 1970-01-01
    • 2018-06-13
    • 2013-11-07
    • 1970-01-01
    相关资源
    最近更新 更多