在我的项目中,我使用spring neo4j4.2.0.m1和新4j-OGM 2.0.4。最初,这是使用一个嵌入式的新4j实例,但在调查这个问题的过程中,我已经迁移到了一个专用的新4j实例(尽管运行在同一台机器上),使用了Bolt协议。
我一直在插入数据,基本上是因为我的应用程序可以使用它(所以我不能使用批处理插入)。启动后,这个操作很好,保存我的NodeEntity的一个实例需要60 my,这对于我的用例来说是非常好的。然而,随着时间的推移,这种情况会慢慢退化。在10-20分钟后,每一次扑救的速度会减慢到大约2秒,这已经不太好了。时间似乎在这里达到顶峰,而且不会有更多的减少。
最初,我认为这是由于嵌入式实例太小造成的,因为我看到了关于neo4j报告GC暂停的重复消息。然后,我迁移到一个更大的专用实例,这些GC警告不再出现。尽管如此,退化仍在发生。
Neo4j报告的存储大小:
Array Store 8.00 KiB
Logical Log 151.36 MiB
Node Store 40.14 MiB
Property Store 1.83 GiB
Relationship Store 742.63 MiB
String Store> Size 120.87 MiB
Total Store Size 4.55 GiB实例配置如下:
dbms.memory.pagecache.size=5g
dbms.memory.heap.initial_size=4g
dbms.memory.heap.max_size=4g
dbms.jvm.additional=-XX:+UseG1GC使用YourKit分析器(采样模式!)我可以看到,大部分时间似乎都是由新4j-oGM的EntityGraphMapper花费的,特别是在
org.neo4j.ogm.context.EntityGraphMapper#haveRelationEndsChanged

保存的NodeEntity通常与其他节点有大约40种关系,其中大多数被建模为RelationshipEntity。在早期阶段,我已经注意到保存实体非常缓慢,因为也映射了太多相关(但未更改)实体。从那以后,我在保存时使用了1的深度。导致保存NodeEntitites的连续操作使用200个实体的事务大小。
我还不相信,新4j-ogm实际上是经济放缓的原因,因为我看不出与良好的初步结果相比有什么变化。在这种情况下,我通常怀疑内存泄漏/污染,但是在我的应用程序中,所有的监控结果看起来都很好。对于neo4j服务器实例,除了debug.log之外,我真的不知道在哪里查找这样的信息。
总之,我已经花了相当长的时间研究这个问题,不知道还能看到什么。有什么想法或建议吗?我很高兴提供更多的资料。
编辑: Follwing @vince的输入,我再次查看了内存分布,发现实际上Neo4jSession在允许应用程序运行了3h之后已经增长了很多:

当时堆是1,7GB大,其中70%引用活数据。其中,大约300 by目前由Neo4jSession引用(并保持存活)。这可能表明它已经发展得太大了。我怎么能手动干预这里呢?
发布于 2016-11-10 11:43:12
实体在会话中一直呆到垃圾被收集为止。如果您正在加载数千个实体,那么在haveRelationEndsChanged中可能会有一些性能影响,所以在每个事务之间执行session.clear()可能是值得的,看看这是否有帮助。
发布于 2017-10-29 01:41:12
希望现在帮助解决这个问题还不算太晚。
最近,当我在一组中保存一个具有大约900个关系的节点时,我也遇到了同样的情况,并且可以使它在大约5秒到500 to之间执行。我最初使用的是新4j-ogm 2.1.3,刚刚迁移到3.0.0。尽管3.0.0要快得多,但这两个版本的性能提高是相似的。
下面是一些伪代码(我现在不能共享真正的代码):
@NodeEntity(label = "MyNode")
public class MyNode {
@GraphId
private Long id;
@Index(unique = true, primary = true)
private String myUniqueValue;
private String value;
@Relationship(type = "CONNECTS_TO")
private Set<MyRelationship> relationships;
// constructors, getters, setters
}
@Relationship(type = "CONNECTS_TO")
public class MyRelationship {
@GraphId
private Long id;
@StartNode
private MyNode parent;
@EndNode
private MyNode child;
// constructors, getters, setters
}请注意,MyNode有一个索引/唯一字段,在该字段中,我可以完全控制该值。新4j-OGM将使用它来确定它是应该执行CREATE语句还是MERGE语句。在我的用例中,如果节点已经存在,我希望合并发生。
另一方面,关系创建依赖于节点id (@GraphId字段)。下面是创建它的语句的一个小片段:
UNWIND {rows} as row MATCH (startNode) WHERE ID(startNode) = row.startNodeId MATCH (endNode) WHERE ID(endNode) = row.endNodeId...
在慢速模式下,新4j-ogm将负责检查关系或其中的节点是否已经保存,并将检索创建节点所需的ids。这是您在YourKit中捕获的操作。
一个缓慢执行的示例:
void slowMode() {
MyNode parent = new MyNode("indexed-and-unique", "some value");
for (int j = 0; j < 900; j++) {
MyNode child = new MyNode("indexed-and-unique" + j, "child value" + j);
parent.addRelationship(new MyRelationship(parent, child));
}
session.save(parent); // save everything. slow.
}我找到的解决方案是将这些操作分为三个部分:
这样做要快得多:
void fastMode() {
MyNode parent = new MyNode("indexed-and-unique", "some value");
for (int j = 0; j < 900; j++) {
MyNode child = new MyNode("indexed-and-unique" + j, "child value" + j);
parent.addRelationship(new MyRelationship(parent, child));
}
session.save(parent, 0); // save only the parent
session.save(getAllChildsFrom(parent), 0); // save all the 900 childs
// at this point, all instances of MyNode will contain an "id". time to save the relationships!
session.save(parent);
}需要注意的一点是:在保存节点集合(session.save(getAllChildsFrom(parent), 0))时,新4j-OGM2.1.3没有执行单个批处理语句,它仍然是聊天和缓慢的,但不像以前那么慢。版本3.0.0修复了这个问题。
希望能帮上忙!
发布于 2016-11-09 12:15:35
不久前,当我们需要将大量数据存储到neo4j时,我们实际上也遇到了同样的情况。我们分析了如何处理这个问题的不同方法。因此,我们找到了一些解决方案,如何加快将数据插入到neo4j。
https://stackoverflow.com/questions/40496129
复制相似问题