10.4 PGQLプロパティ・グラフからのサブグラフのロード

PGQLプロパティ・グラフからサブグラフを作成し、グラフ・サーバー(PGX)のメモリーにロードできます。

グラフ全体をメモリーにロードするかわりに、サブグラフをロードできます。これにより、消費されるメモリーが少なくなります。

次の各項では、サブグラフのロードおよび拡張について詳しく説明します。

10.4.1 PGQLベースのサブグラフのロード

PgViewSubgraphReader#fromPgPgql APIを使用し、一連のPGQL問合せを使用してPGQLプロパティ・グラフからインメモリー・サブグラフを作成できます。

これらのPGQL問合せは、サブグラフにロードされる頂点およびエッジを定義します。複数のPGQL問合せを使用することもでき、結果の出力グラフはサブグラフを結合したものであり、それぞれが各PGQL問合せによって別々にロードされます。

ノート:

  • 非コンポジットの頂点およびエッジ・キーのみがサポートされています。
  • 数値エッジ・キーのみがサポートされています。
  • PGQLプロパティ・グラフからのサブグラフのロードでは、GROUP BY句またはORDER BY句を指定したPGQL問合せはサポートされていません。

次の例では、複数のPGQL問合せを使用してPGQLプロパティ・グラフからサブグラフを作成します。

opg4j> var graph = session.readSubgraph().
...>                    fromPgPgql("FRIENDS").
...>                    queryPgql("MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'").
...>                    queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'").
...>                    load()
graph ==> PgxGraph[name=FRIENDS,N=3,E=1,created=1646726883194]
PgxGraph graph = session.readSubgraph()
                       .fromPgPgql("FRIENDS")
                       .queryPgql("MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'")
                       .queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'")
                       .load();
>>> graph = session.read_subgraph_from_pg_pgql("FRIENDS", ["MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'",
...                           "MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'"])
>>> graph
PgxGraph(name: FRIENDS, v: 3, e: 1, directed: True, memory(Mb): 0)

グラフ・ビジュアライゼーション・ツールを使用した前述のPGQL問合せの出力を次に示します。

図10-1 サブグラフ・ビジュアライゼーション

図10-1の説明が続きます
「図10-1 サブグラフ・ビジュアライゼーション」の説明

カスタム名によるサブグラフのロード

デフォルトでは、新しいサブグラフはPGQLプロパティ・グラフと同じ名前で作成されます。あるいは、カスタム名でサブグラフをロードする場合は、次のようにサブグラフ名を構成できます。

opg4j> var graph = session.readSubgraph().
...>                  fromPgPgql("FRIENDS").
...>                  queryPgql("MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'").
...>                  queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'").
...>                  load("friends_network")
graph ==> PgxGraph[name=friends_network,N=3,E=1,created=1664458398090]
PgxGraph graph = session.readSubgraph()
                       .fromPgPgql("FRIENDS")
                       .queryPgql("MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'")
                       .queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'")
                       .load("friends_network");
>>> graph = session.read_subgraph_from_pg_pgql("FRIENDS",
...                   ["MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'",
...                    "MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'"],
...                   graph_name="friends_network")
>>> graph
PgxGraph(name: friends_network, v: 3, e: 1, directed: True, memory(Mb): 0)

スキーマ名の明示的な指定によるサブグラフのロード

別のスキーマからPGQLプロパティ・グラフを読み取ることでサブグラフをロードする場合は、さらにPgViewSubgraphReader#fromPgPgql APIの引数としてスキーマ名を指定できます。また、PGQLプロパティ・グラフの基礎となるすべてのメタデータおよびデータ表に対するREAD権限を持っていることも確認する必要があります。

たとえば:

opg4j> var graph = session.readSubgraph()
...> .fromPgPgql("GRAPHUSER", "FRIENDS")
...> .queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'")
...> .load()
graph ==> PgxGraph[name=FRIENDS,N=1,E=0,created=1672743755511]
PgxGraph graph = session.readSubgraph()
                       .fromPgPgql("GRAPHUSER", "FRIENDS")
                       .queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'")
                       .load();
>>> graph = session.read_subgraph_from_pg_pgql("FRIENDS",
...  ["MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'"],
...  schema="GRAPHUSER")

10.4.2 準備済PGQL問合せ

PGQLプロパティ・グラフからサブグラフをロードするときに、準備済問合せを使用することもできます。

準備済PGQL問合せを使用してバインド変数を渡すことができます。PreparedPgViewPgqlQuery#preparedPgqlQueryメソッドは、サブグラフをロードするために実行される問合せのリストに準備済問合せを追加します。PreparedPgViewPgqlQuery APIは、変数のバインディングを設定し、サブグラフのロードを続行します。

