3 インメモリー・アナリスト(PGX)の使用

Oracle Spatial and Graphのインメモリー・アナリスト機能は、一連の分析関数をサポートします。

この章では、インメモリー・アナリストを使用する例について説明します(プロパティ・グラフ・インメモリー分析とも呼ばれ、Javadoc、コマンドライン、パスの説明、エラー・メッセージ、例などではPGXと省略されます)。内容は次のとおりです。

3.1 グラフのメモリーへの読込み

このトピックでは、シェル・インタフェースを使用したメモリーへの対話によるグラフの読込みの例について説明します。

主なステップは次のとおりです。

3.1.1 インメモリー・アナリスト・サーバー・インスタンスへの接続

インメモリー・アナリスト・シェルを開始するには:

  1. プロパティ・グラフのサポートがインストールされているシステムで端末セッションを開始します。
  2. ローカル(組込み)インメモリー・アナリスト・インスタンスを開始するか、リモート・インメモリー・アナリスト・インスタンスに接続します
    • ローカル(組込み)インスタンス開始のJavaの例:
      import java.util.Map;
      import java.util.HashMap;
      import oracle.pgx.api.*;
      import oracle.pgx.config.PgxConfig.Field;
       
      String url = Pgx.EMBEDDED_URL; // local JVM
      ServerInstance instance = Pgx.getInstance(url);
      instance.startEngine(); // will use default configuration
      PgxSession session = instance.createSession("test");
    • リモート・インスタンスへの接続のJavaの例:
      import java.util.Map;
      import java.util.HashMap;
      import oracle.pgx.api.*;
      import oracle.pgx.config.PgxConfig.Field;
       
      String url = "http://my-server.com:8080/pgx" // replace with base URL of your setup
      ServerInstance instance = Pgx.getInstance(url);
      PgxSession session = instance.createSession("test");
  3. シェルでは、次のコマンドを入力しますが、開始コマンド、または必要なインスタンスのタイプへの接続コマンドのいずれかを選択します。
    export PGX_HOME=$ORACLE_HOME/md/property_graph/pgx
    cd $PGX_HOME
    ./bin/pgx --help
    ./bin/pgx --version
     
    # start embedded shell
    ./bin/pgx
     
    # start remote shell
    ./bin/pgx --base_url http://my-server.com:8080/pgx

    組込みシェルの場合、次のように出力されます。

    10:43:46,666 [main] INFO Ctrl$2 - >>> PGX engine running.
    pgx>
  4. オプションで、事前定義済の変数を表示します。
    pgx> instance
    ==> PGX Server Instance running on embedded mode
    pgx> session
    ==> PGX session pgxShell registered at PGX Server Instance running on embedded mode
    pgx> analyst
    ==> Analyst for PGX session pgxShell registered at PGX Server Instance running on embedded mode
    pgx>

    他のトピックでの例では、インスタンスおよびセッション変数はここで示すとおり設定されるとみなされます。

インメモリー・アナリスト・ソフトウェアが正しくインストールされている場合、エンジンの実行ログ・メッセージと、インメモリー・アナリスト・シェル・プロンプト(pgx>)が表示されます。

変数instancesession、およびanalystが使用可能です。

このトピックの前の例では、pgxコマンドでリモートURLを指定していないため、シェルがローカル・インスタンスを開始します。

3.1.2 シェル・ヘルプの使用

インメモリー・アナリスト・シェルには、:helpコマンドを使用してアクセスできるヘルプ・システムが用意されています。

3.1.3 構成ファイルでのグラフ・メタデータの指定

