2016-07-25 8 views
1

遺伝子学のサイトでneo4jと遊んできました。Neo4Jノードトラバーサルサイファー各ノードの句

私は起動ノードを見つけるのが簡単ではないところに遭遇しました。ドキュメントやオンラインの投稿を見てみると、このことを暗示するものは見当たらず、おそらくそれは不可能かもしれません。

私がしたいのは、性別のリストを渡し、そのリストからノードを通過する特定のパスに従って単一ノードを取得することです。家族の文脈で

私は私の母の父の母の母を取得したいです。だから私は自分のIDを持っているので、そこから始めて4つのノードを辿るだろう。

ので、擬似問合せは、私が思った以上に簡単だった

select person (follow childof relationship) 
where starting node is me 
where firstNode.gender == female 
AND secondNode.gender == male 
AND thirdNode.gender == female 
AND fourthNode.gender == female 

答えて

2

一般的なソリューションに焦点を当て:ここ

MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person) 
WHERE me.uuid = {uuid} 
    AND length(p) = size({genders}) 
    AND extract(x in tail(nodes(p)) | x.gender) = {genders} 
RETURN ancestor 

どのようにそれをだ

MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person) 
WHERE me.uuid = {uuid} 
    AND length(p) = size({genders}) 
    AND all(i IN range(0, size({genders}) - 1) 
      WHERE {genders}[i] = extract(x in tail(nodes(p)) | x.gender)[i]) 
RETURN ancestor 