たとえば:

opg4j> var pgViewSubgraphReader = session.readSubgraph().
...>                                      fromPgPgql("FRIENDS")
pgViewSubgraphReader ==> oracle.pgx.api.subgraph.PgViewSubgraphReader@33bfe6d3
opg4j> var preparedPgqlQuery = pgViewSubgraphReader.preparedPgqlQuery("MATCH (v1:Person)-[e:FriendOf]->(v2:Person) WHERE id(v2)=?")
preparedPgqlQuery ==> oracle.pgx.api.subgraph.PreparedPgViewPgqlQuery@2e6b379c
opg4j> preparedPgqlQuery = preparedPgqlQuery.withStringArg(1, "PERSONS(3)")
preparedPgqlQuery ==> oracle.pgx.api.subgraph.PreparedPgViewPgqlQuery@2e6b379c
opg4j> var graph = preparedPgqlQuery.load()
graph ==> PgxGraph[name=FRIENDS_2,N=3,E=2,created=1648566047855]

import oracle.pgx.api.subgraph.*;
…
…
PgViewSubgraphReader pgViewSubgraphReader= session.readSubgraph().fromPgPgql("FRIENDS");
PreparedPgViewPgqlQuery preparedPgqlQuery = pgViewSubgraphReader.preparedPgqlQuery("MATCH (v1:Person)-[e:FriendOf]->(v2:Person) WHERE id(v2)=?");
preparedPgqlQuery = preparedPgqlQuery.withStringArg(1, "PERSONS(3)"); 
PgxGraph graph = preparedPgqlQuery.load(); 
>>> from pypgx.api import PreparedPgqlQuery
>>> from pypgx.api import PreparedPgqlQueryStringArgument
>>> graph = session.read_subgraph_from_pg_pgql("FRIENDS",
...   [PreparedPgqlQuery("MATCH (v1:Person)-[e:FriendOf]->(v2:Person) WHERE id(v2)=?", [PreparedPgqlQueryStringArgument("PERSONS(3)")])])
>>> graph
PgxGraph(name: FRIENDS, v: 3, e: 2, directed: True, memory(Mb): 0)

10.4.3 データベース接続資格証明の指定

現在のユーザーのデフォルト資格証明を使用するかわりに、PgViewSubgraphReader#fromPgPgql APIを使用してデータベース接続資格証明を指定できます。

次の例は、デフォルト以外のデータベース接続設定のサブグラフのロードを示しています。

opg4j> var graph = session.readSubgraph().
...>                     fromPgPgql("FRIENDS").
...>                     username("graphuser").
...>                     password("<password_for_graphuser>").
...>                     keystoreAlias("database1").
...>                     schema("GRAPHUSER").
...>                     jdbcUrl("jdbc:oracle:thin:@localhost:1521/orclpdb").
...>                     connections(12).
...>                     queryPgql("MATCH (a:Person)").
...>                     load()
graph ==> PgxGraph[name=FRIENDS,N=4,E=0,created=1648541234520] 
PgxGraph graph = session.readSubgraph()
                        .fromPgPgql("FRIENDS")
                        .username("graphuser")
                        .password("<password_for_graphuser>")
                        .keystoreAlias("database1")
                        .schema("GRAPHUSER")
                        .jdbcUrl("jdbc:oracle:thin:@localhost:1521/orclpdb")
                        .connections(12)
                        .queryPgql("MATCH (a:Person)")
                        .load();

10.4.4 サブグラフの動的な拡張

インメモリー・サブグラフを拡張するには、別のサブグラフをメモリーにロードし、現在のインメモリー・サブグラフとマージします。

PgxGraph.expandGraph()メソッドを使用すると、サブグラフを拡張できます。2つのグラフをマージする際、次のことが適用されます。

  • 両方のグラフに別々のプロバイダ・セットを含めることができます。
  • グラフには、他のグラフと同じプロバイダをいくつか含めることができます。この場合、次のようになります:
    • 同じ名前のプロバイダには、同じラベルが必要です。
    • マージ対象のグラフには、ベース・グラフと同じまたは共通のプロパティのサブセットが必要です。ただし、いずれか一方のグラフのプロパティ数が多くなる可能性があります。

次の例に、「PGQLベースのサブグラフのロード」で作成したサブグラフの拡張を示します。