このトピックでは、構成ファイルでグラフ・メタデータを指定する例を示します。これらのステップに従い、ディレクトリといくつかのファイルの例を作成します。

  1. 作成するファイルの例を保持するディレクトリを作成します。次に例を示します。

    mkdir -p ${ORACLE_HOME}/md/property_graph/examples/pgx/graphs/
  2. このディレクトリで、sample.adj.jsonという名前で、グラフ構成ファイル用の次のコンテンツを含むテキスト・ファイルを作成します。この構成ファイルで、インメモリー・アナリストのグラフの読取り方法について説明します。

    {
      "uri": "sample.adj", 
      "format": "adj_list",
      "node_props": [{ 
        "name": "prop", 
        "type": "integer" 
      }],
      "edge_props": [{ 
        "name": "cost", 
        "type": "double" 
      }],
      "separator": " "
    }
  3. 同じディレクトリで、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 sample.adjデータからレンダリングされたプロパティ・グラフ

図3-1の説明が続きます
「図3-1 sample.adjデータからレンダリングされたプロパティ・グラフ」の説明

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つのエッジがあり、それぞれ他方と逆の方向を指しています)

図3-2 単純なカスタム・プロパティ・グラフ

図3-2の説明が続きます
「図3-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は、グラフ内のそれぞれの頂点(ノード)について01の間のランク値を計算し、その値を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つのエッジがフィルタ式と一致します。

図3-3 src.prop == 10と一致するエッジ

図3-3の説明が続きます
「図3-3 src.prop == 10と一致するエッジ」の説明

次の図は、フィルタを適用した結果のグラフを示します。フィルタは頂点333に対応するエッジ、およびその頂点自体を除外します。

図3-4 簡易フィルタで作成されたグラフ

図3-4の説明が続きます
「図3-4 簡易フィルタで作成されたグラフ」の説明

フィルタ式を使用すると、単一の頂点または頂点集合の選択が難しくなります。たとえば、プロパティ値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つのエッジがこのフィルタ式と一致します。

図3-5 outDegreeフィルタと一致するエッジ

図3-5の説明が続きます
「図3-5 outDegreeフィルタと一致するエッジ」の説明

次の図は、フィルタを適用した結果のグラフを示します。フィルタは頂点99と1908に対応するエッジを除外するため、その頂点も除外します。

図3-6 outDegreeフィルタで作成されたグラフ

図3-6の説明が続きます
「図3-6 outDegreeフィルタで作成されたグラフ」の説明

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 グラフの特定のスナップショットのチェックアウト

データベースには更新があるかどうかの問合せが毎分実行されます。時間間隔の経過後にデータベースのグラフが変更されている場合、グラフはリロードされ、新しいスナップショットがインメモリーで自動的に作成されます。

PgxSessiongetAvailableSnapshots()メソッドを使用して、グラフの使用可能なインメモリー・スナップショットを"チェックアウト"(ポインタを別のバージョンに移動)できます。出力の例は次のとおりです。

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

PgxSessionreadGraphAsOf()メソッドを使用して、グラフの特定のスナップショットを直接ロードすることもできます。これは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レルムの設定方法を参照してください。

  1. インメモリー・アナリストWARファイルをwebappsディレクトリにコピーします。次に例を示します。
    cp $PGX_HOME/server/pgx-webapp-<VERSION>.war $CATALINA_HOME/webapps/pgx.war
    
    PGX_HOMEは、次のように定義する必要があります。
    export PGX_HOME=$ORACLE_HOME/md/property_graph/pgx

    pgx-webapp-<VERSION>-wls.warという名前のWebLogic Serverに固有のファイルをコピーしないでください。

  2. エディタで$CATALINA_HOME/conf/server.xmlを開き、次のレルムのクラス宣言を<Engine>要素に追加します。
    <Realm className="org.apache.catalina.realm.MemoryRealm" />
    
  3. エディタでCATALINA_HOME/conf/tomcat-users.xmlを開き、USERロールのユーザーを定義します。この例のscottおよび<password>を、適切なユーザー名とパスワードに置き換えます。
    <role rolename="USER" />
    <user username="scott" password="<password>" roles="USER" />
    
  4. ポート8080がすでに使用されていないことを確認します。
  5. Tomcatを開始します。
    cd $CATALINA_HOME
    ./bin/startup.sh
    
  6. Tomcatが動作していることを確認します。
    cd $PGX_HOME
    ./bin/pgx --base_url http://scott:<password>@localhost:8080/pgx
    

