Neo4j 如何解释Cypher'的性能;s加载CSV子句?

Neo4j 如何解释Cypher'的性能;s加载CSV子句?,neo4j,cypher,Neo4j,Cypher,我在Neo4J 2.1.2中使用了Cypher的加载CSV语法。到目前为止,它比以前版本中需要的更手动的ETL过程有了巨大的改进。但我在一个案例中遇到了一些行为,这不是我所期望的,我想知道我是否遗漏了什么 正在使用的密码查询如下所示: USING PERIODIC COMMIT 500 LOAD CSV FROM 'file:///Users/James/Desktop/import/dependency_sets_short.csv' AS row MATCH (s:Sense {uid: t

我在Neo4J 2.1.2中使用了Cypher的
加载CSV
语法。到目前为止,它比以前版本中需要的更手动的ETL过程有了巨大的改进。但我在一个案例中遇到了一些行为,这不是我所期望的,我想知道我是否遗漏了什么

正在使用的密码查询如下所示:

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
我的期望是增长或多或少是线性的,特别是当我按照建议每500行提交一次时,但它实际上更接近多项式:

更糟糕的是,在300k到400k行之间的某个地方,它遇到了Java堆空间错误。根据以前进口的趋势,我预计进口40万美元需要一分钟多一点时间。相反,在运行到堆空间错误之前,它会搅拌大约5-7分钟。看起来我可以把这个文件分成300000行,但这不是“使用定期提交”应该做的吗?我想我也可以给Neo4J更多的内存,但同样,我不清楚为什么我必须在这个场景中这样做

另外,需要明确的是,
Sense.uid
DependencySet.label
上的查找都是索引的,因此对它们的查找代价应该很小。下面是模式中的一个片段:

Indexes
  ON :DependencySet(label) ONLINE (for uniqueness constraint)
  ON :Sense(uid)           ONLINE (for uniqueness constraint)
如有任何关于替代方法的解释或想法,将不胜感激


编辑:问题显然出现在查询的匹配和/或创建部分。如果我从Cypher查询中删除第3行和第5行,它将正常运行。

我假设在运行此
LOAD CSV
导入之前,您已经创建了所有
Sense
标记的节点。我认为正在进行的是,当您将带有标签
Sense
的节点匹配到内存中,并通过
CREATE(s)-[:HAS]->(ds)
创建从
DependencySet
Sense
节点的关系时,您正在提高可用堆的利用率

另一种可能性是需要增加内存映射设置中关系存储的大小。在您的场景中,
Sense
节点与图中的其他节点具有高度的连通性。发生这种情况时,这些节点的关系存储需要更多内存。最终,当达到400k个节点时,堆将达到最大值。在此之前,它需要进行更多的垃圾收集和磁盘读取

Michael Hunger撰写了一篇关于快速
加载CSV
性能的内存映射设置的优秀博文。请看这里:

那应该能解决你的问题。我看你的询问没有任何问题。

我相信这句话

匹配(s:Sense{uid:toInt(行[4]))

使时间成为范例。在图形x线的大约200000处,内存中不再有所有
Sense
节点,但其中一些节点必须缓存到磁盘。因此,所有时间的增加都只是将数据从缓存重新加载到内存,反之亦然(否则,如果保留在内存中,数据仍然是线性的)

也许如果你能发布你的服务器内存设置,我们可以深入挖掘


关于java堆错误的问题,请参考Kenny的答案

基于Kenny的答案,我使用了中推荐的内存设置。这无疑修复了堆错误。我继续测试了400k、500k,最后测试了完整的数据集(700k多一点),在每种情况下都有效。而且,时间/行数曲线肯定有点平坦。不是很线性,但更接近。然后我将
nodestore.db.mapped_内存
relationshipstore.db.mapped_内存
加倍并重新运行,但好处微不足道。在这一点上,性能是完全可以接受的。谢谢你给我指出那篇博文,Michael Hunger建议的设置修复了堆错误。将关系存储和/或节点存储内存设置推到更高的位置并重复会产生微不足道的好处,因此我猜这可能是最快的。对我来说,这已经足够快了。