2

追加のプロパティとヘルパーを使用してJPAオブジェクトをカプセル化するAPIを作成しています。APIのコンシューマーに特定のクエリ機能を提供する必要があるため、ユーザーにデータベースへのアクセスを許可しません。

私は次のものを持っています:

Node1(w/ attributes) -- > Edge1(w/ attr.) -- > Node2(w/ attr.)

Node1(w/ attributes) -- > |
Node2(w/ attributes) -- > |  -- > HyperEdge1(w/ attr.)
Node3(w/ attributes) -- > |

ノード/エッジ/ハイパーエッジの例

基本的に、Nodeaは特定のものである可能性がありtype、これにより、使用可能な属性の種類が決まります。したがって、さまざまなタイプと属性に応じて、これらの「パス」を照会できる必要があります。

例:ノードから開始し、パスを見つけますtypeA > typeB & attr1 > typeC

だから私は何か簡単なことをする必要があり、クエリを文字列として、あるいはビルダーパターンスタイルとして書くことができるようにする必要があります。

私がこれまでに持っているのは、ノード/エッジ/ハイパーエッジをトラバースするように設定されたビジターパターンです。これにより、一種のクエリが可能になりますが、新しいタイプのクエリに対して新しいビジターを作成する必要があるため、それほど単純ではありません。

これはこれまでの私の実装です:

    ConditionImpl hasMass = ConditionFactory.createHasMass( 2.5 );
    ConditionImpl noAttributes = ConditionFactory.createNoAttributes();

    List<ConditionImpl> conditions = new ArrayList<ConditionImpl>();
    conditions.add( hasMass );
    conditions.add( noAttributes );

    ConditionVisitor conditionVisitor = new ConditionVisitor( conditions );
    node.accept( conditionVisitor );

    List<Set<Node>> validPaths = conditionVisitor.getValidPaths();

上記のコードは、開始ノードに質量が2.5あり、リンクされたノード(子)に属性がないかどうかをチェックするクエリを実行します。訪問者はaを実行condition.check( Node )し、ブール値を返します。


より単純なグラフのクエリ言語を作成するには、どこから始めればよいですか?注:既存のグラフライブラリを使用するオプションはありません。数十万のノードとエッジがあります。

4

2 に答える 2

1

個人的には、ビジターパターンのアイデアが好きですが、すべてのノードを訪問するのは費用がかかる場合があります。

クエリインターフェイス:ユーザー/他の開発者が使用している場合は、読み取り可能なメソッド名を持つビルダースタイルのインターフェイスを使用します。

    Visitor v = QueryBuilder
                  .selectNodes(ConditionFactory.hasMass(2.5))
                  .withChildren(ConditionFactory.noAttributes())
                  .buildVisitor();
    node.accept(v);
    List<Set<Node>> validPaths = v.getValidPaths();

上で指摘したように、これは多かれ少なかれあなたがすでに持っているものの単なる構文糖衣です(しかし糖衣はすべての違いを生みます)。「グラフ上を移動する」(「訪問したノードが条件を満たしているかどうかを確認する」や「接続されているノードが条件を満たしているかどうかを確認する」など)のコードを、実際に条件を確認する(または条件を満たしている)コードから分離します。また、構築および/または以下の条件でコンポジットを使用します。

    // Select nodes with mass 2.5, follow edges with both conditions fulfilled and check that the children on these edges have no attributes. 
    Visitor v = QueryBuilder
                  .selectNodes(ConditionFactory.hasMass(2.5))
                  .withEdges(ConditionFactory.and(ConditionFactory.freestyle("att1 > 12"), ConditionFactory.freestyle("att2 > 23")) 
                  .withChildren(ConditionFactory.noAttributes())
                  .buildVisitor();

(現在、創造性が欠けているため「フリースタイル」を使用しましたが、その意図は明確である必要があります)奇妙なクエリを作成しないために、これは一般に2つの異なるインターフェイスである可能性があることを示します。

    public interface QueryBuilder {
         QuerySelector selectNodes(Condition c);
         QuerySelector allNodes();
    }

    public interface QuerySelector {
         QuerySelector withEdges(Condition c);
         QuerySelector withChildren(Condition c);
         QuerySelector withHyperChildren(Condition c);
         // ...
         QuerySelector and(QuerySelector... selectors);
         QuerySelector or(QuerySelector... selectors);

         Visitor buildVisitor();
    }       

この種のシンタックスシュガーを使用すると、独自のデータクエリ言語を実装しなくても、ソースコードからクエリを読み取ることができます。QuerySelector実装は、訪問されたノードの周りを「移動」する責任がありますが、実装Condititionは条件が一致するかどうかをチェックします。

このアプローチの明らかな欠点は、インターフェイスでほとんどのクエリを予測し、それらをすでに実装する必要があることです。

ノード数によるスケーラビリティ:「興味深い」ノードの検索を高速化するために、ある種のインデックスを追加する必要がある場合があります。ポップアップ表示されるアイデアの1つは、各ノードが「インデックス付き変数」のさまざまな属性設定の1つをモデル化するレイヤーを(インデックスごとに)グラフに追加することです。通常のエッジは、これらのインデックスノードを元のグラフのノードに接続できます。インデックスのハイパーエッジは、検索するのに小さいネットワークを構築できます。もちろん、attributeValue -> nodeマッピングを使用してインデックスをマップのような構造に格納する退屈な方法はまだあります。とにかく、これはおそらく上記のアイデアよりもはるかにパフォーマンスが高いでしょう。

ある種のインデックスがある場合は、グラフ内のすべてのノードにアクセスする必要がないように、インデックスが訪問者を受け入れることもできることを確認してください。

于 2012-12-13T20:41:47.183 に答える
0

糖衣構文を除いて、すべてのピースがあるようです。

上記のリスト全体を次のように作成する不変のスタイルはどうですか

Visitor v = Visitor.empty
    .hasMass(2.5)
    .edge()
    .node()
    .hasNoAttributes();

このスタイルを使用して、あらゆる種類の線形クエリパターンを作成できます。さらに状態を追加すると、たとえばsetName( "A")と後で.node( "A")を使用してクエリを分岐し、クエリのそのポイントに戻ることもできます。

于 2012-12-13T20:10:15.593 に答える