ノート:

Oracleでは、BASIC Authはテスト用としてのみ推奨します。その他すべてのデプロイメント・タイプについては、より強力な認証メカニズムを使用します。

3.7.1 認証メカニズムについて

インメモリー・アナリストのWebデプロイメントでは、デフォルトでBASIC Authを使用します。本番のデプロイメントでは、より安全な認証メカニズムに変更する必要があります。

証メカニズムを変更するには、Webアプリケーション・アーカイブ(WAR)ファイルでweb.xmlデプロイメント記述子のsecurity-constraint要素を変更します。

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-<version>-wls.war
PGX_HOMEは、次のように定義する必要があります。
export PGX_HOME=$ORACLE_HOME/md/property_graph/pgx

スクリプトが正常に実行されると、次のようなメッセージが表示されます。

Target state: deploy completed on Server myserver

3.8.3 サーバーが動作していることの確認

次の形式のコマンドを入力して、サーバーに接続できることを確認します。

$PGX_HOME/bin/pgx --base_url http://scott:<password>@localhost:7001/pgx

3.8.4 認証メカニズムについて

インメモリー・アナリストのWebデプロイメントでは、デフォルトでBASIC Authを使用します。本番のデプロイメントでは、より安全な認証メカニズムに変更する必要があります。

認証メカニズムを変更するには、Webアプリケーション・アーカイブ(WAR)ファイルでweb.xmlデプロイメント記述子のsecurity-constraint要素を変更します。

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 PGX REST APIによる接続

REST API PGXエンドポイントを使用して、インメモリー・アナリスト・インスタンスに接続できます。これにより、Java以外の言語でインメモリー・アナリストと対話して独自のクライアントを実装できます。

このトピックの例は、次を前提としています。

  • curlを含むLinuxがインストールされています。curlは、RESTエンドポイントと対話するための単純なコマンドライン・ユーティリティです。)
  • PGXサーバーは、http://localhost:7007で稼働中です。
  • PGXサーバーは認証/認可が無効にされています。つまり、$ORACLE_HOME/md/property_graph/pgx/conf/server.conf"enable_tls": falseが含まれています。(これはデフォルト以外の設定であり、本番では推奨されません)。
  • PGXでは、ローカル・ファイル・システムからグラフを読み取ることができます。つまり、$ORACLE_HOME/md/property_graph/pgx/conf/pgx.conf"allow_local_filesystem": trueが含まれています。(これはデフォルト以外の設定であり、本番では推奨されません)。

Swagger仕様では、ブラウザでhttp://localhost:7007/swagger.jsonを開くことで、JSONでサポートされているエンドポイントの完全なリストを表示できます。

ステップ1: CSRFトークンの取得

CSRFトークンをリクエストします。

curl -v http://localhost:7007/token

レスポンスは次のようになります。

