正在使用的密码查询是这样的:
USING PERIODIC COMMIT 500 LOAD CSV FROM 'file:///Users/James/Desktop/import/dependency_sets_short.csv' AS row MATCH (s:Sense {uid: toInt(row[4])}) MERGE (ds:DependencySet {label: row[2]}) ON CREATE SET ds.optional=(row[3] = 't') CREATE (s)-[:has]->(ds)
以下是CSV的几行:
227303,1,TO-PURPOSE-NOMINAL,t,73830 334471,1,AT-LOCATION,t,92048 334470,1,AT-TIME,t,92048 334469,1,ON-LOCATION,t,92048 227302,1,TO-PURPOSE-INFINITIVE,t,73830 116008,1,TO-LOCATION,t,68204 116007,1,IN-LOCATION,t,68204 227301,1,TO-LOCATION,t,73830 334468,1,ON-DATE,t,92048 116006,1,AT-LOCATION,t,68204 334467,1,WITH-ASSOCIATE,t,92048
基本上,我根据它的ID值(第五列)匹配一个Sense节点(先前已导入).然后我正在进行合并以获得DependencySet节点(如果存在),或者创建它.最后,我在Sense节点和DependencySet节点之间创建了一个has边缘.到目前为止一切顺利,这一切都按预期工作.随着CSV大小的增长,性能令人困惑.
CSV Lines Time (msec) ------------------------------ 500 480 1000 717 2000 1110 5000 1521 10000 2111 50000 4794 100000 5907 200000 12302 300000 35494 400000 Java heap space error
我的期望是增长会或多或少是线性的,特别是当我按照manual推荐的每500行提交时,但它实际上更接近于多项式:
更糟糕的是,在300k到400k行之间,它会遇到Java堆空间错误.根据之前进口的趋势,我预计400k的进口需要一分多钟.相反,它会在遇到堆空间错误之前搅拌大约5-7分钟.看起来我可以将这个文件分成300,000行的块,但这不是“使用周期性委托”应该做的,或多或少?我想我也可以为Neo4J提供更多内存,但同样,我不清楚为什么我应该在这种情况下.
另外,要明确的是,Sense.uid和DependencySet.label上的查找都会被编入索引,因此这些查找的查找代价应该非常小.这是架构的一个片段:
Indexes ON :DependencySet(label) ONLINE (for uniqueness constraint) ON :Sense(uid) ONLINE (for uniqueness constraint)
对于替代方法的任何解释或想法将不胜感激.
编辑:问题肯定似乎是在查询的MATCH和/或CREATE部分.如果我从Cypher查询中删除第3行和第5行,它就可以正常运行.
我假设您在运行此LOAD CSV导入之前已经创建了所有Sense标记的节点.我认为正在进行的是,当您将带有标签Sense的节点匹配到内存中并通过CREATE(s) – [:HAS] – >(ds)创建从DependencySet到Sense节点的关系时,您将提高可用的堆.另一种可能性是需要增加内存映射设置中关系存储的大小.在您的场景中,看起来Sense节点与图中的其他节点具有高度的连接性.发生这种情况时,这些节点的关系存储需要更多内存.最终当你达到400k节点时,堆最大化了.到那时为止,它需要进行更多垃圾收集并从磁盘读取.
Michael Hunger撰写了一篇关于内存映射设置的优秀博客文章,以实现快速LOAD CSV性能.见:http://jexp.de/blog/2014/06/load-csv-into-neo4j-quickly-and-successfully/
那应该可以解决你的问题.我没有看到您的查询有任何问题.