使用apoc.periodic.iterate for csv load neo4j创建节点时如何避免重复?

使用apoc.periodic.iterate for csv load neo4j创建节点时如何避免重复?,csv,neo4j,cypher,neo4j-apoc,Csv,Neo4j,Cypher,Neo4j Apoc,我必须从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

我必须从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});

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

如果名称不唯一,则禁用并行导入或清除数据,以避免重复

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

编辑

因此,您在这里遇到的问题是,您的合并没有得到唯一约束的支持。为了实现这一点,模式中必须同时存在约束的属性和标签,如果仅在“创建时”或“匹配时”部分中存在它们,则约束的属性和标签将不起作用

因此,如果您的约束条件是
:PERSON(pid)
,那么您的模式应该是:

MERGE (l:PERSON {pid:payload.id})
然后可以在“创建时”部分中设置名称

如果名称应该是唯一的,那么通过在
: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)
操作符,以便合并正常工作,并使用正确的锁定防止重复

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


如果存在
NodeByLabelScan
,则情况更糟,因为您没有唯一的约束或索引来支持合并。如果之前执行时间对您来说是个问题,可能是因为它正在进行标签扫描,这在加载时根本不会很好地执行。

我对pid有一个限制,因此如果CSV中存在重复条目,并且脚本尝试创建节点,它失败并跳过完整的批处理。如果我们将parallel切换为false,则完整csv的执行时间将增加。CSV有大约10万条记录。然后你应该在pid上合并,而不是在名称上合并(因此交换它们,使pid在模式中,并且在创建时设置名称),这样你就可以得到你想要的行为。此外,处理100k条记录最多只需几秒钟,只需确保您有一个索引(或唯一约束)来支持该合并。名称对于所有节点也是唯一的,问题不在于约束。Scenerio类似于CSV中存在重复条目,而DB中不存在节点。现在,两个重复条目都由不同的批处理拾取,因此即使在使用“合并”之后,这两个批处理都将尝试创建节点,并且会引发冲突。由唯一约束支持的合并也可以正常工作。如果没有唯一的约束支持(如果
pid
不在模式中,那么您对:PERSON(pid)的约束将不会有帮助),那么您将获得当前面临的行为。您可以在更新查询的修改版本上使用EXPLAIN来查看其计划(使用
前缀$payload as payload
将其编译),您希望在查询计划中查看
NodeUniqueIndexSeek(Locking)