*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 7007 (#0)
> GET /token HTTP/1.1
> Host: localhost:7007
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 201
< SET-COOKIE: _csrf_token=9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0;Version=1; HttpOnly
< Content-Length: 0

レスポンスに表示されるように、Cookie _csrf_tokenにトークン値が設定されます。9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0は、次のリクエストのサンプル・トークンとして使用されます。どの書込みリクエストでも、PGXサーバーでは、Cookieとペイロードの両方に同じトークンが存在している必要があります。

ステップ2: セッションの作成

新しいセッションを作成するには、JSONペイロードを送信します。

curl -v --cookie '_csrf_token=9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0' -H 'content-type: application/json' -X POST http://localhost:7007/core/v1/sessions -d '{"source":"my-application", "idleTimeout":0, "taskTimeout":0, "timeUnitName":"MILLISECONDS", "_csrf_token":"9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0"}'

my-applicationを、実行しているアプリケーションを記述する値に置き換えます。この値は、サーバー管理者がセッションをアプリケーションにマップするために使用できます。アイドル・タイムアウトとタスク・タイムアウトを0に設定すると、セッションおよび送信されたタスクのタイムアウトがサーバーにより決定されることを意味します。CookieヘッダーとJSONペイロードの両方に同じCSRFトークンを指定する必要があります。

レスポンスは次のようになります。

*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 7007 (#0)
> POST /core/v1/sessions HTTP/1.1
> Host: localhost:7007
> User-Agent: curl/7.47.0
> Accept: */*
> Cookie: _csrf_token=9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0
> content-type: application/json
> Content-Length: 159
> 
* upload completely sent off: 159 out of 159 bytes
< HTTP/1.1 201
< SET-COOKIE: SID=abae2811-6dd2-48b0-93a8-8436e078907d;Version=1; HttpOnly
< Content-Length: 0

レスポンスは、作成されたセッションID値をCookieに設定します。セッションID abae2811-6dd2-48b0-93a8-8436e078907dは、後続のリクエストのサンプルとして使用されます。

ステップ3: グラフの読取り

ノート:

事前にロードされたグラフまたはすでに別のセッションで公開されたグラフを分析する場合は、このステップをスキップできます。事前にロードまたは公開されたグラフにアクセスするために必要なものはグラフの名前のみです。

グラフを読み取るには、次の例に示すように、グラフ構成をJSONとしてサーバーに送信します(<graph-config>を実際のPGXグラフ構成のJSON表現に置き換えます)。

curl -v -X POST --cookie '_csrf_token=9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0;SID=abae2811-6dd2-48b0-93a8-8436e078907d'  http://localhost:7007/core/v1/loadGraph -H 'content-type: application/json'  -d  '{"graphConfig":<graph-config>,"graphName":null,"csrf_token":"9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0"}'

次に、Oracleデータベースからプロパティ・グラフを読み取るグラフ構成の例を示します。

{
  "format": "pg",
  "db_engine": "RDBMS",
  "jdbc_url":"jdbc:oracle:thin:@127.0.0.1:1521:orcl122",
  "username":"scott",
  "password":"tiger",
  "max_num_connections": 8,
  "name": "connections",
  "vertex_props": [
    {"name":"name", "type":"string"},
    {"name":"role", "type":"string"},
    {"name":"occupation", "type":"string"},
    {"name":"country", "type":"string"},
    {"name":"political party", "type":"string"},
    {"name":"religion", "type":"string"}
  ],
  "edge_props": [
    {"name":"weight", "type":"double", "default":"1"}
  ],
  "edge_label": true,
  "loading": {
    "load_edge_label": true
  }
}

"graphName": nullを渡すと、サーバーに名前の生成が指示されます。

サーバーは次のように応答します。

* upload completely sent off: 315 out of 315 bytes
< HTTP/1.1 202
< Location: http://localhost:7007/core/v1/futures/8a46ef65-01a9-4bd0-87d3-ffe9dfd2ce3c/status
< Content-Type: application/json;charset=utf-8
< Content-Length: 51
< Date: Mon, 05 Nov 2018 17:22:22 GMT
<
* Connection #0 to host localhost left intact
{"futureId":"8a46ef65-01a9-4bd0-87d3-ffe9dfd2ce3c"}

非同期リクエストについて

PGX RESTエンドポイントのほとんどは非同期です。結果が準備できるまで接続をオープンしたままにしておくかわりに、PGXサーバーはタスクとして送信し、ステータス・コードが200のfuture IDを返します。このIDは、クライアントがタスクのステータスを定期的にリクエストしたり、完了後の結果値を要求するために使用できます。

前述のレスポンスから、次のようにfutureのステータスを要求できます。

curl -v --cookie 'SID=abae2811-6dd2-48b0-93a8-8436e078907d'  http://localhost:7007/core/v1/futures/8a46ef65-01a9-4bd0-87d3-ffe9dfd2ce3c/status

次のような内容が返されます。

< HTTP/1.1 200
< Content-Type: application/json;charset=utf-8
< Content-Length: 730
< Date: Mon, 05 Nov 2018 17:35:19 GMT
< 
* Connection #0 to host localhost left intact
{"id":"eb17f75b-e4c1-4a66-81a0-4ff0f8b4cb92","links":[{"href":"http://localhost:7007/core/v1/futures/eb17f75b-e4c1-4a66-81a0-4ff0f8b4cb92/status","rel":"self","method":"GET","interaction":["async-polling"]},{"href":"http://localhost:7007/core/v1/futures/eb17f75b-e4c1-4a66-81a0-4ff0f8b4cb92","rel":"abort","method":"DELETE","interaction":["async-polling"]},{"href":"http://localhost:7007/core/v1/futures/eb17f75b-e4c1-4a66-81a0-4ff0f8b4cb92/status","rel":"canonical","method":"GET","interaction":["async-polling"]},{"href":"http://localhost:7007/core/v1/futures/eb17f75b-e4c1-4a66-81a0-4ff0f8b4cb92/value","rel":"related","method":"GET","interaction":["async-polling"]}],"progress":"succeeded","completed":true,"intervalToPoll":1}

この出力には、ステータス(この場合はsucceeded)の他に、タスクを取り消すリンク(DELETE)および完了後にタスクの結果を取得するリンク(GET <future-id>/value)も含まれます。

curl -X GET --cookie 'SID=abae2811-6dd2-48b0-93a8-8436e078907d' http://localhost:7007/core/v1/futures/cdc15a38-3422-42a1-baf4-343c140cf95d/value

サーバーにより生成された名前(sample)を含め、ロードされたグラフに関する詳細が返されます。

{"id":"sample","links":[{"href":"http://localhost:7007/core/v1/graphs/sample","rel":"self","method":"GET","interaction":["async-polling"]},{"href":"http://localhost:7007/core/v1/graphs/sample","rel":"canonical","method":"GET","interaction":["async-polling"]}],"nodeProperties":{"prop1":{"id":"prop1","links":[{"href":"http://localhost:7007/core/v1/graphs/sample/properties/prop1","rel":"self","method":"GET","interaction":["async-polling"]},{"href":"http://localhost:7007/core/v1/graphs/sample/properties/prop1","rel":"canonical","method":"GET","interaction":["async-polling"]}],"dimension":0,"name":"prop1","entityType":"vertex","type":"integer","transient":false}},"vertexLabels":null,"edgeLabel":null,"metaData":{"id":null,"links":null,"numVertices":4,"numEdges":4,"memoryMb":0,"dataSourceVersion":"1536029578000","config":{"format":"adj_list","separator":" ","edge_props":[{"type":"double","name":"cost"}],"error_handling":{},"vertex_props":[{"type":"integer","name":"prop1"}],"vertex_uris":["PATH_TO_FILE"],"vertex_id_type":"integer","loading":{}},"creationRequestTimestamp":1541242100335,"creationTimestamp":1541242100774,"vertexIdType":"integer","edgeIdType":"long","directed":true},"graphName":"sample","edgeProperties":{"cost":{"id":"cost","links":[{"href":"http://localhost:7007/core/v1/graphs/sample/properties/cost","rel":"self","method":"GET","interaction":["async-polling"]},{"href":"http://localhost:7007/core/v1/graphs/sample/properties/cost","rel":"canonical","method":"GET","interaction":["async-polling"]}],"dimension":0,"name":"cost","entityType":"edge","type":"double","transient":false}},"ageMs":0,"transient":false}

わかりやすくするために、残りのステップでは、非同期タスクのステータスまたは値を要求する追加のリクエストを省略します。

ステップ4: プロパティの作成

ロードされたグラフでPageRankアルゴリズムを実行する前に、グラフ上にDOUBLE型の頂点プロパティを作成して、計算されたランキング値を保持できるようにする必要があります。

curl -v -X POST --cookie '_csrf_token=9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0;SID=abae2811-6dd2-48b0-93a8-8436e078907d'  http://localhost:7007/core/v1/graphs/sample/properties -H 'content-type: application/json'  -d '{"entityType":"vertex","type":"double","name":"pagerank", "hardName":false,"dimension":0,"_csrf_token":"9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0"}'

返されたfutureの結果をリクエストすると、次のような結果が返されます。

{"id":"pagerank","links":[{"href":"http://localhost:7007/core/v1/graphs/sample/properties/pagerank","rel":"self","method":"GET","interaction":["async-polling"]},{"href":"http://localhost:7007/core/v1/graphs/sample/properties/pagerank","rel":"canonical","method":"GET","interaction":["async-polling"]}],"dimension":0,"name":"pagerank","entityType":"vertex","type":"double","transient":true}

ステップ5: ロードされたグラフでのPageRankアルゴリズムの実行

次の例に、アルゴリズム(この場合はPageRank)を実行する方法を示します。アルゴリズムIDはURLの一部であり、アルゴリズムに渡されるパラメータはJSONペイロードの一部です。

curl -v -X POST --cookie '_csrf_token=9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0;SID=abae2811-6dd2-48b0-93a8-8436e078907d' http://localhost:7007/core/v1/analyses/pgx_builtin_k1a_pagerank/run -H  'content-type: application/json' -d  '{"args":[{"type":"GRAPH","value":"sample"},{"type":"DOUBLE_IN","value":0.001},{"type":"DOUBLE_IN","value":0.85},{"type":"INT_IN","value":100},{"type":"BOOL_IN","value":true},{"type":"NODE_PROPERTY","value":"pagerank"}],"expectedReturnType":"void","workloadCharacteristics":["PARALLELISM.PARALLEL"],"_csrf_token":"9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0"}'

futureが完了すると、結果は次のようになります。

{"success":true,"canceled":false,"exception":null,"returnValue":null,"executionTimeMs":50}

ステップ6: PGQL問合せの実行

PageRankアルゴリズムの結果を問い合せるには、次の例に示すようにPGQL問合せを実行できます。

curl -v -X POST --cookie '_csrf_token=9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0;SID=abae2811-6dd2-48b0-93a8-8436e078907d' http://localhost:7007/core/v1/pgql/run -H 'content-type: application/json'  -d '{"pgqlQuery":"SELECT x.pagerank MATCH (x) WHERE x.pagerank > 0","semantic":"HOMOMORPHISM", "schemaStrictnessMode":true, "graphName" : "sample", "_csrf_token":"9bf51c8f-1c75-455e-9b57-ec3ca1c63cc0"}'

結果は、問合せの結果セットとの対話に使用できる一連のリンクです。

{"id":"pgql_1","links":[{"href":"http://localhost:7007/core/v1/pgqlProxies/pgql_1","rel":"self","method":"GET","interaction":["sync"]},{"href":"http://localhost:7007/core/v1/pgqlResultProxies/pgql_1/elements","rel":"related","method":"GET","interaction":["sync"]},{"href":"http://localhost:7007/core/v1/pgqlResultProxies/pgql_1/results","rel":"related","method":"GET","interaction":["sync"]},{"href":"http://localhost:7007/core/v1/pgqlProxies/pgql_1","rel":"canonical","method":"GET","interaction":["async-polling"]}],"exists":true,"graphName":"sample","resultSetId":"pgql_1","numResults":4}

結果セットの最初の2048要素をリクエストするには、次を送信します。

curl -X GET  --cookie 'SID=abae2811-6dd2-48b0-93a8-8436e078907d' http://localhost:7007/core/v1/pgqlProxies/pgql_1/results?size=2048

レスポンスは次のようになります。

{"id":"/pgx/core/v1/pgqlProxies/pgql_1/results","links":[{"href":"http://localhost:7007/core/v1/pgqlProxies/pgql_1/results","rel":"self","method":"GET","interaction":["sync"]},{"href":"http://localhost:7007/core/v1/pgqlProxies/pgql_1/results","rel":"canonical","method":"GET","interaction":["async-polling"]}],"count":4,"totalItems":4,"items":[[0.3081206521195582],[0.21367103988538017],[0.21367103988538017],[0.2645372681096815]],"hasMore":false,"offset":0,"limit":4,"showTotalResults":true}

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