私は現在、大量のノード/関係をグラフに挿入するという観点から、neo4j を評価しています。バッチ挿入で達成できる最初の挿入についてではありません。組み込みモードでneo4jを使用するJavaアプリケーション(spring-data-neo4j 2.2.2.RELEASEに同梱されているため、現在バージョン1.8.1)で実行時に頻繁に処理される挿入についてです。
これらの挿入は通常、スター スキーマに従うノードです。1 つのノード (インポートされたデータセットのルート ノード) には、最大1000000 (100 万!)の接続された子ノードがあります。子ノードは通常、他の追加ノードとも関係があります。しかし、これらの関係は、これまでのところこのテストではカバーされていません。全体的な目標は、その量のデータを最大 5 分でインポートすることです。
Neo4jTemplate
このような種類の挿入をシミュレートするために、ノードと関係を作成するために を使用する小さな junit テストを作成しました。挿入された各リーフには、後で処理するために関連付けられたキーがあります。
@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 Web サイトとさまざまなスクリーンキャストで、neo4j が数十億のノードと関係で実行できるという情報を見つけました (例: http://docs.neo4j.org/chunked/stable/capabilities-capacity.html )。JPAなどでヒープを手動でクリーンに保つために利用できるような機能flush()
やメソッドは見つかりませんでした。clean()
その量のデータでneo4jを使用できるのは素晴らしいことです. すでに 200000 枚のリーフがグラフに保存されているため、組み込みの従来の RDBMS と比較して、パフォーマンスが 10 倍以上向上していることに気付きました。私は、neo4j が提供するようなデータ モデリングとそれらのデータのクエリの優れた方法をあきらめたくありません。