opg4j> graph = graph.expandGraph().
...>          withPgql().
...>          fromPgPgql("FRIENDS").
...>          queryPgql("MATCH (v1:PERSON) -[e:FRIENDOF]-> (v2:PERSON) WHERE id(v1) = 'PERSONS(2)'").
...>          preparedPgqlQuery("MATCH (v:PERSON) WHERE id(v) in ?").withStringArg(1, "PERSONS(4)").
...>          expand()
graph ==> PgxGraph[name=anonymous_graph_152,N=4,E=3,created=1647347092964]
graph = graph.expandGraph()
             .withPgql()
             .fromPgPgql("FRIENDS")
             .queryPgql("MATCH (v1:PERSON) -[e:FRIENDOF]-> (v2:PERSON) WHERE id(v1) = 'PERSONS(2)'")
             .preparedPgqlQuery("MATCH (v:PERSON) WHERE id(v) in ?").withStringArg(1, "PERSONS(4)")
             .expand();
>>> from pypgx.api import PreparedPgqlQuery
>>> from pypgx.api import PreparedPgqlQueryStringArgument
>>> graph = graph.expand_with_pgql(["MATCH (v1:PERSON) -[e:FRIENDOF]-> (v2:PERSON) WHERE id(v1) = 'PERSONS(2)'",
...               PreparedPgqlQuery("MATCH (v:Person) WHERE id(v)=?", [PreparedPgqlQueryStringArgument("PERSONS(4)")])],
...               pg_view_name="FRIENDS")
>>> graph
PgxGraph(name: anonymous_graph_66, v: 4, e: 3, directed: True, memory(Mb): 0)

グラフ・ビジュアライゼーション・ツールを使用した前述のPGQL問合せの出力を次に示します。これで、サブグラフは拡張され、サブグラフにすでに存在していたPERSONS(1)に加えて、PERSONS(2)friendOf関係が含まれるようになります。

図10-2 サブグラフの拡張

図10-2の説明が続きます
「図10-2 サブグラフの拡張」の説明

スキーマ名の明示的な指定によるサブグラフの拡張

グラフを拡張するときに、別のスキーマからPGQLプロパティ・グラフを読み取ることで、別のサブグラフをロードできます。このためには、PgqlViewGraphExpander#fromPgPgql APIの引数としてスキーマ名を指定する必要があります。また、PGQLプロパティ・グラフの基礎となるすべてのメタデータおよびデータ表に対するREAD権限を持っていることも確認する必要があります。

たとえば:

opg4j> graph = graph.expandGraph().
...>           withPgql().
...>           fromPgPgql("GRAPHUSER", "FRIENDS").
...>           queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(1)'").
...>           expand()
graph ==> PgxGraph[name=anonymous_graph_18,N=1,E=0,created=1672848726308]
graph = graph.expandGraph()
             .withPgql()
             .fromPgPgql("GRAPHUSER", "FRIENDS")
             .queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(1)'")
             .expand();
>>> graph = graph.expand_with_pgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(1)'",
...  pg_view_name="FRIENDS", schema="GRAPHUSER")
>>> graph
PgxGraph(name: anonymous_graph_6, v: 2, e: 0, directed: True, memory(Mb): 0)

マージ戦略の使用

グラフの拡張時に、新しいグラフ・データにある頂点およびエッジの一部がすでにベース・グラフにロードされている場合があります。このような場合、頂点およびエッジのプロパティ値が、ベース・グラフとマージ対象となる新しいグラフの両方にあるすべての頂点およびエッジで異なる場合、次のことが適用されます。

  • マージ戦略がKEEP_CURRENT_VALUESの場合、新しいグラフからの頂点およびエッジのプロパティ値は無視されます。
  • マージ戦略がUPDATE_WITH_NEW_VALUESの場合、頂点およびエッジのプロパティ値は新しいグラフで検出された値で更新されます。

たとえば:

opg4j> import oracle.pgx.api.expansion.PropertyMergeStrategy
opg4j> graph = graph.expandGraph().
...>          withPgql().
...>          fromPgPgql("FRIENDS").
...>          queryPgql("MATCH (v1:PERSON) -[e:FRIENDOF]-> (v2:PERSON) WHERE id(v1) = 'PERSONS(2)'").
...>          preparedPgqlQuery("MATCH (v:PERSON) WHERE id(v) in ?").withStringArg(1, "PERSONS(4)").
...>          vertexPropertiesMergingStrategy(PropertyMergeStrategy.UPDATE_WITH_NEW_VALUES).
...>          expand()
import oracle.pgx.api.expansion.PropertyMergeStrategy;
graph = graph.expandGraph()
             .withPgql()
             .fromPgPgql("FRIENDS")
             .queryPgql("MATCH (v1:PERSON) -[e:FRIENDOF]-> (v2:PERSON) WHERE id(v1) = 'PERSONS(2)'")
             .preparedPgqlQuery("MATCH (v:PERSON) WHERE id(v) in ?").withStringArg(1, "PERSONS(4)")
             .vertexPropertiesMergingStrategy(PropertyMergeStrategy.UPDATE_WITH_NEW_VALUES)
             .expand();