REST API のバッチ エンドポイントを介して、Neo4j にノード間の関係を持つ大量のノードを挿入する必要があります (約 5,000 レコード/秒 (まだ増加中))。
これは、24 時間年中無休で連続挿入されます。各レコードでは 1 つのノードのみを作成する必要がある場合がありますが、他のレコードでは 2 つのノードと 1 つの関係を作成する必要がある場合があります。
手順を変更したり、Neo4j の設定を変更したりすることで、挿入のパフォーマンスを向上させることはできますか?
これまでの私の進捗状況:
1.しばらくNeo4jでテストしてきましたが、必要なパフォーマンスが得られませんでした
テスト サーバー ボックス: 24 コア + 32GB RAM
スタンドアロン サービスとしてインストールされた Neo4j 2.0.0-M06。
同じサーバー上で Java アプリケーションを実行します。
REST API エンドポイント: /db/data/batch (ターゲット: /cypher)
スキーマ インデックス、制約、MERGE、CREATE UNIQUE を使用します。
2.私のスキーマ:
neo4j-sh (0)$ schema
==> Indexes
==> ON :REPLY(created_at) ONLINE
==> ON :REPLY(ids) ONLINE (for uniqueness constraint)
==> ON :REPOST(created_at) ONLINE
==> ON :REPOST(ids) ONLINE (for uniqueness constraint)
==> ON :Post(userId) ONLINE
==> ON :Post(postId) ONLINE (for uniqueness constraint)
==>
==> Constraints
==> ON (post:Post) ASSERT post.postId IS UNIQUE
==> ON (repost:REPOST) ASSERT repost.ids IS UNIQUE
==> ON (reply:REPLY) ASSERT reply.ids IS UNIQUE
3. 私の暗号クエリと JSON リクエスト
3.1. 1 つのレコードで単一ノードの作成が必要な場合、ジョブの説明は次のようになります。
{"method" : "POST","to" : "/cypher","body" : {"query" : "MERGE (child:Post {postId:1001, userId:901})"}}
3.2. 1 つのレコードが 1 つの関係を持つ 2 つのノードを作成する必要がある場合、ジョブの説明は次のようになります。
{"method" : "POST","to" : "/cypher","body" : {"query" : "MERGE (parent:Post {postId:1002, userId:902}) MERGE (child:Post {postId:1003, userId:903}) CREATE UNIQUE parent-[relationship:REPOST {ids:'1002_1003', created_at:'Wed Nov 06 14:06:56 AST 2013' }]->child"}}
3.3. 私は通常、バッチごとに 100 個のジョブ記述 (3.1 と 3.2 の混合) を送信しますが、これには約 150 ~ 250 ミリ秒かかります。
4. パフォーマンスの問題
4.1. 同時実行:
/db/data/batch (ターゲット: /cypher) はスレッド セーフではないようです。2 つ以上の同時スレッドでテストすると、Neo4j サーバーが数秒から数分以内にダウンしました。
4.2. 制約のある MERGE は常に機能するとは限りません。
2 つのノードと 1 つのリレーションシップを 1 つのクエリで作成する場合 (上記の 3.2 で説明)、魅力的に機能することがあります。しかし、CypherExecutionException で失敗し、ノード xxxx の 1 つがラベル aaaa とプロパティ "bbbbb"=[ccccc] で既に存在すると言って失敗することがあります。私の理解では、MERGE は例外を返すとは想定していませんが、既に存在する場合はノードを返します。
例外の結果、バッチ全体が失敗してロールバックし、挿入率に影響します。
この問題について、GitHub で問題をオープンしました。 https://github.com/neo4j/neo4j/issues/1428
4.3. 制約付きの CREATE UNIQUE は、リレーションシップの作成に常に機能するとは限りません。
これは、同じ github issue でも言及されています。
4.4. パフォーマンス:
実際、サイファーでバッチを使用する前に、get_or_create (/db/data/index/node/Post?uniqueness=get_or_create & /db/data/index/relationship/XXXXX?uniqueness=get_or_create) で従来のインデックス作成を試しました。
これらの従来のインデックス エンドポイントの性質 (実際のデータ ストレージ内のデータの場所ではなく、インデックス内のデータの場所を返す) のため、バッチ内でそれらを使用できませんでした (同じバッチで以前に作成されたノードを参照する機能が必要でした) )
auto_indexing を有効にして、レガシー インデックスの代わりにデータ ストレージを直接処理できることはわかっていますが、2.0.0 以降、レガシー インデックスよりもスキーマ インデックスが推奨されているとのことでした。そのため、バッチ + サイファー + スキーマ インデックス アプローチに切り替えることにしました。
ただし、バッチ + サイファーでは、1 秒あたり約 200 のジョブ記述しか取得できません。制約付きの MERGE が常に機能していれば、600 ~ 800/秒としましょう。それでも 5k よりはるかに低いです。 /秒。制約なしでスキーマ インデックスも試してみましたが、挿入率の点でさらにパフォーマンスが低下しました。