LOAD CSV多MERGE操作出现Eager operator警告的解决方法
触发Eager警告的核心原因
Neo4j的Cypher查询规划器默认会担心同个查询中后序的写操作会影响前面的匹配结果,因此会将所有CSV内容预加载到内存后再统一执行写操作,就会触发Eager警告,大文件场景下很容易出现内存溢出。你去掉ON CREATE后能正常执行,是因为此时规划器能确认属性赋值不会影响MERGE的主键匹配逻辑,但不符合你的业务需求。
可行解决方案
前置操作(必做)
先给所有MERGE用到的主键添加唯一性约束,既可以大幅加快MERGE执行速度,也能帮助查询规划器确认匹配逻辑不会产生冲突:
// 示例约束,其余4类节点的主键请对应补充 CREATE CONSTRAINT unique_concept_cui FOR (c:Concept) REQUIRE c.cui IS UNIQUE; CREATE CONSTRAINT unique_lexicalform_lui FOR (l:LexicalForm) REQUIRE l.lui IS UNIQUE;
方案1:用子查询隔离写操作(推荐,适用于Neo4j 4.0+)
将每个节点的MERGE操作放到独立的CALL子查询中,子查询之间的写操作互不干扰,就不会触发Eager,全程仅需遍历1次CSV:
LOAD CSV FROM 'file:///MRCONSO.RRF' AS line FIELDTERMINATOR '|' // Concept节点合并逻辑 CALL { WITH line MERGE (c:Concept {cui: line[0]}) ON CREATE SET c.language = line[1] } // LexicalForm节点合并逻辑 CALL { WITH line MERGE (l:LexicalForm {lui: line[3]}) ON CREATE SET l.status = line[2] } // 剩余4类节点的合并逻辑,都按上面的格式单独套CALL子查询即可 // 按批次提交,替代旧版的USING PERIODIC COMMIT,批次大小可根据内存调整 IN TRANSACTIONS OF 1000 ROWS;
方案2:用APOC批量执行(适用于Neo4j 3.5及更早版本,需安装APOC插件)
如果你的数据库版本较低不支持子查询事务,可以用APOC的批量迭代工具实现:
CALL apoc.periodic.iterate( "LOAD CSV FROM 'file:///MRCONSO.RRF' AS line FIELDTERMINATOR '|' RETURN line", "MERGE (c:Concept {cui: line[0]}) ON CREATE SET c.language = line[1] MERGE (l:LexicalForm {lui: line[3]}) ON CREATE SET l.status = line[2] // 剩余4类节点的合并逻辑直接写在这里即可", {batchSize:1000, parallel:false} )
注意:parallel参数必须设为false,避免多线程写入产生死锁。
内容的提问来源于stack exchange,提问作者Martin Preusse
相关产品推荐
相关产品推荐

