从Neo4j加载9M行并将其写入CSV会引发内存不足异常
我有一个大图模型,我需要将下面的查询结果写入csv从Neo4j加载9M行并将其写入CSV会引发内存不足异常,neo4j,spring-data-neo4j,spring-data-neo4j-4,neo4j-ogm,Neo4j,Spring Data Neo4j,Spring Data Neo4j 4,Neo4j Ogm,我有一个大图模型,我需要将下面的查询结果写入csv Match (u:USER)-[r:PURCHASED]->(o:ORDER)-[h:HAS]->(i:ITEM) return u.id as userId,i.product_number as itemId 当我“解释”查询时,我得到的结果是: 结果表明,估计结果约为900万。我的问题是: 1) 得到答复需要很长时间。从neo4j外壳开始需要38分钟!这正常吗?顺便说一句,我有所有模式索引,它们都在线 2) 当我使用Spr
Match (u:USER)-[r:PURCHASED]->(o:ORDER)-[h:HAS]->(i:ITEM) return u.id as userId,i.product_number as itemId
当我“解释”查询时,我得到的结果是:
结果表明,估计结果约为900万。我的问题是:
1) 得到答复需要很长时间。从neo4j外壳开始需要38分钟!这正常吗?顺便说一句,我有所有模式索引,它们都在线
2) 当我使用SpringDataNeo4j获取结果时,它抛出一个“java.lang.OutOfMemoryError:超出GC开销限制”错误,当SDN尝试将加载的数据转换为@QueryResult对象时,就会发生这种情况
我试图以各种不同的方式优化查询,但没有任何改变!我的印象是我做错了什么。有人知道我如何解决这个问题吗?我应该批量读/写吗
另外,我使用的是Neo4j comunity版本:3.0.1,以下是我的系统信息:
这些是我的服务器配置
dbms.jvm.additional=-Dunsupported.dbms.udc.source=tarball
use_memory_mapped_buffers=true
neostore.nodestore.db.mapped_memory=3G
neostore.relationshipstore.db.mapped_memory=4G
neostore.propertystore.db.mapped_memory=3G
neostore.propertystore.db.strings.mapped_memory=1000M
neostore.propertystore.db.index.keys.mapped_memory=500M
neostore.propertystore.db.index.mapped_memory=500M
尽管Neo4j会在匹配结果时将结果流式传输给您,但当您使用SDN时,它必须将输出收集到单个
@QueryResult
对象中。为了避免OOM问题,您需要确保应用程序有足够的堆内存来加载所有9m响应,或者使用neo4j shell,或者使用专门构建的流接口,例如。(注意:我还没有尝试过这个,但看起来应该可以了)您的配置设置对于Neo4j 3.0.1不正确
您必须在conf/neo4j-wrapper.conf中设置堆,例如8G
和conf/neo4j.conf中的页面缓存(查看您的商店,页面缓存只需要2G)
正如您所见,它将创建800多万行
您可能会更幸运地使用此查询:
Match (u:USER)-[:PURCHASED]->(:ORDER)-[:HAS]->(i:ITEM)
with distinct u,i
return u.id as userId,i.product_number as itemId
老实说,将800万行返回给neoj shell也没有意义。
如果要测量它,请将返回值
替换为并添加返回计数(*)
另一个优化<强>可以通过项目和用户进行,并在中间为“强”全局查询< /强>进行哈希连接:
Match (u:USER)-[:PURCHASED]->(o:ORDER)-[:HAS]->(i:ITEM)
USING JOIN ON o
with distinct u,i
WITH u.id as userId,i.product_number as itemId
RETURN count(*)
为了减少返回结果的数量,我可能会做的另一件事是尝试聚合
Match (u:USER)-[:PURCHASED]->(o:ORDER)-[:HAS]->(i:ITEM)
with distinct u,i
WITH u, collect(distinct i) as products
WITH u.id as userId,[i in products | i.product_number] as items
RETURN count(*)
多亏文斯和迈克尔的评论,我找到了解决办法!
在做了一些实验之后,很明显服务器的响应时间实际上是很好的!900万数据只需1.5分钟!正如文斯所说,问题在于SDN!当SDN试图将数据转换为@QueryResult对象时,会发生OOM。为我们的应用程序增加堆内存并不是一个永久的解决方案,因为我们将来会有更多的行!因此,我们决定使用Neo4jJDBC驱动程序进行大数据查询它像喷气式飞机一样工作!下面是我们使用的代码示例:
Class.forName("org.neo4j.jdbc.Driver");
try (Connection con = DriverManager.getConnection("jdbc:neo4j:bolt://HOST:PORT", "USER", "PASSWORD")) {
// Querying
String query = "match (u:USER)-[r:PURCHASED]->(o:ORDER)-[h:HAS]->(i:ITEM) return u.id as userId,i.product_number as itemId";
con.setAutoCommit(false); // important for large dataset
Statement st = con.createStatement();
st.setFetchSize(50);// important for large dataset
try (ResultSet rs = st.executeQuery(query)) {
while (rs.next()) {
writer.write(rs.getInt("userId") + ","+rs.getInt("itemId"));
writer.newLine();
}
}
st.setFetchSize(0);
writer.close();
st.close();
}
如果知道要加载大型数据集,请确保使用“con.setAutoCommit(false);”和“st.setFetchSize(50)”。谢谢大家 谢谢Michael,你说得对,dbms.memory.pagecache.size设置在错误的文件中。我改了。关于返回结果的数量,我不想减少它们,我需要它们全部。我需要创建一个csv的用户ID,项目ID。。。无法使用任何分组。。。我尝试了您建议的所有查询(vi neo4j shell…)都有相同的响应时间。我认为我的数据没有真正标准化:-),但我需要所有的副本。谢谢文斯,你给了我一个关于@QueryResult的好提示!
Class.forName("org.neo4j.jdbc.Driver");
try (Connection con = DriverManager.getConnection("jdbc:neo4j:bolt://HOST:PORT", "USER", "PASSWORD")) {
// Querying
String query = "match (u:USER)-[r:PURCHASED]->(o:ORDER)-[h:HAS]->(i:ITEM) return u.id as userId,i.product_number as itemId";
con.setAutoCommit(false); // important for large dataset
Statement st = con.createStatement();
st.setFetchSize(50);// important for large dataset
try (ResultSet rs = st.executeQuery(query)) {
while (rs.next()) {
writer.write(rs.getInt("userId") + ","+rs.getInt("itemId"));
writer.newLine();
}
}
st.setFetchSize(0);
writer.close();
st.close();
}