3 インメモリー・アナリスト(PGX)の使用
Oracle Spatial and Graphのインメモリー・アナリスト機能は、一連の分析関数をサポートします。
この章では、インメモリー・アナリストを使用する例について説明します(プロパティ・グラフ・インメモリー分析とも呼ばれ、Javadoc、コマンドライン、パスの説明、エラー・メッセージ、例などではPGXと省略されます)。内容は次のとおりです。
- グラフのメモリーへの読込み
このトピックでは、シェル・インタフェースを使用したメモリーへの対話によるグラフの読込みの例について説明します。 - カスタム・グラフ・データの読取り
ユーザー独自のカスタム・グラフ・データを読み取ることができます。 - グラフ・データのディスクへの格納
グラフはJavaまたはシェルを使用してメモリーに読み込んだ後、別の形式でディスクに格納できます。格納したグラフ・データは、後でインメモリー・アナリストへの入力として使用できます。 - 組込みアルゴリズムの実行
インメモリー・アナリストには、一連の組込みアルゴリズムが含まれており、Java APIとして使用できます。 - サブグラフの作成
サブグラフはメモリーにロードしたグラフに基づいて作成できます。フィルタ式を使用するか、2部グラフの左側のセットを指定する頂点(ノード)コレクションに基づく2部サブグラフを作成できます。 - データベースの変更を処理するための自動デルタ・リフレッシュの使用
定期的にグラフを自動的にリフレッシュして(自動リフレッシュ)、インメモリー・グラフの、データベース内の基礎となるプロパティ・グラフへの変更との同期化を維持できます。 - Apache Tomcatへのデプロイ
インメモリー・アナリストは、Apache TomcatまたはOracle WebLogicにデプロイできます。この例では、Webアプリケーションとしてインメモリー分析をApache Tomcatにデプロイする方法を示しています。 - Oracle WebLogic Serverへのデプロイ
インメモリー・アナリストは、Apache TomcatまたはOracle WebLogic Serverにデプロイできます。この例では、Webアプリケーションとしてインメモリー・アナリストをOracle WebLogic Serverにデプロイする方法を示しています。 - インメモリー・アナリスト・サーバーへの接続
プロパティ・グラフのインメモリー・アナリストが、Oracle Databaseが稼働しているコンピュータにインストールされた後、あるいはApache TomcatまたはOracle WebLogic Server上のWebアプリケーションとしてOracle Databaseサーバー・ソフトウェアがインストールされていないクライアント・システムにインストールされた後に、インメモリー・アナリスト・サーバーに接続できます。 - プロパティ・グラフ・スナップショットの管理
Oracle Spatial and Graphプロパティ・グラフにより、プロパティ・グラフ・スナップショットを管理できます。
3.1 グラフのメモリーへの読込み
このトピックでは、シェル・インタフェースを使用したメモリーへの対話によるグラフの読込みの例について説明します。
主な手順は次のとおりです。
3.1.1 インメモリー・アナリスト・サーバー・インスタンスへの接続
インメモリー・アナリスト・シェルを開始する手順:
インメモリー・アナリスト・ソフトウェアが正しくインストールされている場合、エンジンの実行ログ・メッセージと、インメモリー・アナリスト・シェル・プロンプト(pgx>
)が表示されます。
変数instance
、session
、およびanalyst
が使用可能です。
このトピックの前の例では、pgx
コマンドでリモートURLを指定していないため、シェルがローカル・インスタンスを開始します。
3.1.3 構成ファイルでのグラフ・メタデータの指定
このトピックでは、構成ファイルでグラフ・メタデータを指定する例を示します。これらの手順に従い、ディレクトリといくつかのファイルの例を作成します。
-
作成するファイルの例を保持するディレクトリを作成します。次に例を示します。
mkdir -p ${ORACLE_HOME}/md/property_graph/examples/pgx/graphs/
-
このディレクトリで、
sample.adj.json
という名前で、グラフ構成ファイル用の次のコンテンツを含むテキスト・ファイルを作成します。この構成ファイルで、インメモリー・アナリストのグラフの読取り方法について説明します。{ "uri": "sample.adj", "format": "adj_list", "node_props": [{ "name": "prop", "type": "integer" }], "edge_props": [{ "name": "cost", "type": "double" }], "separator": " " }
-
同じディレクトリで、
sample.adj
という名前で、グラフ・データ用の次のコンテンツを含むテキスト・ファイルを作成します。128 10 1908 27.03 99 8.51 99 2 333 338.0 1908 889 333 6 128 51.09
構成ファイルで、uri
フィールドにはグラフ・データの場所を指定します。このパスは構成ファイルの親ディレクトリに対して相対的に解決します。インメモリー・アナリストがグラフをロードするとき、グラフ・データを含むsample.adj
という名前のファイルを検索します。
構成ファイルのその他のフィールドは、グラフ・データが隣接するリスト形式で提供され、integer
型のノード・プロパティとdouble
型のエッジ・プロパティで構成されていることを示します。
次の図に、データから作成されたプロパティ・グラフを示します。
3.1.4 グラフ・データのメモリーへの読込み
グラフをメモリーに読み込むには、次の情報を渡す必要があります。
-
グラフのメタデータを指定するグラフ構成ファイルへのパス
-
グラフの参照に使用できる一意の英数字からなる名前
同じ名前で別のグラフをすでにロードしている場合は、エラーが発生します。
例: シェルを使用したグラフの読取り
pgx> graph = session.readGraphWithProperties("<ORACLE_HOME>/md/property_graph/examples/pgx/graphs/sample.adj.json", "sample"); ==> PGX Graph named sample bound to PGX session pgxShell ... pgx> graph.getNumVertices() ==> 4
例: Javaを使用したグラフの読取り
import oracle.pgx.api.*; PgxGraph graph = session.readGraphWithProperties("<ORACLE_HOME>/md/property_graph/examples/pgx/graphs/sample.adj.json");
次のトピックでは、プロパティ・グラフをメモリーに読み込むその他の例について説明します。
3.1.4.1 Oracleデータベースに格納されているグラフのメモリーへの読込み
Oracleデータベースに格納されているプロパティ・グラフを読み取るには、次のようにJSONベースの構成ファイルを作成できます。ホスト、ストア名、グラフ名、およびその他の情報は、ユーザーの設定に応じてカスタマイズする必要があります。
% cat /tmp/my_graph_oracle.json {"loading":{"load_edge_label":false}, "vertex_props":[ {"default":"default_name","name":"name","type":"string"} ], "password":"<YOUR_PASSWORD>", "db_engine":"RDBMS", "max_num_connections":8, "username":"scott", "error_handling":{},"format":"pg","jdbc_url":"jdbc:oracle:thin:@127.0.0.1:1521:<SID>", "name":"connections", "edge_props":[ {"default":"1000000","name":"cost","type":"double"} ] }
次に、構成ファイルをメモリーに読み込みます。次の例では、スニペットがファイルをメモリーに読み込み、方向のないグラフ(U
という名前)を元のデータから生成し、トライアングルの数をカウントします。
pgx> g = session.readGraphWithProperties("/tmp/my_graph_oracle.json", "connections") pgx> analyst.countTriangles(g, false) ==> 8
3.1.4.2 ローカル・ファイル・システムに格納されているグラフのメモリーへの読込み
次のコマンドでは、「構成ファイルでのグラフ・メタデータの指定」の構成ファイルおよびmy-graph
という名前を使用します。
pgx> g = session.readGraphWithProperties<ORACLE_HOME>/md/property_graph/examples/pgx/graphs/sample.adj.json", "my-graph")
3.2 カスタム・グラフ・データの読取り
ユーザー独自のカスタム・グラフ・データを読み取ることができます。
この例では、グラフを作成し、それを変更して正しく読み取る方法を示します。このグラフでは隣接するリスト形式を使用しますが、インメモリー・アナリストでは、複数のグラフ形式をサポートしています。
主な手順は次のとおりです。
3.2.1 単純なグラフ・ファイルの作成
この例では、頂点またはエッジ・プロパティのない、単純な小さいグラフを隣接するリストに作成します。各行には頂点(ノード) IDが含まれ、そのエッジ点を出力する頂点IDが続きます。
1 2 2 3 4 3 4 4 2
このリストでは各トークンは半角スペースで区切られます。インメモリー・アナリストでは、その他の区切り文字もサポートしており、グラフ構成ファイルで指定できます。
次の図に、4つの頂点と5つのエッジのあるプロパティ・グラフとしてレンダリングされたデータを示します。(頂点2と頂点4の間に2つのエッジがあり、それぞれ他方と逆の方向を指しています)
インメモリー・アナリストへのグラフの読込みにはグラフ構成が必要です。グラフ構成は、次のいずれかのメソッドを使用して指定できます。
-
JSON形式での構成設定のファイルへの書込み
-
Java
GraphConfigBuilder
オブジェクトの使用。
次の例では、両方のメソッドを示します。
JSON構成
{ "uri": "graph.adj", "format":"adj_list", "separator":" " }
Java構成
import oracle.pgx.config.FileGraphConfig; import oracle.pgx.config.Format; import oracle.pgx.config.GraphConfigBuilder; FileGraphConfig config = GraphConfigBuilder .forFileFormat(Format.ADJ_LIST) .setUri("graph.adj") .setSeparator(" ") .build();
3.2.2 頂点プロパティの追加
「単純なグラフ・ファイルの作成」のグラフは、頂点プロパティまたはエッジ・プロパティを使用しない頂点およびエッジで構成されています。頂点プロパティは各行の出力頂点IDの直後に配置されます。値が0.1、2.0、0.3、および4.56789のdouble
頂点(ノード)プロパティがグラフに追加されると、グラフ・データは次のようになります。
1 0.1 2 2 2.0 3 4 3 0.3 4 4 4.56789 2
注意:
インメモリー・アナリストは同種のグラフのみをサポートしており、すべての頂点のプロパティの数とタイプは同じです。
インメモリー・アナリストで、変更したデータ・ファイルを読み取るには、構成ファイルまたはビルダー・コードで頂点(ノード)プロパティを追加する必要があります。次の例では、プロパティを説明する名前を入力し、タイプをdouble
に設定します。
JSON構成
{ "uri": "graph.adj", "format":"adj_list", "separator":" ", "node_props":[{ "name":"double-prop", "type":"double" }] }
Java構成
import oracle.pgx.common.types.PropertyType; import oracle.pgx.config.FileGraphConfig; import oracle.pgx.config.Format; import oracle.pgx.config.GraphConfigBuilder; FileGraphConfig config = GraphConfigBuilder.forFileFormat(Format.ADJ_LIST) .setUri("graph.adj") .setSeparator(" ") .addNodeProperty("double-prop", PropertyType.DOUBLE) .build();
3.2.3 頂点識別子としての文字列の使用
前の例では、integer
頂点(ノード) IDを使用しています。インメモリー分析のデフォルトはinteger
頂点IDですが、string
頂点IDを使用するようにグラフを定義することもできます。
このデータ・ファイルには桁数だけではなく、"node 1"、"node 2"などを使用できます。
"node 1" 0.1 "node 2" "node 2" 2.0 "node 3" "node 4" "node 3" 0.3 "node 4" "node 4" 4.56789 "node 2"
ここでも、データ・ファイルと一致するようにグラフ構成を変更する必要があります。
JSON構成
{ "uri": "graph.adj", "format":"adj_list", "separator":" ", "node_props":[{ "name":"double-prop", "type":"double" }], "node_id_type":"string" }
Java構成
import oracle.pgx.common.types.IdType; import oracle.pgx.common.types.PropertyType; import oracle.pgx.config.FileGraphConfig; import oracle.pgx.config.Format; import oracle.pgx.config.GraphConfigBuilder; FileGraphConfig config = GraphConfigBuilder.forFileFormat(Format.ADJ_LIST) .setUri("graph.adj") .setSeparator(" ") .addNodeProperty("double-prop", PropertyType.DOUBLE) .setNodeIdType(IdType.STRING) .build();
注意:
string
頂点IDは、integer
頂点IDより多くのメモリーを消費します。
文字列内の一重引用符または二重引用符は、バックスラッシュ(\)でエスケープする必要があります。
文字列内の改行(\n)はサポートされていません。
3.2.4 エッジ・プロパティの追加
この例では、タイプstring
のエッジ・プロパティをグラフに追加します。エッジ・プロパティは入力頂点(ノード)IDの後ろに配置されます。
"node1" 0.1 "node2" "edge_prop_1_2" "node2" 2.0 "node3" "edge_prop_2_3" "node4" "edge_prop_2_4" "node3" 0.3 "node4" "edge_prop_3_4" "node4" 4.56789 "node2" "edge_prop_4_2"
グラフ構成は、データ・ファイルと一致している必要があります。
JSON構成
{ "uri": "graph.adj", "format":"adj_list", "separator":" ", "node_props":[{ "name":"double-prop", "type":"double" }], "node_id_type":"string", "edge_props":[{ "name":"edge-prop", "type":"string" }] }
Java構成
import oracle.pgx.common.types.IdType; import oracle.pgx.common.types.PropertyType; import oracle.pgx.config.FileGraphConfig; import oracle.pgx.config.Format; import oracle.pgx.config.GraphConfigBuilder; FileGraphConfig config = GraphConfigBuilder.forFileFormat(Format.ADJ_LIST) .setUri("graph.adj") .setSeparator(" ") .addNodeProperty("double-prop", PropertyType.DOUBLE) .setNodeIdType(IdType.STRING) .addEdgeProperty("edge-prop", PropertyType.STRING) .build();
3.3 グラフ・データのディスクへの格納
グラフはJavaまたはシェルを使用してメモリーに読み込んだ後、別の形式でディスクに格納できます。格納したグラフ・データは、後でインメモリー・アナリストへの入力として使用できます。
HTTP/RESTへのグラフの格納は現在サポートされていません。
オプションは、次のとおりです。
3.3.1 頂点プロパティへの分析結果の格納
この例では、グラフをメモリーに読み込み、Pagerankアルゴリズムを使用して分析します。この分析では、Pagerank値を格納する新しい頂点プロパティが作成されます。
シェルを使用したPageRankの実行
pgx> g = session.readGraphWithProperties("<ORACLE_HOME>/md/property_graph/examples/pgx/graphs/sample.adj.json", "my-graph") ==> ... pgx> rank = analyst.pagerank(g, 0.001, 0.85, 100)
Javaを使用したPageRankの実行
PgxGraph g = session.readGraphWithProperties("<ORACLE_HOME>/md /property_graph/examples/pgx/graphs/sample.adj.json", "my-graph"); VertexProperty<Integer, Double> rank = session.createAnalyst().pagerank(g, 0.001, 0.85, 100);
3.3.2 エッジリスト形式でのグラフのディスクへの格納
この例では、グラフ、Pagerank分析の結果、元のエッジ・プロパティすべてをエッジリスト形式のファイルとしてディスクに格納します。
グラフを格納するには、次を指定する必要があります。
-
グラフの形式
-
ファイルが格納されるパス
-
格納されるプロパティ。VertexProperty.
ALL
またはEdgeProperty.ALL
を指定するとすべてのプロパティが格納され、VertexProperty.NONE
またはEdgePropery.NONE
を指定すると、どのプロパティも格納されません。個々のプロパティを指定するには、格納するVertexPropertyまたはEdgePropertyオブジェクトを渡します。 -
既存のファイルを同じ名前で上書きするかどうかを示すフラグ
次の例では、/tmp/sample_pagerank.elist.json
構成ファイルでグラフ・データを/tmp/sample_pagerank.elist
に格納します。戻り値はファイルに格納されているグラフ構成です。これは再度、グラフの読取りに使用できます。
シェルを使用したグラフの格納
pgx> config = g.store(Format.EDGE_LIST, "/tmp/sample_pagerank.elist", [rank], EdgeProperty.ALL, false) ==> {"uri":"/tmp/sample_pagerank.elist","edge_props":[{"type":"double","name":"cost"}],"vertex_id_type":"integer","loading":{},"format":"edge_list","attributes":{},"vertex_props":[{"type":"double","name":"pagerank"}],"error_handling":{}}
Javaを使用したグラフの格納
import oracle.pgx.api.*; import oracle.pgx.config.*; FileGraphConfig config = g.store(Format.EDGE_LIST, "/tmp/sample_pagerank.elist", Collections.singletonList(rank), EdgeProperty.ALL, false);
3.4 組込みアルゴリズムの実行
インメモリー・アナリストには、一連の組込みアルゴリズムが含まれており、Java APIとして使用できます。
このトピックでは、トライアングル・カウンティングおよびPagerank分析を使用したインメモリー分析の使用方法について説明します。
3.4.1 インメモリー・アナリストについて
インメモリー・アナリストには、一連の組込みアルゴリズムが含まれており、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);
3.4.2 トライアングル・カウンティング・アルゴリズムの実行
トライアングル・カウンティングの場合、countTriangles()
のsortByDegree
ブール・パラメータを使用して、グラフを最初に角度でソートする(true
)かソートしない(false
)かを制御できます。true
の場合、さらに多くのメモリーが使用されますが、アルゴリズムの実行は高速になります。ただし、グラフが非常に大きい場合、この最適化をオフにしてメモリー不足を回避することができます。
シェルを使用したトライアングル・カウンティングの実行
pgx> analyst.countTriangles(graph, true) ==> 1
Javaを使用したトライアングル・カウンティングの実行
import oracle.pgx.api.*; Analyst analyst = session.createAnalyst(); long triangles = analyst.countTriangles(graph, true);
このアルゴリズムでは、サンプル・グラフ内の1つのトライアングルを検出します。
ヒント:
インメモリー・アナリスト・シェルを使用する場合、ロギング・レベルを変更すると、実行中のログ出力の量を増加できます。:h :loglevel
を指定した:loglevel
コマンドの実行に関する情報を参照してください。
3.4.3 Pagerankアルゴリズムの実行
Pagerankは、グラフ内のそれぞれの頂点(ノード)について0
と1
の間のランク値を計算し、その値をdouble
プロパティに格納します。このため、アルゴリズムによって、出力に対してタイプdouble
の頂点プロパティが作成されます。
インメモリー・アナリストでは、頂点プロパティとエッジ・プロパティの2つのタイプがあります。
-
永続プロパティ: データ・ソースからグラフとともにロードされ固定されたディスク上のデータのインメモリー・コピーであるため、永続となるプロパティ。永続プロパティは読取り専用のため変更できず、セッション間で共有されます。
-
一時プロパティ: 一時プロパティには値が書き込めるため、セッションでプライベートに使用されます。一時プロパティは、
PgxGraph
オブジェクトでcreateVertexProperty
およびcreateEdgeProperty
を呼び出して作成できます。
この例では、Pagerank値が最も高い上位3つの頂点を取得します。タイプdouble
の一時頂点プロパティを使用して、計算したPagerank値を保持します。Pagerankアルゴリズムでは入力パラメータに次のデフォルト値を使用します。エラー許容値 = 0.001、減衰係数 = 0.85、および最大反復数 = 100です。
シェルを使用したPagerankの実行
pgx> rank = analyst.pagerank(graph, 0.001, 0.85, 100); ==> ... pgx> rank.getTopKValues(3) ==> 128=0.1402019732468347 ==> 333=0.12002296283541904 ==> 99=0.09708583862990475
Javaを使用したPageRankの実行
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()); }
3.5 サブグラフの作成
サブグラフはロードしたグラフに基づいて作成できます。フィルタ式を使用するか、2部グラフの左側のセットを指定する頂点(ノード)コレクションに基づく2部サブグラフを作成できます。
グラフのメモリーへの読込みについては、「グラフ・データのメモリーへの読込み」を参照してください。
3.5.1 フィルタ式について
フィルタ式は、各エッジで評価される式です。式によって、結果(この場合はサブグラフ)に含まれるようにエッジを完成させる述部を定義できます。
4つの頂点(ノード)と4つのエッジで構成される、「構成ファイルでのグラフ・メタデータの指定」のグラフを検討します。フィルタ式src.prop == 10
と一致するエッジについては、元の頂点のprop
プロパティが10になります。次の図に示すように、2つのエッジがフィルタ式と一致します。
次の図は、フィルタを適用した結果のグラフを示します。フィルタは頂点333に対応するエッジ、およびその頂点自体を除外します。
フィルタ式を使用すると、単一の頂点または頂点集合の選択が難しくなります。たとえば、プロパティ値10
の頂点のみは選択できません。これは、頂点を照合するには、10
が出力と入力のプロパティ値のどちらであるかエッジを照合する必要があるためです。ただし、エッジを一致させるときは、出力頂点、入力頂点、およびその結果のエッジ自体が自動的に含まれます。
3.5.2 簡易フィルタを使用したサブグラフの作成
次の例は、「フィルタ式について」で説明したサブグラフの作成を示します。
シェルを使用したサブグラフの作成
subgraph = graph.filter(new VertexFilter("vertex.prop == 10"))
Javaを使用したサブグラフの作成
import oracle.pgx.api.*; import oracle.pgx.api.filter.*; PgxGraph graph = session.readGraphWithProperties(...); PgxGraph subgraph = graph.filter(new VertexFilter("vertex.prop == 10"));
3.5.3 複合フィルタを使用したサブグラフの作成
この例では、少し複雑なフィルタを使用しています。ここでは、識別子の出力エッジの数(出力src
または入力dst
)を計算するoutDegree
関数を使用します。次のフィルタ式は、cost
プロパティ値が50を超え、outDegree
が1を超える入力頂点(ノード)のエッジと一致します。
dst.outDegree() > 1 && edge.cost > 50
次の図に示すように、サンプル・グラフの1つのエッジがこのフィルタ式と一致します。
次の図は、フィルタを適用した結果のグラフを示します。フィルタは頂点99と1908に対応するエッジを除外するため、その頂点も除外します。
3.5.4 頂点集合を使用した2部サブグラフの作成
2部サブグラフは、左側に使用される頂点(ノード)集合を指定して作成できます。2部サブグラフには、左側の頂点集合と右側の頂点集合の間にのみエッジがあります。左側の2つのノード間など、これらの集合内にエッジはありません。インメモリー・アナリストでは、入力および出力エッジがすべて削除されたために分離された頂点は、2部サブグラフの一部ではありません。
次の図に、2部サブグラフを示します。プロパティは示していません。
次の例では、「構成ファイルでのグラフ・メタデータの指定」で作成した単一のグラフから2部サブグラフを作成します。左側の頂点集合を作成し、それに頂点を入力します。
シェルを使用した2部サブグラフの作成
pgx> s = graph.createVertexSet() ==> ... pgx> s.addAll([graph.getVertex(333), graph.getVertex(99)]) ==> ... pgx> s.size() ==> 2 pgx> 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);
サブグラフを作成すると、インメモリー分析で、頂点が左側にあるかどうかを示すブール頂点(ノード)プロパティが自動的に作成されます。このプロパティには一意の名前を指定できます。
結果の2部サブグラフは次のようになります。
頂点1908は2部サブグラフから除外されます。頂点に繋がっている唯一のエッジは、128から1908に伸びています。エッジはサブグラフの2部プロパティに反しているため削除されています。頂点1908にはその他のエッジがないため、これも削除されています。
3.6 データベースの変更を処理するための自動デルタ・リフレッシュの使用
定期的にグラフを自動的にリフレッシュして(自動リフレッシュ)、インメモリー・グラフの、データベース内の基礎となるプロパティ・グラフへの変更との同期化を維持できます。
3.6.1 自動リフレッシュ用のインメモリー・サーバーの構成
自動リフレッシュは多くのスナップショットを作成できるので、メモリー使用率が高くなる可能性があります。デフォルトで、グラフの自動リフレッシュを有効にするオプションは管理者だけが使用できます。
すべてのユーザーにグラフの自動リフレッシュを許可するには、次の行をインメモリー・アナリストの構成ファイル($ORACLE_HOME/md/property_graph/pgx/conf/pgx.conf
に配置)に含める必要があります。
{
"allow_user_auto_refresh": true
}
3.6.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();
3.6.3 インメモリー・アナリストまたはJavaアプリケーションを使用したグラフの読取り
グラフ構成を作成した後、通常のAPIを使用してグラフをインメモリー・アナリストにロードできます。
pgx> G = session.readGraphWithProperties("graphs/my-config.pg.json")
グラフをロードすると、バックグラウンド・タスクが自動的に開始され、データ・ソースに更新があるかどうかを定期的にチェックします。
3.6.4 グラフの特定のスナップショットのチェックアウト
データベースには更新があるかどうかの問合せが毎分実行されます。時間間隔の経過後にデータベースのグラフが変更されている場合、グラフはリロードされ、新しいスナップショットがインメモリーで自動的に作成されます。
PgxSession
のgetAvailableSnapshots()
メソッドを使用して、グラフの使用可能なインメモリー・スナップショットを"チェックアウト"(ポインタを別のバージョンに移動)できます。出力の例は次のとおりです。
pgx> 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に設定する必要があります。インメモリー・アナリスト・シェルの場合:
pgx> G.getNumVertices()
==> 5
pgx> G.getNumEdges()
==> 5
pgx> session.setSnapshot( G, 1453315122685 )
==> null
pgx> G.getNumVertices()
==> 4
pgx> G.getNumEdges()
==> 4
PgxSession
のreadGraphAsOf()
メソッドを使用して、グラフの特定のスナップショットを直接ロードすることもできます。これはreadGraphWithProperty()
とその後にsetSnapshot()
を使用してグラフをロードするショートカットです。次に例を示します。
pgx> G = session.readGraphAsOf( config, 1453315122685 )
どのスナップショットが現在インメモリーで使用可能なのかがわからない、または気にしていない場合は、最大許容期間を指定することで、どれくらい“古い”スナップショットを許容できるかの時間範囲を指定することもできます。たとえば、スナップショットの最大存続期間を60分に設定するには、次を使用できます。
pgx> G = session.readGraphWithProperties( config, 60l, TimeUnit.MINUTES )
メモリー内に指定した最大期間よりも若い(新しい)スナップショットが1つ以上ある場合、それらのスナップショットのうち最も若い(新しい)ものが返されます。すべての使用可能なスナップショットが指定した最大期間よりも古い場合、または使用可能なスナップショットがまったくない場合は、新しいスナップショットが自動的に作成されます。
3.6.5 高度な自動リフレッシュ構成
自動リフレッシュ構成の拡張オプションを指定できます。
内部で、インメモリー・アナリストは最後のチェック以降の変更をデータベースからフェッチし、差分(変更)を前のスナップショットに適用することで、新しいスナップショットを作成します。2つのタイマーがあります。1つはデータベースから差分をフェッチしてキャッシュするためのもので、もう1つは実際に差分を適用して新しいスナップショットを作成するためのものです。
さらに、キャッシュされる差分の数のしきい値を指定できます。キャッシュされた変更の数がこのしきい値よりも多くなると、新しいスナップショットが自動的に作成されます。キャッシュされた変更の数は、単に頂点の変更の数の合計にエッジの変更の数を足したものです。
2つの理由で、差分は定期的にフェッチされ、インメモリー・アナリスト・サーバーにキャッシュされます。
-
実際のスナップショットの作成プロセスを高速化するため
-
しばらくするとデータベースが変更を"忘れる"可能性がある場合を把握するため
しきい値と更新タイマーの両方を指定できます。つまり、新しいスナップショットが作成される前に、両方の条件がチェックされます。これらのパラメータのうち少なくとも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
}
}
3.7 Apache Tomcatへのデプロイ
インメモリー・アナリストは、Apache TomcatまたはOracle WebLogicにデプロイできます。この例では、Webアプリケーションとしてインメモリー分析をApache Tomcatにデプロイする方法を示しています。
インメモリー・アナリストには、セキュリティ・レルムを必要とする有効なBASIC Auth
が提供されています。Tomcatでは、様々な種類のレルムをサポートしています。この例では、最も単純なMemoryRealm
を構成します。その他の種類については、Tomcatレルムの設定方法を参照してください。
注意:
Oracleでは、BASIC Auth
はテスト用としてのみ推奨します。その他すべてのデプロイメント・タイプについては、より強力な認証メカニズムを使用します。
3.8 Oracle WebLogic Serverへのデプロイ
インメモリー・アナリストは、Apache TomcatまたはOracle WebLogic Serverにデプロイできます。この例では、Webアプリケーションとしてインメモリー・アナリストをOracle WebLogic Serverにデプロイする方法を示しています。
3.8.1 Oracle WebLogic Serverのインストール
Oracle WebLogic Serverの最新バージョンをダウンロードし、インストールするには、次を参照してください
http://www.oracle.com/technetwork/middleware/weblogic/documentation/index.html
3.8.2 インメモリー・アナリストのデプロイ
Oracle WebLogicにインメモリー・アナリストをデプロイするには、次のようなコマンドを使用します。ユーザーの管理資格証明とWARファイルをこの例に示す値に入力します。
. $MW_HOME/user_projects/domains/mydomain/bin/setDomainEnv.sh . $MW_HOME/wlserver/server/bin/setWLSEnv.sh java weblogic.Deployer -adminurl http://localhost:7001 -username username -password password -deploy -source $PGX_HOME/server/pgx-webapp-wls.war
スクリプトが正常に実行されると、次のようなメッセージが表示されます。
Target state: deploy completed on Server myserver
3.9 インメモリー・アナリスト・サーバーへの接続
プロパティ・グラフのインメモリー・アナリストが、Oracle Databaseが稼働しているコンピュータにインストールされた後、あるいはApache TomcatまたはOracle WebLogic Server上のWebアプリケーションとしてOracle Databaseサーバー・ソフトウェアがインストールされていないクライアント・システムにインストールされた後に、インメモリー・アナリスト・サーバーに接続できます。
3.9.1 インメモリー・アナリスト・シェルによる接続
インメモリー・アナリスト・インスタンスへの最も単純な接続方法は、サーバーのベースURLを指定することです。次のベースURLでは、SCOTTユーザーをポート8080でリスニングするローカル・インスタンスに接続できます。
http://scott:<password>@localhost:8080/pgx
このベースURLでインメモリー・アナリスト・シェルを開始するには、--base_url
コマンドライン引数を使用します
cd $PGX_HOME ./bin/pgx --base_url http://scott:<password>@localhost:8080/pgx
同じ方法でリモート・インスタンスに接続できます。ただし、インメモリー・アナリストでは現在、Control APIのリモート・サポートは提供されていません。
3.9.1.1 HTTPリクエストのロギングについて
インメモリー分析シェルでは、デフォルトでデバッグ・メッセージをすべて非表示にします。どのHTTPリクエストが実行されたかを確認するには、この例に示すように、oracle.pgx
のログ・レベルをDEBUG
に設定します。
pgx> :loglevel oracle.pgx DEBUG ===> log level of oracle.pgx logger set to DEBUG pgx> session.readGraphWithProperties("sample_http.adj.json", "sample") 10:24:25,056 [main] DEBUG RemoteUtils - Requesting POST http://scott:<password>@localhost:8080/pgx/core/session/session-shell-6nqg5dd/graph HTTP/1.1 with payload {"graphName":"sample","graphConfig":{"uri":"http://path.to.some.server/pgx/sample.adj","separator":" ","edge_props":[{"type":"double","name":"cost"}],"node_props":[{"type":"integer","name":"prop"}],"format":"adj_list"}} 10:24:25,088 [main] DEBUG RemoteUtils - received HTTP status 201 10:24:25,089 [main] DEBUG RemoteUtils - {"futureId":"87d54bed-bdf9-4601-98b7-ef632ce31463"} 10:24:25,091 [pool-1-thread-3] DEBUG PgxRemoteFuture$1 - Requesting GET http://scott:<password>@localhost:8080/pgx/future/session/session-shell-6nqg5dd/result/87d54bed-bdf9-4601-98b7-ef632ce31463 HTTP/1.1 10:24:25,300 [pool-1-thread-3] DEBUG RemoteUtils - received HTTP status 200 10:24:25,301 [pool-1-thread-3] DEBUG RemoteUtils - {"stats":{"loadingTimeMillis":0,"estimatedMemoryMegabytes":0,"numEdges":4,"numNodes":4},"graphName":"sample","nodeProperties":{"prop":"integer"},"edgeProperties":{"cost":"double"}}
この例のグラフURIは、インメモリー・アナリスト・サーバーがHTTPまたはHDFSを使用してアクセスできるファイルを指し示している必要があります。
3.9.2 Javaによる接続
Javaを使用してインメモリー・アナリストを初期化する場合、ベースURLを指定できます。この例は次のようになります。インメモリー・アナリスト・サーバーへのURLがgetInMemAnalyst
APIコールに表示されます。
import oracle.pg.rdbms.*; import oracle.pgx.api.*; PgRdbmsGraphConfigcfg = GraphConfigBuilder.forPropertyGraphRdbms().setJdbcUrl("jdbc:oracle:thin:@127.0.0.1:1521:orcl") .setUsername("scott").setPassword("<password>") .setName("mygraph") .setMaxNumConnections(2) .setLoadEdgeLabel(false) .addVertexProperty("name", PropertyType.STRING, "default_name") .addEdgeProperty("weight", PropertyType.DOUBLE, "1000000") .build();OraclePropertyGraph opg = OraclePropertyGraph.getInstance(cfg); ServerInstance remoteInstance = Pgx.getInstance("http://scott:<password>@hostname:port/pgx"); PgxSession session = remoteInstance.createSession("my-session"); PgxGraph graph = session.readGraphWithProperties(opg.getConfig());
3.9.3 HTTPリクエストによる接続
インメモリー・アナリスト・シェルでは、HTTPリクエストを使用してインメモリー・アナリスト・サーバーと通信します。同じHTTPエンドポイントを直接使用、またはユーザーのクライアント・ライブラリへの書込みに使用できます。
この例では、HTTPを使用してcreate session
を呼び出します。
HTTP POST 'http://scott:<password>@localhost:8080/pgx/core/session' with payload '{"source":"shell"}' Response: {"sessionId":"session-shell-42v3b9n7"}
create session
のコールによって、セッション識別子が返されます。ほとんどのHTTPコールはインメモリー・アナリストUUIDを返し、リクエストの結果を保持しているリソースを識別します。インメモリー分析リクエストの数が多いと、完了するまで時間がかかりますが、結果へのハンドルはすぐに取得できます。このハンドルを使用して、HTTP GET
を特殊なエンドポイントに呼び出すと、リクエストの結果(リクエストが完了していない場合はブロック)が得られます。
インメモリー・アナリストとHTTPの相互作用のほとんどはこの例のようになります。
// any request, with some payload HTTP POST 'http://scott:<password>@localhost:8080/pgx/core/session/session-shell-42v3b9n7/graph' with payload '{"graphName":"sample","graphConfig":{"edge_props":[{"type":"double","name":"cost"}],"format":"adj_list","separator":" ","node_props":[{"type":"integer","name":"prop"}],"uri":"http://path.to.some.server/pgx/sample.adj"}}' Response: {"futureId":"15fc72e9-42e9-4527-9a31-bd20eb0adafb"} // get the result using the in-memory analyst future UUID. HTTP GET 'http://scott:<password>@localhost:8080/pgx/future/session/session-shell-42v3b9n7/result/15fc72e9-42e9-4527-9a31-bd20eb0adafb' Response: {"stats":{"loadingTimeMillis":0,"estimatedMemoryMegabytes":0,"numNodes":4,"numEdges":4},"graphName":"sample","nodeProperties":{"prop":"integer"},"edgeProperties":{"cost":"double"}}
3.10 プロパティ・グラフ・スナップショットの管理
Oracle Spatial and Graphプロパティ・グラフにより、プロパティ・グラフ・スナップショットを管理できます。
異なるバージョンのプロパティ・グラフをバイナリ・スナップショットとしてデータベースに永続化できます。バイナリ・スナップショットは、実行時に計算されるグラフ・データのサブグラフを表し、これは将来の使用時に必要になる可能性があります。スナップショットは、インメモリー・アナリストの入力として、またはパラレル・プロパティ・グラフ・データ・ローダーが使用できる出力ストリームとして、後で読み戻すことができます。
注意:
プロパティ・グラフ・スナップショットの管理は上級ユーザーを対象としています。
Java API OraclePropertyGraphUtils.storeBinaryInMemoryGraphSnapshot
を使用して、プロパティ・グラフの<graph_name>SS$表にバイナリ・スナップショットを格納できます。この操作には、プロパティ・グラフ・インスタンス、グラフの名前および所有者、スナップショットのID、およびバイナリ・スナップショットが読み取られる元の入力ストリームを保持しているOracleデータベースへの接続が必要です。スナップショットのタイムスタンプと、スナップショットを表に格納するときに使用する並列度も指定できます。
oraclePropertyGraphUtils.readBinaryInMemGraphSnapshot
を使用して、格納されたバイナリ・スナップショットを読み取ることができます。この操作には、プロパティ・グラフ・インスタンス、グラフの名前および所有者、読み取るスナップショットのID、およびバイナリ・ファイル・スナップショットを書き込む先の出力ストリームを保持しているOracleデータベースへの接続が必要です。スナップショット・バイナリ・ファイルを表から読み取るときに使用する並列度も指定できます。
次のコード・スニペットは、Oracleフラットファイル形式のデータ・ファイルからプロパティ・グラフを作成し、新しい頂点を追加し、GraphML形式を使用した出力ストリームにグラフをエクスポートします。この出力ストリームはバイナリ・ファイル・スナップショットを表し、プロパティ・グラフ・スナップショット表に格納されます。最後に、この例はスナップショット表からファイルを読み戻し、そのコンテンツから2番目のグラフを作成します。
String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";
OraclePropertyGraph opg = OraclePropertyGraph.getInstance(args, szGraphName);
opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, 2 /* dop */, 1000, true,
"PDML=T,PDDL=T,NO_DUP=T,");
// Add a new vertex
Vertex v = opg.addVertex(Long.valueOf("1000"));
v.setProperty("name", "Alice");
opg.commit();
System.out.pritnln("Graph " + szGraphName + " total vertices: " +
opg.countVertices(dop));
System.out.pritnln("Graph " + szGraphName + " total edges: " +
opg.countEdges(dop));
// Get a snapshot of the current graph as a file in graphML format.
OutputStream os = new ByteArrayOutputStream();
OraclePropertyGraphUtils.exportGraphML(opg,
os /* output stream */,
System.out /* stream to show progress */);
// Save the snapshot into the SS$ table
InputStream is = new ByteArrayInputStream(os.toByteArray());
OraclePropertyGraphUtils.storeBinaryInMemGraphSnapshot(szGraphName,
szGraphOwner /* owner of the
property graph */,
conn /* database connection */,
is,
(long) 1 /* snapshot ID */,
1 /* dop */);
os.close();
is.close();
// Read the snapshot back from the SS$ table
OutputStream snapshotOS = new ByteArrayOutputStream();
OraclePropertyGraphUtils.readBinaryInMemGraphSnapshot(szGraphName,
szGraphOwner /* owner of the
property graph */,
conn /* database connection */,
new OutputStream[] {snapshotOS},
(long) 1 /* snapshot ID */,
1 /* dop */);
InputStream snapshotIS = new ByteArrayInputStream(snapshotOS.toByteArray());
String szGraphNameSnapshot = szGraphName + "_snap";
OraclePropertyGraph opg = OraclePropertyGraph.getInstance(args,szGraphNameSnapshot);
OraclePropertyGraphUtils.importGraphML(opg,
snapshotIS /* input stream */,
System.out /* stream to show progress */);
snapshotOS.close();
snapshotIS.close();
System.out.pritnln("Graph " + szGraphNameSnapshot + " total vertices: " +
opg.countVertices(dop));
System.out.pritnln("Graph " + szGraphNameSnapshot + " total edges: " +
opg.countEdges(dop));
前述の例では、次のような出力が生成されます。
Graph test total vertices: 79 Graph test total edges: 164 Graph test_snap total vertices: 79 Graph test_snap total edges: 164