2017-11-06 1 views
2

大きなバッチのノード(〜1000〜10000)間のリレーションを作成するための私のcypherクエリは、次のようになります。多数の既存ノードでリレーションの作成を最適化する

"MATCH (startNode1),....,(startNode1000),(endNode1),..(endNode1000) 
    WHERE ID(startNode1) = 538035 AND .. ID(startNode1000) = 538035 AND ID(endNode1) = 577 ..ID(endNode1000) = 586 
    CREATE 
    (startNode1)-[r1:`ParameterValue`{Name: "Phi"}]->(endNode1), 
    (startNode2)-[r2:`ParameterValue`{Type: "block"}]->(endNode2),.. 
    (startNode1000)-[r100:`ParameterValue`{FontAngle: "auto"}]->(endNode1000) 
    RETURN ID(r1), ID(r2), ..... ID(r1000)" 

私はCYPHERクエリを実行するために、公式のJavaのNeo4jボルトのドライバーを使用していますが、平均的に上記CYPHERコマンドは、自分のアプリケーションに適していない程度秒かかります。

私が持っている質問は次のとおりです。

  1. は、私は私の CYPHERクエリをバンドルすることによって、この方法を逃しています任意の明白な最適化はありますか?
  2. 一般に、ノード上に をループさせて、それらをバンドルするよりもリレーションを作成することをお勧めしますか?

私は初心者ですので、どんな提案も大歓迎です。ありがとう!

答えて

3

を行うには正しい方法である私は私のCYPHERクエリをこのように束ねて逃しています任意の明白な最適化はありますか?

はい。問題のクエリは、クエリオプティマイザと実行エンジンの仕事を非常に困難にします。 WebブラウザにアクセスしてEXPLAINというクエリプランを実行すると、このクエリプランにはエンジンが処理するために作られたものではない巨大なタプルが必要であることが示されます。

一般に、ノードをループしてバンドルするよりもリレーションを作成するのがよいでしょうか?

ループオーバーが良い方向です。

  1. UWINDそれをドライバーに単一のパラメータとして[startNode, endNode, relationshipProperties]トリプルのコレクションをパスし、:実際には、あなたが作ることができるいくつかの最適化があります。

  2. SET relationship_variable = map_variableconstructを使用して、関係のプロパティを初期化します。

  3. オプションで、collectメソッドを使用して結果のIDをリストに戻すことができますが、通常はドライバが反復可能な結果を​​返すため、これは必要ありません。

これらのトリックは、このクエリによって組み込まれる:クライアント側で

UNWIND $rels AS rel 
WITH 
    rel[0] AS startNodeId, 
    rel[1] AS endNodeId, 
    rel[2] AS relationshipProperties 
MATCH (startNode:SomeLabel), (endNode:SomeLabel) 
WHERE ID(startNode) = startNodeId 
    AND ID(endNode) = endNodeId 
CREATE (startNode)-[r:`ParameterValue`]->(endNode1) 
SET r = relationshipProperties 
WITH collect(ID(r)) AS relationshipIds 
RETURN relationshipIds 

、あなたはStatementRunner.run(statementTemplate, statementParameters) methodでパラメータを渡す必要があります。単一のキーがrelsのマップと3要素リストのリストです。

Map<String, Object> parameters = 
    ImmutableMap.of("rels", 
    ImmutableList.of(
     ImmutableList.of(1, 2, ImmutableMap.of("prop1", "value1", "prop2", false)), 
     ImmutableList.of(3, 4, ImmutableMap.of(...)), 
    ... 
) 
); 
StatementRunner.run("UNWIND ...", parameters); 

注1.サイファー言語を使用して、パラメータとして、ノードとの関係を渡すことができます:あなたは、グアバのimmutable collectionsは、例えば、優れたコレクションライブラリを使用して簡潔な方法でこれを表現することができます。しかし、これは組み込みバージョンとnot in the client-server setupでしか動作しないので、IDを渡す方がよいでしょう。

注2.内部IDの受け渡しは実用的ではありません。ほとんどのプロトタイプでうまく動作しますが、それらの使用を避け、独自の識別子を提供することを検討することをお勧めします。 Best and Worst Practices with Node IDsを参照してください。

注3.トリプルを使用する代わりに、マップを使用して作成する関係を表すこともできます。このように、あなたはJavaから地図として渡す、つまり、あなたのリストは、マップで構成されます:

ImmutableMap.of("startNode", 1, "endNode", 2, "relationshipProperties", ImmutableMap.of("prop1", "value1", "prop2", true)) 

次にあなたがrel.startNoderel.endNoderel.relationshipPropertiesなどの値を参照することができます。これにより、クエリの読みやすさと保守性が少し向上しますが、通常は面倒なことではありません。

+0

ありがとうございます!これは知っておくべき素晴らしい情報であり、試してみるとパフォーマンスに戻ってきます。 – Kirin

+1

ソリューションを実装した後に更新します。関係の作成時間を15秒から0.2秒に短縮できました。ソリューションと他のポインターについてもありがとうございました。 – Kirin

-3

あなたが実際にこれは我々がユーザーのノードを持っていて、私達はROLEとの関係船を作成し、単なる一例であるCYPHER

MATCH (u:User {username:'admin'}), (r:Role {name:'ROLE_WEB_USER'}) 
CREATE (u)-[:HAS_ROLE]->(r) 

を使用してリレーションシップを作成することができます。

ここにはドキュメントへのリンクがあります。私は上記とは思わないhttps://neo4j.com/docs/developer-manual/current/cypher/clauses/create/#create-create-a-relationship-between-two-nodes

はそれを

関連する問題