4

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 よりはるかに低いです。 /秒。制約なしでスキーマ インデックスも試してみましたが、挿入率の点でさらにパフォーマンスが低下しました。

4

1 に答える 1

5

2.0 では、トランザクション エンドポイントを使用してステートメントをバッチで作成します。たとえば、http リクエストごとに 100 または 1000、トランザクションごとに (コミットするまで) 約 30k-50k です。

新しいストリーミング トランザクション エンドポイントの形式については、次を参照してください。

http://docs.neo4j.org/chunked/milestone/rest-api-transactional.html

また、このような高性能で継続的な挿入エンドポイントのために、埋め込み API に対して実行され、1 秒あたり 10k 以上のノードと関係を簡単に挿入できるサーバー拡張機能を作成することを強くお勧めします。ドキュメントについては、こちらを参照してください。

http://docs.neo4j.org/chunked/milestone/server-unmanaged-extensions.html

純粋な挿入の場合、Cypher は必要ありません。また、同時実行性については、よく知られている (挿入するサブグラフごとに) ノードでロックを取得するだけで、同時挿入が問題にならないようにできます。tx.acquireWriteLock()ノードから存在しないプロパティを使用または削除することで、それを行うことができます ( REMOVE n.__lock__)。

アンマネージ拡張機能 (暗号を使用するもの) を作成する別の例については、このプロジェクトを確認してください。役立つモードもあります (CSV ファイルをサーバー エンドポイントに POST し、行ごとに cypher ステートメントを使用して実行します)。

https://github.com/jexp/cypher-rs

于 2013-11-08T00:46:36.060 に答える