我目前正在评估 neo4j 在图中插入大量节点/关系的方式。这与可以通过批量插入实现的初始插入无关。它是关于在嵌入式模式下使用 neo4j(当前版本为 1.8.1,因为它与 spring-data-neo4j 2.2.2.RELEASE 一起提供)的 Java 应用程序在运行时频繁处理的插入。
这些插入通常是遵循星型模式的节点。一个节点(导入数据集的根节点)有多达1000000(一百万!)个连接的子节点。子节点通常也与其他附加节点有关系。但到目前为止,该测试并未涵盖这些关系。总体目标是在最多五分钟内导入该数量的数据!
为了模拟这种插入,我编写了一个小的 junit 测试,它使用Neo4jTemplate
来创建节点和关系。每个插入的叶子都有一个关联的键以供以后处理:
@Test
@Transactional
@Rollback
public void generateUngroupedNode()
{
long numberOfLeafs = 1000000;
Assert.assertTrue(this.template.transactionIsRunning());
Node root = this.template.createNode(map(NAME, UNGROUPED));
String groupingKey = null;
for (long index = 0; index < numberOfLeafs; index++)
{
// Just a sample division of leafs to possible groups
// Creates keys to be grouped by to groups containing 2 leafs each
if (index % 2 == 0)
{
groupingKey = UUID.randomUUID().toString();
}
Node leaf = this.template.createNode(map(GROUPING_KEY, groupingKey, NAME, LEAF));
this.template.createRelationshipBetween(root, leaf, Relationships.LEAF.name(),
map());
}
}
对于这个测试,我使用gcr
缓存来避免垃圾收集器问题:
cache_type=gcr
node_cache_array_fraction=7
relationship_cache_array_fraction=5
node_cache_size=400M
relationship_cache_size=200M
此外,我将我的设置MAVEN_OPTS
为:
export MAVEN_OPTS="-Xmx4096m -Xms2046m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:-UseGCOverheadLimit"
但无论如何,在运行该测试时,我总是会得到一个Java heap space
错误:
java.lang.OutOfMemoryError: Java heap space
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
at java.lang.Class.getMethod0(Class.java:2670)
at java.lang.Class.getMethod(Class.java:1603)
at org.apache.commons.logging.LogFactory.directGetContextClassLoader(LogFactory.java:896)
at org.apache.commons.logging.LogFactory$1.run(LogFactory.java:862)
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.commons.logging.LogFactory.getContextClassLoaderInternal(LogFactory.java:859)
at org.apache.commons.logging.LogFactory.getFactory(LogFactory.java:423)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:685)
at org.springframework.transaction.support.TransactionTemplate.<init>(TransactionTemplate.java:67)
at org.springframework.data.neo4j.support.Neo4jTemplate.exec(Neo4jTemplate.java:403)
at org.springframework.data.neo4j.support.Neo4jTemplate.createRelationshipBetween(Neo4jTemplate.java:367)
我用较少的数据进行了一些测试,结果如下。1 个节点连接到:
- 50000叶:3035ms
- 100000叶:4290ms
- 200000叶:10268ms
- 400000叶:20913ms
- 800000 个叶子:Java 堆空间
以下是这些操作期间系统监视器的屏幕截图:
为了更好地了解究竟在运行什么并存储在堆中,我使用最后一个测试(800000 个叶子)运行了 JProfiler。以下是一些截图:
堆使用:
CPU使用率:
对我来说最大的问题是:neo4j 不是为使用这种海量数据而设计的吗?还是有其他方法可以实现这种插入(以及以后的操作)?在 neo4j 官方网站和各种截屏视频中,我发现了 neo4j 能够运行数十亿个节点和关系的信息(例如http://docs.neo4j.org/chunked/stable/capabilities-capacity.html)。我没有找到任何可用的功能flush()
和方法,例如在 JPA 中可以手动保持堆清洁。clean()
能够将 neo4j 与这些数据量一起使用会很棒。图表中已经存储了 200000 个叶子,我注意到与嵌入式经典 RDBMS 相比,性能提高了 10 倍甚至更多。我不想放弃像 neo4j 提供的数据建模和查询这些数据的好方法。