ビル@ InverseFalconの答えに、あなたが実際にクエリを簡素化した、コレクションを比較することができます作品:

  1. は、(任意の祖先
  2. に行く
  3. 一致すべての可変長パスがパスのlengthを制約IDによって開始ノードに一致し、すなわちクエリ
  4. の長さをパラメータ化することができないように先祖の数と同じである関係の数、)、経路における性別
    1. nodes(p)戻り経路内のすべてのノードを抽出し、開始ノード
    2. tail(nodes(p))含めて、今、我々は唯一それがに祖先ノードのリストを変換すなわち
    3. extract()は、すべての祖先ノードの性別を抽出し、祖先を持って、開始ノード、つまり、リストの最初の要素をスキップします性別:
    4. 性別の抽出リストは、パスが一致した場合、我々はしかし、パス

    の終わりであるバウンド祖先を返すことができ、私は考えていない

  • パラメータと比較することができますパフォーマンスは同等のままですが、明示的な解決策よりも速くなります。小さなテストデータ(わずか5ノード)では、一般的なソリューションは26のDBアクセスを行いますが、具体的なソリューションはPROFILEで報告されているように22になります。さらにプロファイリングは、性能を比較するために、より大きなデータベースで必要とされるであろう:

    PROFILE MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person) 
    WHERE me.uuid = {uuid} 
        AND length(p) = size({genders}) 
        AND extract(x in tail(nodes(p)) | x.gender) = {genders} 
    RETURN ancestor 
    

    一般的な解決策は、各生成されたクエリに対し、サイファーエンジンによって再度解析する必要はありません単一のクエリであるという利点を有します解析する必要があります。

  • +0

    今朝これについてもっと考えてみましょう。このクエリはn^2クエリになります。すべての可能な祖先につながるすべての可能なパスを比較します。私が間違っているなら私を訂正してください。一方、私がデータセットをループして、私の答えと同じようにクエリを構築すると、各レベルで関連するデータのみが表示されるため、パフォーマンスが大幅に向上します。それはnに近いでしょう。私はまだNeo4Jには新しいので、私は誤解を招く可能性があります。 –

    +0

    あなたが祖先の世代になると仮定すると、_Σ(i = 1→n、2^i)の異なるパスがありますが、それらの_2^n_についてのみ比較されることを願っています。 Cypherエンジンは 'WHERE'節を並べ替えます)、長さ_n_のパスを構築するには、最初に_n-1_に構築する必要があります。特定のクエリを作成することにより、各世代で利用できる2つの正しいブランチを直接選択することができるため、祖先を遠く離れて行くとより速くなります。 –

    +0

    この問題は、Cypherで再帰を行うことができないという事実に起因しています。そのため、一般的な解決方法は、カスタム作成された方法よりはるかに効率が悪くなります。それはあなたの呼び出しですが、(たとえパラメータ化されていれば)_n_世代までは別のクエリを構築するだけです。 –

    1

    だろう。たぶんもっと良い方法があるので、私は少しこれを開いたままにしておきます。

    クエリは

    MATCH (n1:Person { Id: 'f59c40de-506d-4829-a765-7a3ae94af8d1' }) 
    <-[:CHILDOF]-(n2 { Gender:'0'}) 
    <-[:CHILDOF]-(n3 { Gender:'1'}) 
    <-[:CHILDOF]-(n4 { Gender:'1'}) 
    RETURN n4 
    

    になり、各世代の背面に新しい行を追加します。私は、構文をダブルチェックしていない、

    MATCH (me:Person) 
    WHERE me.ID = ? 
    WITH me 
    MATCH (me)-[r:childof*4]->(ancestor:Person) 
    WITH ancestor, EXTRACT(rel IN r | endNode(rel).gender) AS genders 
    WHERE genders = ? 
    RETURN ancestor 
    

    免責事項:

    +0

    「n1」があなたの場合、あなたの関係は間違った方向に向いているように見えます。通常、あなたはその方向で関係を読んでいます。実際には逆の場合、ここでは "n2 childof n1"となります。 –

    1

    同等のクエリは次のようになります。

    Neo4jでは、通常、開始ノードが最初に見つかっています。通常、IDは一意のプロパティに一致するように変更されます。次に、祖先への数多くの関係をトラバースし、トラバースされた関係のすべてのエンドノードのジェンダー特性を抽出し、ジェンダーを期待される性別のリストと比較します(引数は、所望の順序)。

    このアプローチでは、グラフを歩くのとは対照的に、その度合いのchildof関係ですべての結果をフィルタリングするので、関係の度合いが高いほど(照会する祖先の度合いが高いほど)、呼び出しが遅くなる。

    可変関係の度合いをパラメータ化できるかどうかもわからないので、任意の程度の祖先についてこれが一般化された解決策になるのを防ぐことができます。

    1

    あなたが渡した性別の集合や、特定の解決策を扱うことができる一般的なクエリを希望するかどうかはわかりません。

    これは具体的な解決策です。パスを目的の長さに一致させ、あなた自身の答えですでに述べたように、各性別にマッチさせます。

    MATCH (me:Person)-[:IS_CHILD_OF]->(p1:Person) 
         -[:IS_CHILD_OF]->(p2:Person) 
         -[:IS_CHILD_OF]->(p3:Person) 
         -[:IS_CHILD_OF]->(p4:Person) 
    WHERE me.uuid = {uuid} 
        AND p1.gender = {genders}[0] 
        AND p2.gender = {genders}[1] 
        AND p3.gender = {genders}[2] 
        AND p4.gender = {genders}[3] 
    RETURN p4 
    

    ここで、任意の長さの性別のリストを渡す場合は、実際には可能です。あなたは可変長のパスにマッチし、適切な長さ(性別の数に一致する)を持っていることを確認してから、各ジェンダーを順番にマッチさせます。

    MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person) 
    WHERE me.uuid = {uuid} 
        AND length(p) = size({genders}) 
        AND extract(x in tail(nodes(p)) | x.gender) = {genders} 
    RETURN ancestor 
    
    +0

    最後に提案されたクエリは最もクリーンです。もしあなたがそれが最速であると思うなら、それをそれ自身の答えに引っ張ってください。そして私はそれを正しいとマークします。私は私のデータベースに対してそれをテストし、それは素晴らしい動作します。あなたはキーワードの簡単な説明に投げかけられる新しい答えで?抽出物および尾部およびパイプ。ありがとう –

    関連する問題