14 グラフ分析を使用したアプリケーションの開発
グラフ・アルゴリズムを実行するために、グラフ・アプリケーションは中間層のグラフ・サーバー(PGX)に接続し、Oracle Databaseに接続します。
ノート:
プロパティ・グラフ・ビューは、グラフ・サーバー(PGX)にのみロードできます。グラフ・サーバー(PGX)へのSQLプロパティ・グラフのロードはサポートされていません。- 頂点IDとエッジIDについて
グラフ・サーバー(PGX)では、グラフ内の頂点およびエッジごとに一意の識別子が存在することをデフォルトで強制されます。 - グラフ・サーバー(PGX)でのグラフ管理
グラフをグラフ・サーバー(PGX)にロードし、グラフの公開、格納、削除などの様々な操作を実行できます。 - Oracle Databaseのグラフとグラフ・サーバーの同期の維持
FlashbackSynchronizer
APIを使用すると、データベースでのグラフに対する変更をメモリー内の対応するPgxGraph
オブジェクトに自動的に適用できるため、両方の同期が保たれます。 - グラフ・サーバー(PGX)での読取りおよび更新用のグラフの最適化
グラフ・サーバー(PGX)には、他の読取りまたは更新のために最適化されたグラフを格納できます。このことは、グラフ・サーバーでグラフ・インスタンスに対して直接更新が行われる場合にのみ関連します。 - 組込みアルゴリズムの実行
グラフ・サーバー(PGX)には、一連の組込みアルゴリズムが含まれており、Java APIとして使用できます。 - カスタムPGXグラフ・アルゴリズムの使用
カスタムPGXグラフ・アルゴリズムを使用すると、Java構文でグラフ・アルゴリズムを記述し、それを自動的にコンパイルして効率的なパラレル実装にできます。 - サブグラフの作成
サブグラフはメモリーにロードしたグラフに基づいて作成できます。フィルタ式を使用するか、2部グラフの左側のセットを指定する頂点(ノード)コレクションに基づく2部サブグラフを作成できます。 - データベースの変更を処理するための自動デルタ・リフレッシュの使用
定期的にグラフを自動的にリフレッシュして(自動リフレッシュ)、Oracle Database内のプロパティ・グラフ表(VT$およびGE$表)に格納されているプロパティ・グラフへの変更とインメモリー・グラフとの同期化を維持できます。 - PGXでのユーザー定義関数(UDF)
ユーザー定義関数(UDF)を使用すると、PGXのユーザーはPGQL問合せまたはカスタム・グラフ・アルゴリズムにカスタム・ロジックを追加して、組込み関数をカスタム要件で補完できます。 - ライブラリとしてのグラフ・サーバー(PGX)の使用
PGXをアプリケーションのライブラリとして使用すると、グラフ・サーバー(PGX)インスタンスはJavaアプリケーションと同じJVMで実行され、すべてのリクエストがリモート・プロシージャ呼出しではなく直接ファンクション・コールに変換されます。
親トピック: グラフ・サーバー(PGX)の使用
14.1 頂点IDとエッジIDについて
グラフ・サーバー(PGX)では、グラフ内の頂点およびエッジごとに一意の識別子が存在することをデフォルトで強制されます。
PgxGraph.getVertex(ID id)
およびPgxGraph.getEdge(ID id)
を使用するか、組込みid()
メソッドを使用するPGQL問合せによって、これらの一意の頂点およびエッジIDを取得できます。
vertex_id_strategy
およびedge_id_strategy
を使用して選択できます。
keys_as_ids
: これは、頂点IDを生成するためのデフォルトの方法です。partitioned_ids
: これは、パーティション化されたグラフの場合にお薦めの方法です。unstable_generated_ids
: これを使用すると、システムによって頂点IDまたはエッジIDが生成されます。no_ids
: この方法を使用すると、頂点IDまたはエッジIDが無効になるため、頂点IDまたはエッジIDを使用してAPIをコールできなくなります。
キーを使用したIDの生成
頂点IDを生成するデフォルトの戦略は、グラフのロード中に指定されたキーを使用することです(keys_as_ids
)。その場合、各頂点はすべてのプロバイダにわたって一意である頂点キーを持つ必要があります。
エッジの場合、デフォルトではエッジ・データにキーは必要なく、エッジIDはPGX (unstable_generated_ids
)によって自動的に生成されます。この自動ID生成は、頂点IDにも適用できます。なお、頂点IDまたはエッジIDの生成は確定的であるとはかぎりません。必要に応じて、エッジ・キーをIDとしてロードすることもできます。
partitioned_ids
方針では、キーは頂点またはエッジ・プロバイダ(データソース)内でのみ一意である必要があります。キーはグローバルに一意である必要はありません。グローバル一意IDは、<provider_name>
(<unique_key_within_provider>
)のように、プロバイダ名とその内部のキーの組合せから導出されます。たとえば、Account(1)
です。
partititioned_ids
方針は、構成フィールドvertex_id_strategy
およびedge_id_strategy
を使用して設定できます。たとえば、
{
"name": "bank_graph_analytics",
"optimized_for": "updates",
"vertex_id_strategy" : "partitioned_ids",
"edge_id_strategy" : "partitioned_ids",
"vertex_providers": [
{
"name": "Accounts",
"format": "rdbms",
"database_table_name": "BANK_ACCOUNTS",
"key_column": "ID",
"key_type": "integer",
"props": [
{
"name": "ID",
"type": "integer"
},
{
"name": "NAME",
"type": "string"
}
],
"loading": {
"create_key_mapping" : true
}
}
],
"edge_providers": [
{
"name": "Transfers",
"format": "rdbms",
"database_table_name": "BANK_TXNS",
"key_column": "ID",
"source_column": "FROM_ACCT_ID",
"destination_column": "TO_ACCT_ID",
"source_vertex_provider": "Accounts",
"destination_vertex_provider": "Accounts",
"props": [
{
"name": "ID",
"type": "integer"
},
{
"name": "AMOUNT",
"type": "double"
}
],
"loading": {
"create_key_mapping" : true
}
}
]
}
ノート:
使用可能なすべてのキー・タイプが、パーティション化されたIDとの組合せでサポートされています。グラフがロードされると、PGXは、プロバイダのどのプロパティがプロバイダのキーに対応するかについての情報を保持します。前述の例では、頂点プロパティID
が頂点キーに対応し、エッジ・プロパティID
もエッジ・キーに対応しています。各プロバイダはこのようなキー・プロパティを最大で1つ持つことができ、そのプロパティは任意の名前を持つことができます。
vertex key property ID cannot be updated
自動増分機能の使用によるパーティション化されたIDの生成
パフォーマンスの最適化によるメリットを得るために、常にcreate_key_mapping
をtrue
に設定することをお薦めします。ただし、エッジに単一列のキーがない場合は、create_key_mapping
をfalse
に設定できます。同様に、頂点プロバイダでもcreate_key_mapping
をfalse
に設定できます。IDは自動増分機能によって生成され、Accounts(1)
、Accounts(2)
、Accounts(3)
のようになります。
パーティション化されたIDを含むPGQL問合せの実行の詳細は、パーティション化されたIDを含むPGQL問合せを参照してください。
親トピック: グラフ分析を使用したアプリケーションの開発
14.2 グラフ・サーバー(PGX)でのグラフ管理
グラフをグラフ・サーバー(PGX)にロードし、グラフの公開、格納、削除などの様々な操作を実行できます。
- Oracle Databaseからグラフ・サーバー(PGX)へのグラフの読込み
グラフ・サーバー(PGX)にログインすると、データベースからグラフ・サーバーにグラフを読み込むことができます。 - グラフ・スナップショットのディスクへの格納
グラフをメモリーに読み込んだ後、グラフに変更(PageRankアルゴリズムの実行や頂点プロパティとしての値の格納など)を加えた場合は、グラフのそのスナップショットをディスクに格納できます。 - グラフの公開
他のセッションで参照できるグラフを公開できます。 - グラフの削除
グラフ・サーバー(PGX)のメモリー使用量を削減するには、セッションで、destroy()
メソッドを呼び出して、getGraph()
を介して作成した未使用のグラフ・オブジェクトを削除する必要があります。
親トピック: グラフ分析を使用したアプリケーションの開発
14.2.1 Oracle Databaseからグラフ・サーバー(PGX)へのグラフの読込み
グラフ・サーバー(PGX)にログインすると、データベースからグラフ・サーバーにグラフを読み込むことができます。
データベース・ユーザーが存在し、データベースのグラフ・データに対する読取りアクセス権を持っている必要があります。
Oracle Databaseからグラフ・サーバー(PGX)にプロパティ・グラフ・ビューをロードする方法はいくつかあります:
readGraphByName
APIの使用 - 詳細は、「readGraphByName APIを使用したPGビューのロード」を参照してください。- PGQL
CREATE PROPERTY GRAPH
文の使用 - 詳細は、「PGQLを使用したプロパティ・グラフの作成」を参照してください。 PgViewSubgraphReader#fromPgView
APIを使用したサブグラフの作成およびロード - 詳細は、「プロパティ・グラフ・ビューからのサブグラフのロード」を参照してください。- JSON形式のPGXグラフ構成ファイルの使用 - 詳細は、「JSON構成ファイルを使用したグラフのロード」を参照してください。
- GraphConfigBuilderクラスを使用したJavaメソッドによるプログラムでのOracle RDBMSグラフ構成の作成 - 詳細は、「グラフ構成オブジェクトの定義によるグラフのロード」を参照してください。
- 同じSCNでのエンティティ・プロバイダの読取り
複数の頂点表またはエッジ表、あるいはその両方で構成されるグラフがある場合は、同じシステム変更番号(SCN)の頂点とエッジをすべて読み取ることができます。 - グラフ・ロードの進捗レポートおよび見積り
大規模なグラフをグラフ・サーバー(PGX)にロードすると、長時間実行される操作になることがあります。ただし、非同期アクションを使用してグラフをロードすると、グラフ・ロード操作の進行状況をモニターできます。 - グラフをメモリーにロードするためのAPI
JSON構成ファイルまたはグラフ構成オブジェクトを使用したグラフのロードに使用されるAPIについて学習します。 - グラフ構成のオプション
グラフ構成のオプションについて学習します。 - データ・ロードのセキュリティのベスト・プラクティス
データベースからグラフをロードするには認証が必要であるため、この種類のデータ・ソースへのアクセスを構成する際は、特定のセキュリティ・ガイドラインに従うことが重要です。 - データ形式のサポート・マトリクス
グラフ・サーバー(PGX)でサポートされている様々なデータ形式について学習します。 - ロード済グラフの不変性
グラフがグラフ・サーバー(PGX)にロードされると、グラフとそのプロパティは自動的に不変としてマークされます。
親トピック: グラフ・サーバー(PGX)でのグラフ管理
14.2.1.1 同じSCNでのエンティティ・プロバイダの読取り
複数の頂点表またはエッジ表、あるいはその両方で構成されるグラフがある場合は、同じシステム変更番号(SCN)の頂点とエッジをすべて読み取ることができます。
これは、一部のエッジが欠落した頂点を参照している可能性があるため、頂点が読み取られたSCNよりも後のSCNでエッジ・プロバイダが読み取られるなどの問題を克服するのに役立ちます。
Oracle Databaseでフラッシュバックが有効になっていない場合でも、データベースからグラフを読み取ることができることに注意してください。複数のデータベースの場合、SCNを使用して、同じデータベースに属するエンティティ・プロバイダのみの一貫性を維持できます。
グラフ構成でas_of
フラグを使用して、エンティティ・プロバイダを読み取るSCNを指定できます。as_of
フラグの有効な値は次のとおりです。
表14-1 グラフ構成の"as_of"キーの有効な値
値 | 説明 |
---|---|
正のlong 値
|
これは解析可能なSCN値です。 |
"<current-scn>" |
現在のSCNは、グラフ・ロードの開始時に決定されます。 |
"<no-scn>" |
これは、グラフのロード時にSCNを無効化するためのものです。 |
null |
これにより、"<current-scn>" の動作がデフォルトになります。
|
グラフ構成ファイルの頂点プロバイダまたはエッジ・プロバイダに対して"as_of"
を省略すると、"as_of": null
と同じ動作になります。
例14-1 同じデータベース内の頂点プロバイダおよびエッジ・プロバイダに"as_of"
を使用したグラフ構成
次の設定例では、3つの頂点プロバイダと1つのエッジ・プロバイダが同じデータベースを指しています。
{
"name": "employee_graph",
"vertex_providers": [
{
"name": "Department",
"as_of": "<current-scn>",
"format": "rdbms",
"database_table_name": "DEPARTMENTS",
"key_column": "DEPARTMENT_ID",
"props": [
{
"name": "DEPARTMENT_NAME",
"type": "string"
}
]
},
{
"name": "Location",
"as_of": "28924323",
"format": "rdbms",
"database_table_name": "LOCATIONS",
"key_column": "LOCATION_ID",
"props": [
{
"name": "CITY",
"type": "string"
}
]
},
{
"name": "Region",
"as_of": "<no-scn>",
"format": "rdbms",
"database_table_name": "REGIONS",
"key_column": "REGION_ID",
"props": [
{
"name": "REGION_NAME",
"type": "string"
}
]
}
],
"edge_providers": [
{
"name": "LocatedAt",
"format": "rdbms",
"database_table_name": "DEPARTMENTS",
"key_column": "DEPARTMENT_ID",
"source_column": "DEPARTMENT_ID",
"destination_column": "LOCATION_ID",
"source_vertex_provider": "Department",
"destination_vertex_provider": "Location"
}
]
}
前述の構成ファイルを使用してemployee_graph
を読み取る場合、グラフはDepartment
およびLocatedAt
エンティティ・プロバイダの同じSCNで読み取られます。これを次の表に示します。
表14-2 "as_of"を使用したシナリオの例
エンティティ・プロバイダ | "as_of" |
SCN値 |
---|---|---|
Department |
"<current-scn>" |
SCNが自動的に決定される |
Location |
"28924323" |
"28924323" をSCNとして使用
|
Region |
"<no-scn>" |
SCNの使用なし |
LocatedAt |
"as_of" フラグが省略
|
SCNが自動的に決定される |
データベースの現在のSCN値は、次のいずれかのオプションを使用して決定されます。
V$DATABASE
ビューの問合せ:SELECT CURRENT_SCN FROM V$DATABASE;
DBMS_FLASHBACK
パッケージの使用:SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER FROM DUAL;
前述の操作のいずれかを実行するために必要な権限がない場合は、次を使用できます。
SELECT TIMESTAMP_TO_SCN(SYSDATE) FROM DUAL;
ただし、このオプションは前述の2つのオプションよりも正確ではありません。
次のようにJSON構成ファイルを使用して、グラフをグラフ・サーバーに読み取ることができます。
opg4j> var g = session.readGraphWithProperties("employee_graph.json")
PgxGraph g = session.readGraphWithProperties("employee_graph.json");
g = session.read_graph_with_properties("employee_graph.json")
14.2.1.2 グラフ・ロードの進捗レポートおよび見積り
大規模なグラフをグラフ・サーバー(PGX)にロードすると、長時間実行される操作になることがあります。ただし、非同期アクションを使用してグラフをロードすると、グラフ・ロード操作の進行状況をモニターできます。
次の表に、次の形式でサポートされる非同期グラフ・ロードAPIを示します。
表14-3 非同期グラフ・ロードAPI
データ形式 | API |
---|---|
PGビュー | session.readGraphByNameAsync() |
PGスキーマ | session.readGraphWithPropertiesAsync() |
CSV | session.readGraphFileAsync() |
これらのサポートされているAPIは、PgxFuture
オブジェクトを戻します。
その後、PgxFuture.getProgress()
メソッドを使用して次の統計を収集できます。
- グラフ・ロード操作の進行状況に関するレポート
- メモリーにロードする必要がある残りの頂点およびエッジの見積り
たとえば、次のコードは、PGビュー・グラフを非同期にロードし、その後FutureProgress
オブジェクトを取得してロードの進行状況をレポートおよび見積るステップを示しています。ただし、グラフ・ロードの見積り(ロードされたエンティティおよびプロバイダの数、エンティティおよびプロバイダの合計数など)は、グラフのロード操作が進行中になるまでしか取得できません。また、グラフ・サーバー(PGX)にロードされるエンティティの10000エントリごとにグラフ・ロードの進行状況がシステムによって内部的に計算します。
opg4j> var graphLoadingFuture = session.readGraphByNameAsync("BANK_GRAPH_VIEW", GraphSource.PG_VIEW)
readGraphFuture ==> oracle.pgx.api.PgxFuture@6106dfb6[Not completed]
opg4j> while (!graphLoadingFuture.isDone()) {
...> var progress = graphLoadingFuture.getProgress();
...> var graphLoadingProgress = progress.asGraphLoadingProgress();
...> if (graphLoadingProgress.isPresent()) {
...> var numLoadedVertices = graphLoadingProgress.get().getNumLoadedVertices();
...> }
...> Thread.sleep(1000);
...> }
opg4j> var graph = graphLoadingFuture.get();
graph ==> PgxGraph[name=BANK_GRAPH_VIEW_3,N=999,E=4993,created=1664289985985]
PgxFuture<PgxGraph> graphLoadingFuture = session.readGraphByNameAsync("BANK_GRAPH_VIEW", GraphSource.PG_VIEW);
while (!graphLoadingFuture.isDone()) {
FutureProgress progress = graphLoadingFuture.getProgress();
Optional < GraphLoadingProgress > graphLoadingProgress = progress.asGraphLoadingProgress();
if (graphLoadingProgress.isPresent()) {
long numLoadedVertices = graphLoadingProgress.get().getNumLoadedVertices();
}
Thread.sleep(1000);
}
PgxGraph graph = graphLoadingFuture.get();
FutureProgress
オブジェクトは、一連の非同期操作で使用しないことをお薦めします。
14.2.1.3 グラフをメモリーにロードするためのAPI
JSON構成ファイルまたはグラフ構成オブジェクトを使用したグラフのロードに使用されるAPIについて学習します。
PgxSession
の次のメソッドを使用して、グラフをグラフ・サーバー(PGX)にロードできます。
PgxGraph readGraphWithProperties(String path)
PgxGraph readGraphWithProperties(String path, String newGraphName)
PgxGraph readGraphWithProperties(GraphConfig config)
PgxGraph readGraphWithProperties(GraphConfig config, String newGraphName)
PgxGraph readGraphWithProperties(GraphConfig config, boolean forceUpdateIfNotFresh)
PgxGraph readGraphWithProperties(GraphConfig config, boolean forceUpdateIfNotFresh, String newGraphName)
PgxGraph readGraphWithProperties(GraphConfig config, long maxAge, TimeUnit maxAgeTimeUnit)
PgxGraph readGraphWithProperties(GraphConfig config, long maxAge, TimeUnit maxAgeTimeUnit, boolean blockIfFull, String newGraphName)
read_graph_with_properties(self, config, max_age=9223372036854775807, max_age_time_unit='days',
block_if_full=False, update_if_not_fresh=True, graph_name=None)
最初の引数(グラフ構成ファイルまたは解析されたconfig
オブジェクトへのpath
)は、読み取られるグラフのメタデータです。メタデータには次の情報が含まれます。
- グラフ・データの場所(ファイルの場所と名前、DBの場所、接続情報など)
- グラフ・データの形式(プレーン・テキスト形式、XMLベースの形式、バイナリ形式など)
- ロードされるプロパティのタイプと名前
forceUpdateIfNotFresh
およびmaxAge
引数を使用して、読み取られるスナップショットの経過時間を微調整できます。指定されたグラフ仕様がすでに別のセッションによってメモリーにロードされている場合、グラフ・サーバー(PGX)は既存のグラフ・スナップショットを返します。そのため、データが頻繁に変更される可能性のあるデータベースから読取りを行う場合は、maxAge
引数が重要になります。forceUpdateIfNotFresh
またはmaxAge
が指定されていない場合、PGXは新しいスナップショットをメモリーに読み込むことよりも、キャッシュされたデータを優先します。
14.2.1.4 グラフ構成のオプション
グラフ構成のオプションについて学習します。
次の表に、すべてのグラフ構成に共通するJSONフィールドを示します。
表14-4 グラフ構成JSONフィールド
フィールド | 型 | 説明 | デフォルト |
---|---|---|---|
name | string | グラフの名前。 | 必須 |
array_compaction_threshold | number | [グラフが更新用に最適化されている場合にのみ関連]デルタログを新規配列に圧縮するタイミングを決定するために使用されるしきい値。エンジンmin_array_compaction_threshold値 より小さい場合は、かわりにmin_array_compaction_threshold が使用されます
|
0.2 |
attributes | object | グラフ・データの読取りおよび書込みに必要な追加属性。 | null |
data_source_id | string |
RDBMSインスタンスへの接続に使用するデータ・ソースID。 | null |
edge_id_strategy | enum[no_ids, keys_as_ids, unstable_generated_ids] | このグラフのエッジに使用するID戦略を示します。指定しない(またはnull に設定されている)場合、戦略は、ロード中に、またはデフォルト値を使用して決定されます。
|
null |
edge_id_type | enum[long] | エッジIDのタイプ。これをlong に設定するには、エッジ・プロバイダのIDがグラフ間で一意である必要があります。これらのIDはグローバルIDとして使用されます。これをnull に設定(または省略)すると、異なるエッジ・プロバイダ間でIDの繰返しが許可され、PGXにより、エッジに対してグローバルに一意のIDが自動的に生成されます。
|
null |
edge_providers | オブジェクトの配列 | このグラフのエッジ・プロバイダのリスト。 | [] |
error_handling | object | エラー処理構成。 | null |
external_stores | オブジェクトの配列 | 外部文字列プロパティが存在する外部ストアの指定。 | [] |
jdbc_url | string | RDBMSインスタンスを指すJDBC URL | null |
keystore_alias | string | データベースへの接続時に使用するキーストアの別名。 | null |
loading | object | 使用するロード固有の構成。 | null |
local_date_format | 文字列の配列 | local_date プロパティのロードおよび格納時に使用するlocal_date 形式の配列。形式の文字列の詳細は、DateTimeFormatterを参照してください
|
[] |
max_prefetched_rows | integer | resultsetデータベースの各ラウンドトリップ中にプリフェッチされた行の最大数。 | 10000 |
num_connections | integer | RDBMS表との間でデータの読取りおよび書込みを行う接続の数。 | <no-of-cpus> |
optimized_for | enum[read, updates] | グラフで、読取り集中型のシナリオや高速更新のために最適化されたデータ構造を使用するかどうかを示します。 | read |
password | string | データベースに接続する際に使用するパスワード。 | null |
point2d | string | 空白で区切られた浮動小数点値としての経度と緯度。 | 0.0 0.0 |
prepared_queries |
オブジェクトの配列 |
引数が指定された準備済問合せの追加リスト。'queries'と同じように機能します。1つ以上の問合せに一致するデータもロードされます。 | [] |
queries |
文字列の配列 |
データベースからロードするデータの決定に使用される問合せのリスト。1つ以上の問合せに一致するデータがロードされます。問合せを設定しないと、グラフ全体がロードされます。 | [] |
redaction_rules | オブジェクトの配列 | リダクション・ルールの配列。 | [] |
rules_mapping | オブジェクトの配列 | ユーザーおよびロールへのリダクション・ルールのマッピング。 | [] |
schema | string | RDBMSオブジェクトの読取りまたは書込みに使用するスキーマ | null |
source_name |
string |
データベース・グラフの名前(グラフがデータベースからロードされる場合)。 | null |
source_type |
enum[pg_view] |
データベース・グラフのソース・タイプ。 | null |
time_format | 文字列の配列 | 時間プロパティのロードおよび格納時に使用するtime 形式。形式の文字列に関するドキュメントは、DateTimeFormatterを参照してください。
|
[] |
time_with_timezone_format | 文字列の配列 | 時間(タイムゾーン付き)プロパティをロードおよび格納する際に使用する時間(タイムゾーン付き) の形式。形式の文字列の詳細は、DateTimeFormatterを参照してください。
|
[] |
timestamp_format | 文字列の配列 | タイムスタンプ・プロパティのロードおよび格納時に使用するタイムスタンプ 形式。形式の文字列の詳細は、DateTimeFormatterを参照してください。
|
[] |
timestamp_with_timezone_format | 文字列の配列 | タイムスタンプ(タイムゾーン付き) プロパティをロードおよび格納する際に使用するタイムスタンプ(タイムゾーン付き) の形式。形式の文字列の詳細は、DateTimeFormatterを参照してください。
|
[] |
username | string | RDBMSインスタンスに接続する際に使用するユーザー名。 | null |
vector_component_delimiter | character | ベクトル・プロパティの様々なコンポーネント用の区切り文字。 | ; |
vertex_id_strategy | enum[no_ids, keys_as_ids, unstable_generated_ids] | このグラフの頂点に使用するID戦略を示します。指定しない(またはnull に設定されている)場合、戦略は自動的に検出されます。
|
null |
vertex_id_type | enum[int, integer, long, string] | vertex IDのタイプ。同種のグラフで指定されていない(またはnull に設定されている)場合、デフォルトで特定の値(データの元によって異なる)に設定されます。
|
null |
vertex_providers | オブジェクトの配列 | このグラフの頂点プロバイダのリスト。 | [] |
ノート:
グラフ構成で指定されたデータベース接続フィールドは、基礎となるデータ・プロバイダ構成でこれらのフィールドを指定しない場合のデフォルトとして使用されます。プロバイダ構成JSONファイルのオプション
プロバイダ構成を使用して、各プロバイダのデータに関するメタ情報を指定できます。プロバイダ構成には、プロバイダ・データに関する次の情報が含まれます。
- データの場所: ファイル、複数ファイルまたはデータベース・プロバイダ
- プロパティに関する情報: プロパティの名前とタイプ
表14-5 プロバイダ構成JSONファイルのオプション
フィールド | 型 | 説明 | デフォルト |
---|---|---|---|
format | enum[pgb, csv, rdbms] | プロバイダ形式。 | 必須 |
name | string | エンティティ・プロバイダ名。 | 必須 |
attributes | object | グラフ・データの読取りおよび書込みに必要な追加属性。 | null |
destination_vertex_provider | string | このエッジ・プロバイダに使用される入力頂点プロバイダの名前。 | null |
error_handling | object | エラー処理構成。 | null |
has_keys | boolean | 指定されたエンティティ・データにキーがあるかどうかを示します。 | true |
key_type | enum[int, integer, long, string] | キーのタイプ。 | long |
keystore_alias | string | データベースへの接続時に使用するキーストアの別名。 | null |
label | string | このプロバイダからロードされたエンティティのラベル。 | null |
loading | object | ロード固有の構成。 | null |
local_date_format | 文字列の配列 | local_dateプロパティのロードおよび格納時に使用するlocal_date形式の配列。形式の文字列に関するドキュメントは、DateTimeFormatterを参照してください。 | [] |
password | string | データベースに接続する際に使用するパスワード。 | null |
point2d | string | 空白で区切られた浮動小数点値としての経度と緯度。 | 0.0 0.0 |
props | オブジェクトの配列 | このエンティティ・プロバイダに関連付けられたプロパティの指定。 | [] |
source_vertex_provider | string | このエッジ・プロバイダに使用される出力頂点プロバイダの名前。 | null |
time_format | 文字列の配列 | 時間プロパティのロードおよび格納時に使用する時間形式。形式の文字列に関するドキュメントは、DateTimeFormatterを参照してください。 | [] |
time_with_timezone_format | 文字列の配列 | 時間(タイムゾーン付き)プロパティをロードおよび格納する際に使用する時間(タイムゾーン付き)の形式。形式の文字列に関するドキュメントは、DateTimeFormatterを参照してください。 | [] |
timestamp_format | 文字列の配列 | タイムスタンプ・プロパティのロードおよび格納時に使用するタイムスタンプ形式。形式の文字列に関するドキュメントは、DateTimeFormatterを参照してください。 | [] |
timestamp_with_timezone_format | 文字列の配列 | タイムスタンプ(タイムゾーン付き)プロパティをロードおよび格納する際に使用するタイムスタンプ(タイムゾーン付き)の形式。形式の文字列に関するドキュメントは、DateTimeFormatterを参照してください。 | [] |
vector_component_delimiter | character | ベクトル・プロパティの様々なコンポーネント用の区切り文字。 | ; |
プロバイダ・ラベル
プロバイダ構成のlabel
フィールドを使用すると、プロバイダからロードされたエンティティのラベルを設定できます。label
が指定されていない場合、プロバイダからのすべてのエンティティに、プロバイダの名前のラベルが付けられます。2つの異なるプロバイダに同じラベルを設定できるのは、プロパティが厳密に同じ(名前とタイプが同じ)場合だけです。
プロパティ構成
プロバイダ
構成のprops
エントリは、次のJSONフィールドを含むオブジェクトです。
表14-6 プロパティ構成
フィールド | 型 | 説明 | デフォルト |
---|---|---|---|
name | string | プロパティの名前を指定します。 | 必須 |
type | enum[boolean, integer, vertex, edge, float, long, double, string, date, local_date, time, timestamp, time_with_timezone, timestamp_with_timezone, point2d] | プロパティのタイプ。
ノート: dateは非推奨です。かわりに、local_date/time/timestamp/time_with_timezone/timestamp_with_timezoneのいずれかを使用します。 |
必須 |
aggregate | enum[identity, group_key, min, max, avg, sum, concat, count] | [現在サポートされていません]どの集計関数を使用しても、常に頂点キーによって集計が行われます。 | null |
column | value | プロパティ・データを保持する列の名前または索引(0から開始)。指定しない場合、ローダーはプロパティ名を列名として使用しようとします(CSV形式のみ)。 | null |
default | value | データ・ソースで指定されていない場合、このプロパティに割り当てられるデフォルト値。date型の場合: 文字列はyyyy-MM-dd HH:mm:ss でフォーマットされます。デフォルトが存在しない場合(null )、存在しないプロパティにはデフォルトのJava型(プリミティブ)または空の文字列(string)または01.01.1970 00:00 (date)が含まれます。
|
null |
dimension | integer | プロパティのディメンション。 | 0 |
drop_after_loading | boolean | [現在サポートされていません]集計にのみ使用されるヘルパー・プロパティを示します。これはロード後に削除されます | false |
field | value | プロパティ・データを保持するJSONフィールドの名前。ネストはドット区切りで示されます。ドットを含むフィールド名を使用できますが、この場合、バックスラッシュを使用してドットをエスケープし、あいまいさを解決する必要があります。厳密に指定されているオブジェクトのみがロードされ、存在しない場合はデフォルト値が使用されます。 | null |
format | 文字列の配列 | プロパティの形式の配列。 | [] |
group_key | string | [現在サポートされていません]プロパティ/キーがグループ化式の一部である場合にのみ使用できます。 | null |
max_distinct_strings_per_pool | integer | [string_pooling_strategyがindexedの場合のみ関連]プーリングを停止するまでのプロパティごとの個別の文字列数。制限に達すると、例外がスローされます。nullに設定すると、グローバルPGX構成からのデフォルト値が使用されます。 | null |
stores | オブジェクトの配列 | このプロパティが存在する場所を示すストレージ識別子のリスト。 | [] |
string_pooling_strategy | enum[indexed, on_heap, none] | 使用する文字列プール戦略を示します。null に設定すると、グローバルPGX構成からのデフォルト値が使用されます。
|
null |
ロード構成
loading
エントリは、次のフィールドを含むJSONオブジェクトです。
表14-7 ロード構成
フィールド | 型 | 説明 | デフォルト |
---|---|---|---|
create_key_mapping | boolean | true の場合、ロード中に、エンティティ・キーと内部IDの間のマッピングが準備されます。
|
true |
filter | string | [現在サポートされていません]フィルタ式 | null |
grouping_by | 文字列の配列 | [現在サポートされていません]アグリゲータに使用されるエッジ・プロパティの配列。頂点の場合、IDのみを使用できます(デフォルト) | [] |
load_labels | boolean | 使用可能な場合にエンティティ・ラベルをロードするかどうか。 | false |
strict_mode | boolean | true に設定すると、ローダーで入力ファイルに関する問題(無効な形式、繰返しキー、欠落フィールド、不一致、その他潜在的なエラーなど)が発生した場合は常に例外がスローされ、ERROR レベルでログに記録されます。false に設定すると、ローダーでロード・フェーズ中のメモリー使用量が削減されますが、入力ファイルが不規則である場合は予期しない動作が発生する可能性があります。
|
true |
エラー処理構成
error_handling
エントリは、次のフィールドを含むJSONオブジェクトです。
表14-8 エラー処理構成
フィールド | 型 | 説明 | デフォルト |
---|---|---|---|
on_missed_prop_key | enum[silent, log_warn, log_warn_once, error] | 欠落しているプロパティ・キーに対するエラー処理。 | log_warn_once |
on_missing_vertex | enum[ignore_edge, ignore_edge_log, ignore_edge_log_once, create_vertex, create_vertex_log, create_vertex_log_once, error] | 頂点データ・ソース内のエッジの欠落した出力頂点または入力頂点に対するエラー処理。 | error |
on_parsing_issue | enum[silent, log_warn, log_warn_once, error] | 不正なデータ解析に対するエラー処理。silent、log_warn またはlog_warn_once に設定すると、ロードの続行が試行されます。解析に関する問題にはリカバリできないものもあり、ロードが終了される場合もあります。
|
error |
on_prop_conversion | enum[silent, log_warn, log_warn_once, error] | プロパティ・タイプが指定されたものとは異なる場合のエラー処理。ただし、強制できます。 | log_warn_once |
on_type_mismatch | enum[silent, log_warn, log_warn_once, error] | プロパティ・タイプが指定されたものとは異なる場合のエラー処理。ただし、強制できません。 | error |
on_vector_length_mismatch | enum[silent, log_warn, log_warn_once, error] | 適切なディメンションのないベクトル・プロパティに対するエラー処理。 | error |
ノート:
on_missing_vertex
エラー処理構成でサポートされる設定は、ignore_edge
のみです。
14.2.1.5 データ・ロードのセキュリティのベスト・プラクティス
データベースからグラフをロードするには認証が必要であるため、この種類のデータ・ソースへのアクセスを構成する際は、特定のセキュリティ・ガイドラインに従うことが重要です。
次のガイドラインをお薦めします:
- データへのアクセスに使用するユーザーまたはロールは、必要なグラフ・データにのみアクセスできる読取り専用アカウントにします。
- たとえば、データベースの場合は、更新できないビューを使用して、グラフ・データを読取り専用としてマークします。
14.2.1.6 データ形式のサポート・マトリクス
グラフ・サーバー(PGX)でサポートされている様々なデータ形式について学習します。
ノート:
この表は形式のPGX実装に関する制限を示し、必ずしも形式自体の制限を示すものではありません。表14-9 データ形式のサポート・マトリクス
形式 | 頂点ID | エッジID | 頂点ラベル | エッジ・ラベル | ベクトル・プロパティ |
---|---|---|---|---|---|
PGB |
int, long, string |
long |
複数 | 単一 | サポートされる(ベクトルのタイプはinteger 、long 、float またはdouble )
|
CSV |
int, long, string |
long |
複数 | 単一 | サポートされる(ベクトルのタイプはinteger 、long 、float またはdouble )
|
ADJ_LIST |
int, long, string |
サポート対象外 | サポート対象外 | サポート対象外 | サポートされる(ベクトルのタイプはinteger 、long 、float またはdouble )
|
EDGE_LIST |
int, long, string |
サポート対象外 | 複数 | 単一 | サポートされる(ベクトルのタイプはinteger 、long 、float またはdouble )
|
GRAPHML |
int, long, string |
サポート対象外 | サポート対象外 | サポート対象外 | サポート対象外 |
14.2.1.7 ロード済グラフの不変性
グラフがグラフ・サーバー(PGX)にロードされると、グラフとそのプロパティは自動的に不変としてマークされます。
ロード済グラフの不変性は、次の設計選択によるものです。
- 通常のグラフ分析はグラフ・インスタンスのスナップショットで行われるため、グラフ・インスタンスの変更は必要ありません。
- 不変性により、PGXは、高速分析用に最適化された内部グラフ表現を使用できます。
- リモート・モードでは、グラフ・インスタンスが複数のクライアント間で共有される可能性があります。
ただし、グラフ・サーバー(PGX)には、分析の目的でグラフ・インスタンスをカスタマイズおよび変更するためのメソッドも用意されています。詳細は、グラフ変更とサブグラフを参照してください。
14.2.2 グラフ・スナップショットのディスクへの格納
グラフをメモリーに読み込んだ後、グラフに変更(PageRankアルゴリズムの実行や頂点プロパティとしての値の格納など)を加えた場合は、グラフのそのスナップショットをディスクに格納できます。
グラフの状態をメモリーに保存する場合は、グラフのスナップショットをバイナリ形式のファイル(PGBファイル)として保存できます。
一般に、グラフ・サーバーを停止する必要がある場合は、グラフで実行されたすべてのグラフ問合せおよび分析APIを格納することをお薦めします。グラフ・サーバー(PGX)を再起動すると、グラフをリロードしてAPIを再実行できます。
ただし、グラフの状態を保存する必要がある場合は、次の例でグラフ・スナップショットをディスクに格納する方法について説明します。
グラフ・スナップショットを格納するための前提条件として、読取りまたは書込みの対象となるファイルが格納されているディレクトリ(グラフ・サーバー上)を指すディレクトリ・オブジェクトを定義して、対応するディレクトリへのアクセスを明示的に認可する必要があります。
CREATE OR REPLACE DIRECTORY pgx_file_location AS '<path_to_dir>';
GRANT READ, WRITE ON directory pgx_file_location to GRAPH_DEVELOPER;
また、次の点にも注意してください。
CREATE DIRECTORY
文のディレクトリは、グラフ・サーバー(PGX)に存在する必要があります。- このディレクトリは、グラフ・サーバー(PGX)によってOSレベルで読取り可能(/書込み可能)である必要があります。
前述のコードでは、ディレクトリに対する権限をGRAPH_DEVELOPER
ロールに付与します。ただし、個々のユーザーに権限を付与することもできます。
GRANT READ, WRITE ON DIRECTORY pgx_file_location TO <graph_user>;
その後、次のコードを実行して、プロパティ・グラフ・ビューをグラフ・サーバー(PGX)にロードし、グラフ・スナップショットをファイルとして保存できます。グラフ内の頂点およびエッジ・プロバイダごとに1つずつ、複数のPGBファイルが生成されることに注意してください。
opg4j> var g = session.readGraphByName("BANK_GRAPH", GraphSource.PG_VIEW)
g ==> PgxGraph[name=BANK_GRAPH_NEW,N=999,E=4993,created=1676021791568]
opg4j> analyst.pagerank(graph)
$8 ==> VertexProperty[name=pagerank,type=double,graph=BANK_GRAPH]
// Now save the state of this graph
opg4j> var storedPgbConfig = graph.store(ProviderFormat.PGB, "<path_to_dir>")
3層デプロイメントでは、ファイルはサーバー側のファイル・システムに書き込まれます。また、書き込むファイルの場所がグラフ・サーバー(PGX)で指定されていることを確認する必要があります。(Autonomous Databaseを使用したOracle Graphの3層デプロイメントで説明されているように、3層デプロイメントでは、PGXサーバー・ファイル・システムにアクセスするには、許可されている場所のリストを指定する必要があります。)
親トピック: グラフ・サーバー(PGX)でのグラフ管理
14.2.3 グラフの公開
他のセッションで参照できるグラフを公開できます。
単一のグラフ・スナップショットの公開
PgxGraph#publish()
メソッドを使用して、グラフの現在選択されているスナップショットを公開できます。公開操作により、グラフ名がセッション非公開のネームスペースからパブリック・ネームスペースに移動します。同じ名前を持つグラフがすでに公開されている場合、publish()
メソッドは失敗し、例外が発生します。スナップショットとともに公開されたグラフと、公開された単一のスナップショットは同じネームスペースを共有します。
表12-6に、グラフの公開に必要な権限を示します。
引数を指定せずにpublish()
メソッドをコールすると、スナップショットは永続プロパティのみとともに公開されます。ただし、特定の一時プロパティを公開する場合は、次のようにpublish()
コール内でそれらをリストする必要があります:
opg4j> var prop1 = graph.createVertexProperty(PropertyType.INTEGER, "prop1")
opg4j> prop1.fill(0)
opg4j> var cost = graph.createEdgeProperty(PropertyType.DOUBLE, "cost")
opg4j> cost.fill(0d)
opg4j> graph.publish(List.of(prop1), List.of(cost))
VertexProperty<Integer, Integer> prop1 = graph.createVertexProperty(PropertyType.INTEGER, "prop1");
prop1.fill(0);
EdgeProperty<Double> cost = graph.createEdgeProperty(PropertyType.DOUBLE, "cost");
cost.fill(0d);
List<VertexProperty<Integer, Integer> vertexProps = Arrays.asList(prop);
List<EdgeProperty<Double>> edgeProps = Arrays.asList(cost);
graph.publish(vertexProps, edgeProps);
prop = graph.create_vertex_property("integer", "prop1")
prop1.fill(0)
cost = graph.create_edge_property("double", "cost")
cost.fill(0d)
vertex_props = [prop]
edge_props = [cost]
graph.publish(vertex_props, edge_props)
スナップショットを含むグラフの公開
グラフのすべてのスナップショットを他のセッションから参照できるようにする場合は、publishWithSnapshots()
メソッドを使用します。グラフがスナップショットとともに公開されると、各スナップショットのGraphMetaData
情報も他のセッションで使用できるようになります。ただし、null
であるグラフ構成は除きます。
publishWithSnapshots()
メソッドをコールすると、全スナップショットの永続プロパティがすべて公開され、他のセッションから参照できるようになります。一時プロパティはセッション非公開であるため、明示的に公開する必要があります。公開されると、すべてのプロパティが読取り専用になります。
単一のグラフ・スナップショットを公開する場合と同様に、publishWithSnapshots()
メソッドにより、グラフ名はセッション非公開のネームスペースからパブリック・ネームスペースに移動します。同じ名前を持つグラフがすでに公開されている場合、publishWithSnapshots()
メソッドは失敗し、例外が発生します。
特定の一時プロパティを公開する場合は、次の例のように、publishWithSnapshots()
コール内でそれらをリストする必要があります。
opg4j> var prop1 = graph.createVertexProperty(PropertyType.INTEGER, "prop1")
opg4j> prop1.fill(0)
opg4j> var cost = graph.createEdgeProperty(PropertyType.DOUBLE, "cost")
opg4j> cost.fill(0d)
opg4j> graph.publishWithSnapshots(List.of(prop1), List.of(cost))
VertexProperty<Integer, Integer> prop1 = graph.createVertexProperty(PropertyType.INTEGER, "prop1");
prop1.fill(0);
EdgeProperty<Double> cost = graph.createEdgeProperty(PropertyType.DOUBLE, "cost");
cost.fill(0d);
List<VertexProperty<Integer, Integer> vertexProps = Arrays.asList(prop);
List<EdgeProperty<Double>> edgeProps = Arrays.asList(cost);
graph.publishWithSnapshots(vertexProps,edgeProps);
VertexProperty<Integer, Integer> prop1 = graph.createVertexProperty(PropertyType.INTEGER, "prop1")
prop1.fill(0)
EdgeProperty<Double> cost = graph.createEdgeProperty(PropertyType.DOUBLE, "cost")
cost.fill(0d)
List<VertexProperty<Integer, Integer> vertexProps = Arrays.asList(prop)
List<EdgeProperty<Double>> edgeProps = Arrays.asList(cost)
graph.publishWithSnapshots(vertexProps,edgeProps)
別のセッションからの公開済グラフの参照
公開済グラフは、PgxSession#getGraph()
メソッドを使用して別のセッションで名前で参照できます。
次の例では、公開済グラフmyGraph
を新しいセッション(session2
)で参照します。
opg4j> var session2 = instance.createSession("session2")
opg4j> var graph2 = session2.getGraph(Namespace.PUBLIC, "myGraph")
PgxSession session2 = instance.createSession("session2");
PgxGraph graph2 = session2.getGraph(Namespace.PUBLIC, "myGraph");
session2 = pypgx.get_session("session2");
PgxGraph graph2 = session2.get_graph("myGraph")
session2
は、公開済スナップショットのみにアクセスできます。グラフがスナップショットなしで公開されている場合、getAvailableSnapshots()
メソッドのコールによって空のキューが返されます。
グラフ・スナップショットが公開されている場合は、getGraph()
へのコールによって使用可能な最新のスナップショットが返されます。session2
では、getAvailableSnapshots()
メソッドを使用して、使用可能なすべてのスナップショットを表示できます。その後、PgxSession#setSnapshot()
メソッドを使用して特定のスナップショットを設定できます。
ノート:
参照したグラフが不要になった場合は、グラフを解放することが重要です。詳細は、グラフの削除を参照してください。プロパティの公開
(単一のスナップショットまたは全スナップショットを)公開した後でも、一時プロパティを個々に公開できます。公開済プロパティは、それらが作成された特定のスナップショットに関連付けられているため、そのスナップショットでのみ参照できます。
opg4j> graph.getVertexProperty("prop1").publish()
opg4j> graph.getEdgeProperty("cost").publish()
graph.getVertexProperty("prop1").publish();
graph.getEdgeProperty("cost").publish();
graph.get_vertex_property("prop1").publish()
graph.get_edge_property("cost").publish()
別のセッションでの公開済プロパティの取得
公開済グラフを(スナップショットの有無に関係なく)参照するセッションは、PgxGraph#getVertexProperty
およびPgxGraph#getEdgeProperty
を介して公開済プロパティを参照できます。
opg4j> var session2 = instance.createSession("session2")
opg4j> var graph2 = session2.getGraph(Namespace.PUBLIC, "myGraph")
opg4j> var vertexProperty = graph2.getVertexProperty("prop1")
opg4j> var edgeProperty = graph2.getEdgeProperty("cost")
PgxSession session2 = instance.createSession("session2");
PgxGraph graph2 = session2.getGraph(Namespace.PUBLIC, "myGraph");
VertexProperty<Integer, Integer> vertexProperty = graph2.getVertexProperty("prop1");
EdgeProperty<Double> edgeProperty = graph2.getEdgeProperty("cost");
session2 = pypgx.get_session(session_name ="session2")
graph2 = session2.get_graph("myGraph")
vertex_property = graph2.get_vertex_property("prop1")
edge_property = graph2.get_edge_property("cost")
公開済グラフの固定
公開済グラフは、セッションで使用されない場合でも公開されたままになるように固定できます。
opg4j> graph.pin()
graph.pin();
>>> graph.pin()
公開済グラフの固定解除
以前に固定された公開済グラフの固定を解除できます。これにより、グラフとそのすべてのスナップショット(他のセッションでグラフのスナップショットを使用していない場合)を削除できます。
opg4j> var graph = session.getGraph("bank_graph_analytics")
graph ==> PgxGraph[name=bank_graph_analytics,N=999,E=4993,created=1660217577201]
opg4j> graph.unpin()
PgxGraph graph = session.getGraph("bank_graph_analytics");
graph.unpin();
>>> graph = session.get_graph("bank_graph_analytics")
>>> graph.unpin()
関連トピック
親トピック: グラフ・サーバー(PGX)でのグラフ管理
14.2.4 グラフの削除
グラフ・サーバー(PGX)のメモリー使用量を削減するには、セッションで、destroy()
メソッドを呼び出して、getGraph()
を介して作成した未使用のグラフ・オブジェクトを削除する必要があります。
destroy()
メソッドをコールすると、指定したグラフだけでなく、関連するすべてのプロパティ(一時プロパティも含む)も破棄されます。また、グラフ・インスタンスに関連するすべてのコレクション(VertexSet
など)も自動的に破棄されます。セッションに同じグラフを参照する複数のPgxGraph
オブジェクトが保持されている場合、それらのいずれかに対してdestroy()
を呼び出すと、そのグラフを参照するすべてのPgxGraph
オブジェクトが無効になり、それらのオブジェクトに対するすべての操作が失敗します。
たとえば:
opg4j> var graph1 = session.getGraph("myGraphName")
opg4j> var graph2 = session.getGraph("myGraphName")
opg4j> graph2.destroy() // Delete graph2
opg4j> var properties = graph1.getVertexProperties() //throws an exception as graph1 reference is not valid anymore
opg4j> properties = graph2.getVertexProperties() //throws an exception as graph2 reference is not valid anymore
PgxGraph graph1 = session.getGraph("myGraphName");
// graph2 references the same graph of graph1
PgxGraph graph2 = session.getGraph("myGraphName");
// Delete graph2
graph2.destroy();
// Both the following calls throw an exception, as both references are not valid anymore
Set<VertexProperty<?, ?>> properties = graph1.getVertexProperties();
properties = graph2.getVertexProperties();
graph1 = session.get_graph("myGraphName")
# graph2 references the same graph of graph1
graph2 = session.get_graph("myGraphName")
# Delete graph2
graph2.destroy()
# Both the following calls throw an exception, as both references are not valid anymore
properties = graph1.get_vertex_properties()
properties = graph2.get_vertex_properties()
同じ動作が発生するのは、複数のPgxGraph
オブジェクトが同じスナップショットを参照している場合です。スナップショットは実質的にグラフであるため、特定のスナップショットを参照するPgxGraph
オブジェクトを破棄すると、同じスナップショットを参照するすべてのPgxGraph
オブジェクトが無効になりますが、他のスナップショットを参照しているオブジェクトは無効になりません。
// Get a snapshot of "myGraphName"
PgxGraph graph1 = session.getGraph("myGraphName");
// graph2 and graph3 reference the same snapshot as graph1
PgxGraph graph2 = session.getGraph("myGraphName");
PgxGraph graph3 = session.getGraph("myGraphName");
// Assume another snapshot is created ...
// Make graph3 references the latest snapshot available
session.setSnapshot(graph3, PgxSession.LATEST_SNAPSHOT);
graph2.destroy();
// Both the following calls throw an exception, as both references are not valid anymore
Set<VertexProperty<?, ?>> properties = graph1.getVertexProperties();
properties = graph2.getVertexProperties();
// graph3 is still valid, so the call succeeds
properties = graph3.getVertexProperties();
ノート:
グラフがセッションによって破棄されても、グラフが他のセッションによって現在共有されている場合、グラフ・データはサーバー・メモリーに引き続き保持されることがあります。このような場合、このグラフは、PgxSession.getGraphs()
メソッドを介して、使用可能なグラフとして引き続き参照できます。
PGX APIでは、各グラフの手動による削除に代わる安全な手段として、開発者がdestroy()
コールを安全に省略できる、いくつかの暗黙的なリソース管理機能がサポートされています。詳細は、リソース管理に関する考慮事項を参照してください。
親トピック: グラフ・サーバー(PGX)でのグラフ管理
14.3 Oracle Databaseのグラフとグラフ・サーバーの同期の維持
FlashbackSynchronizer
APIを使用すると、データベースでのグラフに対する変更をメモリー内の対応するPgxGraph
オブジェクトに自動的に適用できるため、両方の同期が保たれます。
このAPIでは、Oracleのフラッシュバック・テクノロジを使用して最後のフェッチ以降のデータベースでの変更をフェッチし、ChangeSet
APIを使用してそれらの変更をグラフ・サーバーにプッシュします。変更が適用された後、グラフ・サーバーの通常のスナップショット・セマンティクスが適用されます。デルタ・フェッチが適用されるたびに新しいインメモリー・スナップショットが作成されます。スナップショットの作成に対して同時に実行されている問合せまたはアルゴリズムは、対応するセッションがsession.setSnapshot(graph, PgxSession.LATEST_SNAPSHOT)
プロシージャをコールしてPgxGraph
オブジェクトを最新の状態にリフレッシュするまで、変更の影響を受けません。
また、前のフェッチ操作からの変更が存在しなくなった場合、シンクロナイザは例外をスローします。これは、前のフェッチ期間がデータベースのUNDO_RETENTION
パラメータ設定より長い場合に発生します。この例外を回避するには、UNDO_RETENTION
パラメータ値より短い間隔で変更をフェッチします。UNDO_RETENTION
パラメータのデフォルト設定は900
秒です。詳細は、『Oracle Databaseリファレンス』を参照してください。
同期の前提条件
Oracleデータベースでフラッシュバックが有効になっている必要があり、同期の実行に使用するデータベース・ユーザーには次のものが必要です。
- 同期を維持する必要があるすべての表に対する読取りアクセス権。
- フラッシュバックAPIを使用するための権限。たとえば:
GRANT EXECUTE ON DBMS_FLASHBACK TO <user>
また、ユースケースに必要な時間の間変更を保持するようにデータベースを構成する必要もあります。
同期可能なグラフのタイプ
PGXのすべてのPgxGraph
オブジェクトを同期できるわけではありません。次の制限が適用されます。
-
グラフの元の作成者のみがそれを同期できます。つまり、現在のユーザーはグラフのMANAGE権限を持っている必要があります。
- データベース表からロードされたグラフ(PGビュー・グラフ)のみを同期できます。他の形式から作成されたグラフ、グラフ・ビルダーAPIを使用して作成されたグラフまたはデータベース・ビューから作成されたPGビュー・グラフは同期できません。
- グラフの最新のスナップショットのみを同期できます。
同期可能な変更のタイプ
シンクロナイザでは、インメモリー・グラフ・スナップショットと次のデータベース側の変更との同期の維持がサポートされています。
- 新しい頂点とエッジの挿入
- 既存の頂点とエッジの削除
- 任意の頂点またはエッジのプロパティ値の更新
シンクロナイザでは、入力グラフに対する次のようなスキーマ・レベルの変更はサポートされていません。
- 入力頂点表またはエッジ表のリストの変更
- 任意の入力表(頂点表またはエッジ表)の任意の列の変更
さらに、シンクロナイザでは、頂点キーおよびエッジ・キーに対する更新はサポートされていません。
詳細な例は、次のトピックを参照してください。
- PGビュー・グラフの同期
プロパティ・グラフ・ビュー(PGビュー)からグラフ・サーバー(PGX)にロードされたグラフを、データベース内のグラフに加えられた変更と同期できます。 - 公開済グラフの同期
公開済グラフを同期するには、グラフ・スキーマが含まれるPartitionedGraphConfig
オブジェクトとデータベース接続の詳細で、フラッシュバック・シンクロナイザを構成します。
親トピック: グラフ分析を使用したアプリケーションの開発
14.3.1 PGビュー・グラフの同期
プロパティ・グラフ・ビュー(PGビュー)からグラフ・サーバー(PGX)にロードされたグラフを、データベース内のグラフに加えられた変更と同期できます。
14.3.2 公開済グラフの同期
公開済グラフを同期するには、グラフ・スキーマが含まれるPartitionedGraphConfig
オブジェクトとデータベース接続の詳細で、フラッシュバック・シンクロナイザを構成します。
PartitionedGraphConfig
オブジェクトは、PartitionedGraphConfigBuilder
APIを使用するか、JSONファイルからグラフ構成を読み取ることで作成できます。
グラフ構成オブジェクトを使用して作成されたグラフの同期は一般的にサポートされていますが、次のいくつかの制限が適用されます。
- すべてのプロバイダがデータベース表であるパーティション化されたグラフ構成のみがサポートされます。
- 各エッジまたは頂点プロバイダ、あるいはその両方で、ユーザー名フィールドを設定して表の所有者を指定する必要があります。たとえば、ユーザー
SCOTT
が表を所有している場合は、プロバイダのユーザー名を適宜設定します。 - スナップショット・ソースは
CHANGE_SET
に設定する必要があります。 - 多数のスナップショットの作成時にメモリー不足を回避するために、更新操作用にグラフを最適化することをお薦めします。
次の例は、PartitionedGraphConfig
オブジェクトを作成するためのサンプル構成を示しています。
{
...
"optimized_for": "updates",
"vertex_providers": [
...
"username":"<username>",
...
],
"edge_providers": [
...
"username":"<username>",
...
],
"loading": {
"snapshots_source": "change_set"
}
}
GraphConfig cfg = GraphConfigBuilder.forPartitioned()
…
.setUsername("<username>")
.setSnapshotsSource(SnapshotsSource.CHANGE_SET)
.setOptimizedFor(GraphOptimizedFor.UPDATES)
...
.build();
opg4j> var graph = session.readGraphWithProperties("<path_to_json_config_file>")
graph ==> PgxGraph[name=bank_graph_analytics_fb,N=999,E=4993,created=1664310157103]
opg4j> graph.publishWithSnapshots()
PgxGraph graph = session.readGraphWithProperties("<path_to_json_config_file>");
graph.publishWithSnapshots();
>>> graph = session.read_graph_with_properties("<path_to_json_config_file>")
>>> graph.publish_with_snapshots()
これで、次のステップを実行し、JSONファイルから作成されたグラフ構成オブジェクトを使用して公開済グラフを同期できるようになります。
14.4 グラフ・サーバー(PGX)での読取りおよび更新用のグラフの最適化
グラフ・サーバー(PGX)には、他の読取りまたは更新のために最適化されたグラフを格納できます。このことは、グラフ・サーバーでグラフ・インスタンスに対して直接更新が行われる場合にのみ関連します。
読取り用に最適化されたグラフ
読取り用に最適化されたグラフでは、グラフ分析およびPGQL問合せについて最高のパフォーマンスが提供されます。この場合、グラフを更新する(GraphChangeSet
APIを介して頂点およびエッジを追加または削除したり、既存の頂点またはエッジのプロパティ値を更新する)際にはレイテンシが高くなる可能性があります。また、メモリー消費も増加する可能性があります。読取り用に最適化されたグラフを使用する場合、更新された各グラフまたはグラフ・スナップショットは、頂点およびエッジに関してグラフのサイズに比例するメモリーを消費します。
グラフをグラフ・サーバー(PGX)にロードして、読取り用に最適化されたグラフ・インスタンスを作成する場合、optimized_for
構成プロパティをreads
に設定できます。
更新用に最適化されたグラフ
更新用に最適化されたグラフでは、グラフを低レイテンシで更新できる表現が使用されます。この表現を使用すると、数百万の頂点およびエッジがあるグラフを更新するときに、グラフ・サーバーはミリ秒単位のレイテンシに達する可能性があります(これは指標であり、ハードウェア構成によって異なります)。
より高速な更新操作を実現するために、グラフ・サーバーは、以前のグラフ(スナップショット)の完全複製をできるかぎり行わないようにして、新しいグラフ(スナップショット)を作成します。これにより、メモリー消費も改善されます(一般的なシナリオの場合)。新しいスナップショット(または新しいグラフ)は、適用された変更に必要なメモリーに比例する追加メモリーのみを消費します。
この表現では、グラフの問合せおよび分析のパフォーマンスが低下する可能性があります。
グラフをグラフ・サーバー(PGX)にロードして、読取り用に最適化されたグラフ・インスタンスを作成する場合、optimized_for
構成プロパティをupdates
に設定できます。
親トピック: グラフ分析を使用したアプリケーションの開発
14.5 組込みアルゴリズムの実行
グラフ・サーバー(PGX)には、一連の組込みアルゴリズムが含まれており、Java APIとして使用できます。
次の表に、使用可能なアルゴリズムの概要をカテゴリ別に示します。これらのアルゴリズムは、Analystクラスを介して起動できます。
ノート:
詳細は、GitHubのサポートされている組込みアルゴリズムを参照してください。表14-10 組込みアルゴリズムの概要
カテゴリ | アルゴリズム |
---|---|
クラシック・グラフ・アルゴリズム | プリム法 |
コミュニティ検出 | コンダクタンス最小化(SomanおよびNarangアルゴリズム)、Infomap、ラベル伝播、Louvain |
接続されたコンポーネント | 強力に接続されたコンポーネント、弱く接続されたコンポーネント(WCC) |
リンク予測 | Whom To Follow (WTF)アルゴリズム |
行列因数分解 | 行列因数分解 |
その他 | グラフ・トラバース・アルゴリズム |
パス検索 | フィルタされたパス上のすべての頂点およびエッジ、ベルマン–フォード法、双方向ダイクストラ法、距離指標計算、高次頂点計算、ダイクストラ法、列挙単純パス、高速パス検索、最大フロー・パス、フィルタされた高速パス検索、ホップ距離アルゴリズム |
ランキングとウォーキング | 近接中心性アルゴリズム、次数中心性アルゴリズム、固有ベクトル中心性、Hyperlink-Induced Topic Search (HITS)、PageRankアルゴリズム、Random Walk with Restart、Stochastic Approach for Link-Structure Analysis (SALSA)アルゴリズム、頂点媒介中心性アルゴリズム |
構造評価 | Adamic-Adar指標、Bipartite Check、コンダクタンス、循環検出アルゴリズム、次数分布アルゴリズム、離心性アルゴリズム、K-コア、ローカル・クラスタリング係数(LCC)、モジュール性、パーティション・コンダクタンス、到達可能性アルゴリズム、Topological Orderingアルゴリズム、トライアングル・カウンティング・アルゴリズム |
次のトピックでは、例としてトライアングル・カウンティングおよびPageRank分析を使用したグラフ・サーバー(PGX)の使用について説明します。
親トピック: グラフ分析を使用したアプリケーションの開発
14.5.1 グラフ・サーバー(PGX)での組込みアルゴリズムについて
グラフ・サーバー(PGX)には、一連の組込みアルゴリズムが含まれており、Java APIとして使用できます。APIの詳細は、製品のドキュメント・ライブラリに同梱されているJavadocに記載されています。特に、サポートされているインメモリー・アナリスト・メソッドのリストについては、BuiltinAlgorithms
インタフェースのメソッド・サマリーを参照してください。
たとえば、PageRankプロシージャの署名は次のとおりです。
/**
* Classic pagerank algorithm. Time complexity: O(E * K) with E = number of edges, K is a given constant (max
* iterations)
*
* @param graph
* graph
* @param e
* maximum error for terminating the iteration
* @param d
* damping factor
* @param max
* maximum number of iterations
* @return Vertex Property holding the result as a double
*/
public <ID extends Comparable<ID>> VertexProperty<ID, Double> pagerank(PgxGraph graph, double e, double d, int max);
親トピック: 組込みアルゴリズムの実行
14.5.2 トライアングル・カウンティング・アルゴリズムの実行
トライアングル・カウンティングの場合、countTriangles()
のsortByDegree
ブール・パラメータを使用して、グラフを最初に角度でソートする(true
)かソートしない(false
)かを制御できます。true
の場合、さらに多くのメモリーが使用されますが、アルゴリズムの実行は高速になります。ただし、グラフが非常に大きい場合、この最適化をオフにしてメモリー不足を回避することができます。
opg4j> analyst.countTriangles(graph, true)
==> 1
import oracle.pgx.api.*; Analyst analyst = session.createAnalyst(); long triangles = analyst.countTriangles(graph, true);
このアルゴリズムでは、サンプル・グラフ内の1つのトライアングルを検出します。
ヒント:
グラフ・シェルを使用する場合、ロギング・レベルを変更すると、実行中のログ出力の量を増加できます。:h :loglevel
を指定した:loglevel
コマンドの実行に関する情報を参照してください。
親トピック: 組込みアルゴリズムの実行
14.5.3 PageRankアルゴリズムの実行
PageRankは、グラフ内のそれぞれの頂点(ノード)について0
から1
の間のランク値を計算し、その値をdouble
プロパティに格納します。このため、アルゴリズムによって、出力に対してタイプdouble
の頂点プロパティが作成されます。
グラフ・サーバー(PGX)には、頂点プロパティとエッジ・プロパティの2つのタイプがあります。
-
永続プロパティ: データ・ソースからグラフとともにロードされ固定されたディスク上のデータのインメモリー・コピーであるため、永続となるプロパティ。永続プロパティは読取り専用のため変更できず、セッション間で共有されます。
-
一時プロパティ: 値が書き込めるのは一時プロパティのみで、これらはセッションに対してプライベートです。一時プロパティを作成するには、
PgxGraph
オブジェクトでcreateVertexProperty
およびcreateEdgeProperty
をコールするか、プロパティ・オブジェクトでclone()
を使用して既存のプロパティをコピーします。一時プロパティには、アルゴリズムによる計算結果が保持されます。たとえば、PageRankアルゴリズムでは、グラフ内の頂点ごとに0から1の間のランク値を計算し、これらの値を
pg_rank
という一時プロパティに格納します。一時プロパティは、アナリスト・オブジェクトが破棄されると破棄されます。
この例では、PageRank値が最も高い上位3つの頂点を取得します。タイプdouble
の一時頂点プロパティを使用して、計算したPageRank値を保持します。PageRankアルゴリズムでは入力パラメータに次のデフォルト値を使用します。エラー許容値 = 0.001、減衰係数 = 0.85および最大反復数 = 100です。
opg4j> rank = analyst.pagerank(graph, 0.001, 0.85, 100);
==> ...
opg4j> rank.getTopKValues(3)
==> 128=0.1402019732468347
==> 333=0.12002296283541904
==> 99=0.09708583862990475
import java.util.Map.Entry;
import oracle.pgx.api.*;
Analyst analyst = session.createAnalyst();
VertexProperty<Integer, Double> rank = analyst.pagerank(graph, 0.001, 0.85, 100);
for (Entry<Integer, Double> entry : rank.getTopKValues(3)) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
親トピック: 組込みアルゴリズムの実行
14.6 カスタムPGXグラフ・アルゴリズムの使用
カスタムPGXグラフ・アルゴリズムを使用すると、Java構文でグラフ・アルゴリズムを記述し、それを自動的にコンパイルして効率的なパラレル実装にできます。
14.6.1 カスタムPGXアルゴリズムの作成
PGXアルゴリズムは、@GraphAlgorithm
を使用して注釈が付けられる単一のクラス定義を含む通常の.javaファイルです。たとえば:
import oracle.pgx.algorithm.annotations.GraphAlgorithm;
@GraphAlgorithm
public class MyAlgorithm {
...
}
PGXアルゴリズム・クラスには、エントリ・ポイントとして使用されるパブリック・メソッドが1つだけ含まれている必要があります。クラスには任意の数のprivateメソッドを含めることができます。
たとえば:
import oracle.pgx.algorithm.PgxGraph;
import oracle.pgx.algorithm.VertexProperty;
import oracle.pgx.algorithm.annotations.GraphAlgorithm;
import oracle.pgx.algorithm.annotations.Out;
@GraphAlgorithm
public class MyAlgorithm {
public int myAlgorithm(PgxGraph g, @Out VertexProperty<Integer> distance) {
System.out.println("My first PGX Algorithm program!");
return 42;
}
}
通常のJavaメソッドと同様に、PGXアルゴリズム・メソッドは、戻り値としてプリミティブ・データ型のみをサポートします(この例では整数)。さらに興味深いのは、頂点プロパティdistance
を出力パラメータとしてマークする@Out
注釈です。コール元は、出力パラメータを参照渡しします。このようにして、呼出し側は、アルゴリズムの終了後に変更されたプロパティへの参照を持ちます。
親トピック: カスタムPGXグラフ・アルゴリズムの使用
14.6.1.1 コレクション
コレクションを作成するには、.create()関数をコールします。たとえば、VertexProperty<Integer>は次のように作成されます。
VertexProperty<Integer> distance = VertexProperty.create();
特定の頂点v
でプロパティの値を取得するには:
distance.get(v);
同様に、特定の頂点v
のプロパティを値e
に設定するには、次のようにします。
distance.set(v, e);
コレクションのプロパティを作成することもできます。
VertexProperty<VertexSequence> path = VertexProperty.create();
ただし、PGXアルゴリズムの割当ては常に(参照ではなく)値で行われます。これを明示的にするには、コレクションの割当て時に.clone()
をコールする必要があります。
VertexSequence sequence = path.get(v).clone();
値で渡される値のもう1つの結果として、Javaメソッド.equals()
ではなく、==
演算子を使用して等価性をチェックできるようになりました。たとえば:
PgxVertex v1 = G.getRandomVertex();
PgxVertex v2 = G.getRandomVertex();
System.out.println(v1 == v2);
親トピック: カスタムPGXアルゴリズムの作成
14.6.1.2 反復
PGXアルゴリズムの最も一般的な操作は、反復(すべての頂点のループ、頂点の近隣のループなど)およびグラフ・トラバーサル(幅優先/深さ優先など)です。すべてのコレクションが、forEach
メソッドとforSequential
メソッドを公開します。これらのメソッドにより、コレクションはそれぞれ並列、および順に反復処理できます。
たとえば:
- グラフの頂点を並列して反復処理するには:
G.getVertices().forEach(v -> { ... });
- グラフの頂点を順に反復処理するには:
G.getVertices().forSequential(v -> { ... });
- グラフの頂点を
r
から幅優先順にトラバースするには:import oracle.pgx.algorithm.Traversal; Traversal.inBFS(G, r).forward(n -> { ... });
forward
(またはbackward
)ラムダ内部では、currentLevel()
をコールすることによってBFS (またはDFS)トラバーサルの現在のレベルにアクセスできます。
親トピック: カスタムPGXアルゴリズムの作成
14.6.1.3 削減
これらの並列ブロック内では一般に、ラムダ外部に定義された変数をアトミックに更新するか、この変数まで削減します。これらのアトミック型削減は、Scalar<T>: reduceAdd、reduceMul、reduceAnd
などでメソッドとして使用できます。たとえば、グラフ内の頂点の数をカウントするには、次のようにします。
public int countVertices() {
Scalar<Integer> count = Scalar.create(0);
G.getVertices().forEach(n -> {
count.reduceAdd(1);
});
return count.get();
}
複数の値を原子的に更新する必要がある場合があります。たとえば、最小のプロパティ値と、この最小値にプロパティ値が到達した頂点を検出できます。並列実行による2つの別々の削減文のために、状態の一貫性が失われる場合があります。
この問題を解決するために、Reductions
クラスにはargMin
関数とargMax
関数が用意されています。argMin
の最初の引数は現在の値で、2番目の引数は潜在的な新しい最小値です。また、ArgMinMax
オブジェクトに対してandUpdate
コールを連鎖的に実行することにより、他の変数およびこれらの(アトミックな)更新先の値を示すことができます。たとえば:
VertexProperty<Integer> rank = VertexProperty.create();
int minRank = Integer.MAX_VALUE;
PgxVertex minVertex = PgxVertex.NONE;
G.getVertices().forEach(n ->
argMin(minRank, rank.get(n)).andUpdate(minVertex, n)
);
親トピック: カスタムPGXアルゴリズムの作成
14.6.2 カスタムPGXアルゴリズムのコンパイルおよび実行
ノート:
PGXアルゴリズムAPIを使用したカスタムPGXアルゴリズムのコンパイルは、Oracle JDK 17ではサポートされていません。親トピック: カスタムPGXグラフ・アルゴリズムの使用
14.6.3 カスタムPGXアルゴリズムの例: PageRank
PGXアルゴリズムとしてのpagerank
の実装を次に示します。
import oracle.pgx.algorithm.PgxGraph;
import oracle.pgx.algorithm.Scalar;
import oracle.pgx.algorithm.VertexProperty;
import oracle.pgx.algorithm.annotations.GraphAlgorithm;
import oracle.pgx.algorithm.annotations.Out;
@GraphAlgorithm
public class Pagerank {
public void pagerank(PgxGraph G, double tol, double damp, int max_iter, boolean norm, @Out VertexProperty<Double> rank) {
Scalar<Double> diff = Scalar.create();
int cnt = 0;
double N = G.getNumVertices();
rank.setAll(1 / N);
do {
diff.set(0.0);
Scalar<Double> dangling_factor = Scalar.create(0d);
if (norm) {
dangling_factor.set(damp / N * G.getVertices().filter(v -> v.getOutDegree() == 0).sum(rank::get));
}
G.getVertices().forEach(t -> {
double in_sum = t.getInNeighbors().sum(w -> rank.get(w) / w.getOutDegree());
double val = (1 - damp) / N + damp * in_sum + dangling_factor.get();
diff.reduceAdd(Math.abs(val - rank.get(t)));
rank.setDeferred(t, val);
});
cnt++;
} while (diff.get() > tol && cnt < max_iter);
}
}
親トピック: カスタムPGXグラフ・アルゴリズムの使用
14.7 サブグラフの作成
サブグラフはロードしたグラフに基づいて作成できます。フィルタ式を使用するか、2部グラフの左側のセットを指定する頂点(ノード)コレクションに基づく2部サブグラフを作成できます。
ノート:
Graph Server and Clientリリース22.3以降、フィルタ式を使用したサブグラフの作成は非推奨です。プロパティ・グラフ・ビューからサブグラフをロードすることをお薦めします。詳細は、「プロパティ・グラフ・ビューからのサブグラフのロード」を参照してください。メモリーへのグラフの読込みの詳細は、「Oracle Databaseからグラフ・サーバー(PGX)へのグラフの読込み」で、グラフ・サーバー(PGX)にグラフをロードする様々な方法を参照してください。
14.7.1 フィルタ式について
フィルタ式は、頂点ごとかエッジごとに評価される式です。この式により、結果(この場合はサブグラフ)に含まれるために頂点またはエッジが満たす必要がある述語を定義できます。
4つの頂点(ノード)と4つのエッジで構成されるグラフの例を考えてみます。フィルタ式src.prop == 10
と一致するエッジについては、元の頂点のprop
プロパティが10になります。次の図に示すように、2つのエッジがフィルタ式と一致します。
次の図は、フィルタを適用した結果のグラフを示します。
頂点フィルタsrc.prop == 10
は、頂点333および頂点自体に関連付けられたエッジをフィルタで除外します。
親トピック: サブグラフの作成
14.7.2 簡易フィルタを使用したサブグラフの作成
次の例は、「フィルタ式について」で説明したサブグラフの作成を示します。
var subgraph = graph.filter(new VertexFilter("vertex.prop == 10"))
import oracle.pgx.api.*;
import oracle.pgx.api.filter.*;
PgxGraph graph = session.readGraphWithProperties(...);
PgxGraph subgraph = graph.filter(new VertexFilter("vertex.prop == 10"));
親トピック: サブグラフの作成
14.7.3 複合フィルタを使用したサブグラフの作成
この例では、少し複雑なフィルタを使用しています。ここでは、識別子の出力エッジの数(出力src
または入力dst
)を計算するoutDegree
関数を使用します。次のフィルタ式は、cost
プロパティ値が50を超え、outDegree
が1を超える入力頂点(ノード)のエッジと一致します。
dst.outDegree() > 1 && edge.cost > 50
次の図に示すように、サンプル・グラフの1つのエッジがこのフィルタ式と一致します。
次の図は、フィルタを適用した結果のグラフを示します。フィルタは頂点99と1908に対応するエッジを除外するため、その頂点も除外します。
親トピック: サブグラフの作成
14.7.4 頂点集合を使用した2部サブグラフの作成
2部サブグラフは、左側に使用される頂点(ノード)集合を指定して作成できます。2部サブグラフには、左側の頂点集合と右側の頂点集合の間にのみエッジがあります。左側の2つのノード間など、これらの集合内にエッジはありません。グラフ・サーバー(PGX)では、入力および出力エッジがすべて削除されたために分離された頂点は、2部サブグラフの一部ではありません。
次の図に、2部サブグラフを示します。プロパティは示していません。
次の例では、4つの頂点と4つのエッジで構成される単純なグラフから、2部サブグラフを作成します。4つの頂点の頂点ID値は、それぞれ99
、128
、1908
および333
です。頂点間のエッジ方向など、頂点とエッジのプロパティ値の詳細は、「フィルタ式について」の図14-1を参照してください。
最初に頂点コレクションを作成し、その左側に頂点を追加する必要があります。この例では、頂点ID値が333
および99
の頂点が頂点コレクションの左側に追加されます。
シェルを使用した2部サブグラフの作成
opg4j> s = graph.createVertexSet() ==> ... opg4j> s.addAll([graph.getVertex(333), graph.getVertex(99)]) ==> ... opg4j> s.size() ==> 2 opg4j> bGraph = graph.bipartiteSubGraphFromLeftSet(s) ==> PGX Bipartite Graph named sample-sub-graph-4
Javaを使用した2部サブグラフの作成
import oracle.pgx.api.*; VertexSet<Integer> s = graph.createVertexSet(); s.addAll(graph.getVertex(333), graph.getVertex(99)); BipartiteGraph bGraph = graph.bipartiteSubGraphFromLeftSet(s);
サブグラフを作成すると、グラフ・サーバー(PGX)によって、頂点が左側にあるかどうかを示すブール頂点(ノード)プロパティが自動的に作成されます。このプロパティには一意の名前を指定できます。
結果の2部サブグラフは次のようになります。
IDが1908
の頂点は2部サブグラフから除外されます。頂点に繋がっている唯一のエッジは、128
から1908
に伸びています。エッジはサブグラフの2部プロパティに反しているため削除されています。頂点1908
にはその他のエッジがないため、これも削除されています。さらに、IDが128
の頂点からIDが99
の頂点までのエッジは、2部サブグラフに存在しません。これは、エッジは左から右にしか移動できないためです(右から左ではありません)。
親トピック: サブグラフの作成
14.8 データベースの変更を処理するための自動デルタ・リフレッシュの使用
定期的にグラフを自動的にリフレッシュして(自動リフレッシュ)、Oracle Database内のプロパティ・グラフ表(VT$およびGE$表)に格納されているプロパティ・グラフへの変更とインメモリー・グラフとの同期化を維持できます。
リレーショナル表からメモリー内のPGXにグラフを直接ロードする場合、自動リフレッシュ機能はサポートされないことに注意してください。
- 自動リフレッシュ用のグラフ・サーバー(PGX)の構成
- 基本的な自動リフレッシュの構成
- グラフ・サーバー(PGX)またはJavaアプリケーションを使用したグラフの読取り
- グラフの特定のスナップショットのチェックアウト
- 高度な自動リフレッシュ構成
- 自動リフレッシュを使用する場合の特別な考慮事項
親トピック: グラフ分析を使用したアプリケーションの開発
14.8.1 自動リフレッシュ用のグラフ・サーバー(PGX)の構成
自動リフレッシュは多くのスナップショットを作成できるので、メモリー使用率が高くなる可能性があります。デフォルトで、グラフの自動リフレッシュを有効にするオプションは管理者だけが使用できます。
すべてのユーザーにグラフの自動リフレッシュを許可するには、次の行をグラフ・サーバー(PGX)の構成ファイル(/etc/oracle/graph/pgx.conf
にある)に含める必要があります。
{
"allow_user_auto_refresh": true
}
14.8.2 基本的な自動リフレッシュの構成
自動リフレッシュはグラフ構成のロード・セクションで構成されています。このトピックの例では、自動リフレッシュを設定して、毎分、更新があるかどうかをチェックし、ソースが変更されていたら新しいスナップショットを作成します。
次のブロック(JSON形式)により、サンプル・グラフの構成ファイルの自動リフレッシュ機能を有効にします。
{
"format": "pg",
"jdbc_url": "jdbc:oracle:thin:@mydatabaseserver:1521/dbName",
"username": "scott",
"password": "<password>",
"name": "my_graph",
"vertex_props": [{
"name": "prop",
"type": "integer"
}],
"edge_props": [{
"name": "cost",
"type": "double"
}],
"separator": " ",
"loading": {
"auto_refresh": true,
"update_interval_sec": 60
},
}
自動リフレッシュ設定を含んでいる追加のロード・
セクションに注意してください。Java APIを使用して、同じグラフ構成をプログラムで作成することもできます。
GraphConfig config = GraphConfigBuilder.forPropertyGraphRdbms()
.setJdbcUrl("jdbc:oracle:thin:@mydatabaseserver:1521/dbName")
.setUsername("scott")
.setPassword("<password>")
.setName("my_graph")
.addVertexProperty("prop", PropertyType.INTEGER)
.addEdgeProperty("cost", PropertyType.DOUBLE)
.setAutoRefresh(true)
.setUpdateIntervalSec(60)
.build();
14.8.3 グラフ・サーバー(PGX)またはJavaアプリケーションを使用したグラフの読取り
グラフ構成を作成した後、通常のAPIを使用してグラフをグラフ・サーバー(PGX)にロードできます。
opg4j> G = session.readGraphWithProperties("graphs/my-config.pg.json")
グラフをロードすると、バックグラウンド・タスクが自動的に開始され、データ・ソースに更新があるかどうかを定期的にチェックします。
14.8.4 グラフの特定のスナップショットのチェックアウト
データベースには更新があるかどうかの問合せが毎分実行されます。時間間隔の経過後にデータベースのグラフが変更されている場合、グラフはリロードされ、新しいスナップショットがインメモリーで自動的に作成されます。
PgxSession
のgetAvailableSnapshots()
メソッドを使用して、グラフの使用可能なインメモリー・スナップショットを"チェックアウト"(ポインタを別のバージョンに移動)できます。出力の例は次のとおりです。
opg4j> session.getAvailableSnapshots(G)
==> GraphMetaData [getNumVertices()=4, getNumEdges()=4, memoryMb=0, dataSourceVersion=1453315103000, creationRequestTimestamp=1453315122669 (2016-01-20 10:38:42.669), creationTimestamp=1453315122685 (2016-01-20 10:38:42.685), vertexIdType=integer, edgeIdType=long]
==> GraphMetaData [getNumVertices()=5, getNumEdges()=5, memoryMb=3, dataSourceVersion=1452083654000, creationRequestTimestamp=1453314938744 (2016-01-20 10:35:38.744), creationTimestamp=1453314938833 (2016-01-20 10:35:38.833), vertexIdType=integer, edgeIdType=long]
前の出力例には、2つのエントリが含まれ、1つは最初にロードされた4つの頂点と4つのエッジのあるグラフで、もう1つは自動リフレッシュで作成された5つの頂点と5つのエッジのあるグラフです。
グラフの特定のスナップショットをチェックアウトするには、PgxSessionのsetSnapshot()メソッドを使用し、ロードするスナップショットのcreationTimestampを指定します。
たとえば、Gが5つの頂点と5つのエッジのある新しいグラフを指しているが、古いバージョンのグラフを分析したい場合、スナップショットを1453315122685に設定する必要があります。グラフ・シェルで次のようにします。
opg4j> G.getNumVertices()
==> 5
opg4j> G.getNumEdges()
==> 5
opg4j> session.setSnapshot( G, 1453315122685 )
==> null
opg4j> G.getNumVertices()
==> 4
opg4j> G.getNumEdges()
==> 4
PgxSession
のreadGraphAsOf()
メソッドを使用して、グラフの特定のスナップショットを直接ロードすることもできます。これはreadGraphWithProperty()
とその後にsetSnapshot()
を使用してグラフをロードするショートカットです。たとえば:
opg4j> G = session.readGraphAsOf( config, 1453315122685 )
どのスナップショットが現在インメモリーで使用可能なのかがわからない、または気にしていない場合は、最大許容期間を指定することで、どれくらい“古い”スナップショットを許容できるかの時間範囲を指定することもできます。たとえば、スナップショットの最大存続期間を60分に設定するには、次を使用できます。
opg4j> G = session.readGraphWithProperties( config, 60l, TimeUnit.MINUTES )
メモリー内に指定した最大期間よりも若い(新しい)スナップショットが1つ以上ある場合、それらのスナップショットのうち最も若い(新しい)ものが返されます。すべての使用可能なスナップショットが指定した最大期間よりも古い場合、または使用可能なスナップショットがまったくない場合は、新しいスナップショットが自動的に作成されます。
14.8.5 高度な自動リフレッシュ構成
自動リフレッシュ構成の拡張オプションを指定できます。
内部的には、グラフ・サーバー(PGX)は最後のチェック以降の変更をデータベースからフェッチし、差分(変更)を前のスナップショットに適用することで、新しいスナップショットを作成します。2つのタイマーがあります。1つはデータベースから差分をフェッチしてキャッシュするためのもので、もう1つは実際に差分を適用して新しいスナップショットを作成するためのものです。
さらに、キャッシュされる差分の数のしきい値を指定できます。キャッシュされた変更の数がこのしきい値よりも多くなると、新しいスナップショットが自動的に作成されます。キャッシュされた変更の数は、単に頂点の変更の数の合計にエッジの変更の数を足したものです。
2つの理由で、差分は定期的にフェッチされ、グラフ・サーバー(PGX)にキャッシュされます。
-
実際のスナップショットの作成プロセスを高速化するため
-
しばらくするとデータベースが変更を"忘れる"可能性がある場合を把握するため
しきい値と更新タイマーの両方を指定できます。つまり、新しいスナップショットが作成される前に、両方の条件がチェックされます。これらのパラメータのうち少なくとも1つは指定して、差分キャッシュが大きくなりすぎるのを防ぐ必要があります。ソースに変更を問合せる間隔は省略できません。
次のパラメータは、5分ごとにデータ・ソースに新しい差分を問合せる構成を示しています。新しいスナップショットは20分ごとに作成されるか、またはキャッシュされた差分が1000の変更のサイズに到達すると作成されます。
{
"format": "pg",
"jdbc_url": "jdbc:oracle:thin:@mydatabaseserver:1521/dbName",
"username": "scott",
"password": "<your_password>",
"name": "my_graph",
"loading": {
"auto_refresh": true,
"fetch_interval_sec": 300,
"update_interval_sec": 1200,
"update_threshold": 1000,
"create_edge_id_index": true,
"create_edge_id_mapping": true
}
}
14.8.6 自動リフレッシュを使用する場合の特別な考慮事項
このセクションでは、グラフ・サーバー(PGX)でグラフの自動リフレッシュを有効にする場合のいくつかの特別な考慮事項について説明します。
graph.destroy()
をコールしても、自動リフレッシュはすぐには停止しません。グラフが実際にサーバー・メモリーから解放された後にのみ停止します。
このことは、次のすべての条件に該当する場合に発生します。- そのグラフを参照している他のセッションがありません。
- PGXが
release_memory_threshold
を超えるメモリーを消費しています。memory_threshold
はpgx.conf
のオプションであり、デフォルトでは、使用可能なシステム・メモリーの85%に設定されます。 - PGXのガベージ・コレクタが実行されています。
memory_cleanup_interval
はpgx.conf
オプションで、10分に1回にデフォルト設定されます。
- 自動リフレッシュを使用してロードされるようにグラフを構成する場合、自動リフレッシュされたグラフはユーザーにバインドされないため、グラフ構成ファイルから
jdbc url
、username
およびkeystore
パラメータを省略することはできません。それを開始したユーザーから接続設定を取得することはできません。
14.9 PGXでのユーザー定義関数(UDF)
ユーザー定義関数(UDF)を使用すると、PGXのユーザーはPGQL問合せまたはカスタム・グラフ・アルゴリズムにカスタム・ロジックを追加して、組込み関数をカスタム要件で補完できます。
注意:
UDFはPGXサーバーで任意のコードを実行できるようにするため、機密データにアクセスする可能性があります。さらに、いずれのPGXセッションでも、PGXサーバーで有効になっている任意のUDFを呼び出すことができます。UDFを有効にするアプリケーション管理者は、次の点を確認する必要があります。
- すべてのUDFコードが信頼できること。
- UDFが改ざんできない安全な場所に保管されること。
さらに、PGXでは、UDFはステートレスで副次効果がないものとみなされます。
PGXは、次の2種類のUDFをサポートしています。
- Java UDF
- JavaScript UDF
Java UDFの使用方法
次の簡単な例は、PGXサーバーでJava UDFを登録して呼び出す方法を示しています。
- public staticメソッドのあるクラスを作成します。たとえば:
package my.udfs; public class MyUdfs { public static String concat(String a, String b) { return a + b; } }
- クラスをコンパイルしてJARファイルに圧縮します。たとえば:
mkdir ./target javac -d ./target *.java cd target jar cvf MyUdfs.jar *
- JARファイルを
/opt/oracle/graph/pgx/server/lib
にコピーします。 - UDF JSON構成ファイルを作成します。たとえば、
/path/to/my/udfs/dir/my_udfs.json
に次のものが含まれているとします。{ "user_defined_functions": [ { "namespace": "my", "language": "java", "implementation_reference": "my.udfs.MyUdfs", "function_name": "concat", "return_type": "string", "arguments": [ { "name": "a", "type": "string" }, { "name": "b", "type": "string" } ] } ] }
/etc/oracle/graph/pgx.conf
に、UDF構成ファイルが含まれているディレクトリを示します。たとえば:"udf_config_directory": "/path/to/my/udfs/dir/"
- PGXサーバーを再起動します。たとえば:
sudo systemctl restart pgx
- PGQL問合せ内からUDFの起動を試行します。たとえば:
graph.queryPgql("SELECT my.concat(my.concat(n.firstName, ' '), n.lastName) FROM MATCH (n:Person)")
- PGXアルゴリズム内からUDFの起動を試行します。たとえば:
ノート:
使用するUDFごとに、@Udf
注釈で注釈を付ける同じスキーマを持つ抽象メソッドを作成する必要があります。import oracle.pgx.algorithm.annotations.Udf; .... @GraphAlgorithm public class MyAlogrithm { public void bomAlgorithm(PgxGraph g, VertexProperty<String> firstName, VertexProperty<String> lastName, @Out VertexProperty<String> fullName) { ... fullName.set(v, concat(firstName.get(v), lastName.get(v))); ... } @Udf(namespace = "my") abstract String concat(String a, String b); }
JavaScript UDF
JavaScript UDFの要件は次のとおりです。
- JavaScriptソースにはすべての依存関係が含まれている必要があります。
- ソースには有効なエクスポートが少なくとも1つ含まれている必要があります。
- UDF構成ファイルで
language
パラメータをjavascript
に設定する必要があります。
たとえば、次のようなJavaScriptソース・ファイルformat.js
を考えてみます。
//format.js
const fun = function(name, country) {
if (country == null) return name;
else return name + " (" + country + ")";
}
module.exports = {stringFormat: fun};
format.js
からUDFをロードするには、UDF構成ファイルは次のようになります。
{
"namespace": "my",
"function_name": "format",
"language": "javascript",
"source_location": "format.js",
"source_function_name": "stringFormat",
"return_type": "string",
"arguments": [
{
"name": "name",
"type": "string"
},
{
"name": "country",
"type": "string"
}
]
}
ノート:
この場合、UDFの名前と実装方法が異なるため、source_function_name
フィールドにUDFの名前を設定する必要があります。また、source_location
フィールドにソース・コード・ファイルのパスを指定することもできます。
UDF構成ファイル情報
UDF構成ファイルは、user_defined_functions
の配列を含むJSONファイルです。(このようなファイルの例は、前述のJava UDFの使用方法サブセクションの「UDF JSON構成ファイルの作成」のステップを参照してください)。
各ユーザー定義関数は、次の表に示すフィールドをサポートしています。
表14-11 各UDFのフィールド
フィールド | データ型 | 説明 | 必須かどうか |
---|---|---|---|
function_name | string | PGXで識別子として使用される関数の名前 | 必須 |
language | enum[java, javascript] | 関数のソース言語(java またはjavascript )
|
必須 |
return_type | enum[boolean, integer, long, float, double, string] | 関数の戻り型 | 必須 |
arguments | オブジェクトの配列 | 引数の配列。引数ごとに、型、引数名、必須かどうか | [] |
implementation_reference | string | クラスパス上の関数名への参照 | null |
namespace | string | PGXでの関数のネームスペース | null |
source_code | string | インラインで提供される関数のソース・コード | null |
source_function_name | string | ソース言語での関数の名前 | null |
source_location | string | 関数のソース・コードへのローカル・ファイル・パス | null |
構成されたすべてのUDFは、次に示すフィールドの組合せに関して一意である必要があります。
- namespace
- function_name
- arguments
親トピック: グラフ分析を使用したアプリケーションの開発
14.10 ライブラリとしてのグラフ・サーバー(PGX)の使用
PGXをアプリケーションのライブラリとして使用すると、グラフ・サーバー(PGX)インスタンスはJavaアプリケーションと同じJVMで実行され、すべてのリクエストがリモート・プロシージャ呼出しではなく直接ファンクション・コールに変換されます。
この場合、クライアント・アプリケーションと同じマシンにRPM
を使用してグラフ・サーバー(PGX)をインストールする必要があります。グラフ・サーバー・インストールで提供されるシェル実行可能ファイルは、埋込みサーバー・モードでJavaまたはPythonシェルを起動するのに役立ちます。詳細は、Oracle Graph Serverのインストールを参照してください。
これで、次のようにパラメータなしでJavaシェルを起動できるようになります。
cd /opt/oracle/graph
./bin/opg4j
/etc/oracle/graph/pgx.conf
構成ファイルの場所を変更するには、構成ファイルへのパスを後ろに付けて--pgx_conf
コマンドライン・オプションを渡します。
# start local PGX instance with custom config
./bin/opg4j --pgx_conf <path_to_pgx.conf>
次のようにパラメータを指定せずにPythonシェルを起動することもできます。
cd /opt/oracle/graph/
./bin/opg4py
Javaを使用する場合、ローカルPGXインスタンスへの参照を次のように取得できます。
import oracle.pg.rdbms.*; import oracle.pgx.api.*; ... ServerInstance instance = GraphServer.getEmbeddedInstance();
Pythonアプリケーションでは、ローカルPGXインスタンスへの参照を次のように取得できます。
import os os.environ["PGX_CLASSPATH"] = "/opt/oracle/graph/lib/*" import opg4py.graph_server as graph_server ... instance = graph_server.get_embedded_instance()
PGXエンジンの起動
PGXは、グラフ・サーバー(PGX)をライブラリとして使用するときに、PGXエンジンを起動する便利なメカニズムを提供します。つまり、グラフ・サーバー(PGX)は自動的に初期化され、ServerInstance.createSession()
が初めてコールされたときに自動的に起動します。ただし、エンジンがその時点でまだ実行されていないものとします。
この暗黙的な初期化の場合、PGXは、デフォルトの場所にあるPGX構成ファイルを使用して自身を構成します。PGX構成ファイルが見つからない場合、PGXは、グラフ・サーバー(PGX)エンジンの構成パラメータに示されているデフォルトのパラメータ値を使用して自身を構成します。
PGXエンジンの停止
グラフ・サーバー(PGX)をライブラリとして使用する場合、終了時にJVMシャットダウン・フックを介してshutdownEngine()
メソッドが自動的にコールされます。具体的には、アプリケーションのデーモン以外のスレッドがすべて終了すると、シャットダウン・フックが起動されます。
temp
ディレクトリがクリアされないため、kill -9
を使用してPGXアプリケーションを強制的に終了しないことをお薦めします。グラフ・サーバー(PGX)エンジンの構成パラメータのtmp_dir
を参照してください。
親トピック: グラフ分析を使用したアプリケーションの開発