我有一个大图模型,我需要将以下查询的结果写入csv。
Match (u:USER)-[r:PURCHASED]->(o:ORDER)-[h:HAS]->(i:ITEM) return u.id as userId,i.product_number as itemId
它显示估计结果约为9M。我的问题是:
1)获得回复需要很多时间。从neo4j-shell开始需要38分钟!这是正常的吗?顺便说一下,我有模式索引,它们都在线。
2)当我使用SpringDataNeo4j获取结果时,它会抛出一个" java.lang.OutOfMemoryError:超出GC开销限制"错误,当SDN尝试将加载的数据转换为@QueryResult对象时发生这种情况。
我尝试以各种方式优化查询,但没有改变!我的印象是我做错了什么。有谁知道如何解决这个问题?我应该去批量读/写吗?
P.S我正在使用Neo4j社区版本:3.0.1,这些是我的sysinfos:
这些是我的服务器配置。
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
答案 0 :(得分:6)
虽然Neo4j会在匹配它们时将结果传输给您,但是当您使用SDN时,它必须将输出收集到单个@QueryResult
对象中。为避免出现OOM问题,您需要确保应用程序有足够的堆内存可用于加载所有9m响应,或使用neo4j-shell,或使用专用流媒体接口,例如https://www.npmjs.com/package/cypher-stream。 (告诫者:我还没试过这个,但看起来应该这样做了)
答案 1 :(得分:3)
您的配置设置不适用于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
说实话,将8M行返回neoj-shell也没有意义。
如果您想衡量它,请将RETURN
替换为WITH
并添加RETURN count(*)
Match (u:USER)-[r:PURCHASED]->(o:ORDER)-[h:HAS]->(i:ITEM)
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)
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(*)
答案 2 :(得分:2)
感谢Vince和Michael的评论,我找到了解决方案! 做了一些实验后,很清楚服务器响应时间实际上是好的! 900万分数为1.5分钟!文斯提到的问题在于SDN!当SDN尝试将数据转换为@QueryResult对象时,就会发生OOM。为我们的应用程序增加堆内存不是永久解决方案,因为我们将来会有更多行!所以我们决定使用 neo4j-jdbc-driver 进行大数据查询...&它像喷气机一样工作!以下是我们使用的代码示例:
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(假); "和" st.setFetchSize(50)"如果您知道要加载大型数据集。谢谢大家!