5 ビッグ・データ環境でのプロパティ・グラフの使用

この章では、ビッグ・データ環境でのプロパティ・グラフ・データの作成、格納および操作に関する概念と使用方法の情報を提供します。

5.1 プロパティ・グラフについて

プロパティ・グラフでは、プロパティ(キー値ペア)をグラフの頂点およびエッジに簡単に関連付けることができ、大量のデータ・セット間の関係に基づく分析操作が可能になります。

5.1.1 プロパティ・グラフとは

プロパティ・グラフは、オブジェクトまたは頂点のセットと、これらのオブジェクトをつなぐ矢印またはエッジのセットで構成されます。頂点とエッジには複数のプロパティを含めることができ、それらはキー値ペアとして表されます。

各頂点には一意の識別子があり、次のものを含めることができます。

  • 出力エッジのセット

  • 入力エッジのセット

  • プロパティの集まり

各エッジには一意の識別子があり、次のものを含めることができます。

  • 出力頂点

  • 入力頂点

  • 2つの頂点間の関係を示すテキスト・ラベル

  • プロパティの集まり

図5-1は、2つの頂点と1つのエッジを持つ非常に単純なプロパティ・グラフを示しています。2つの頂点には、識別子1および2があります。両方の頂点には、プロパティnameおよびageがあります。エッジは、出力頂点1から入力頂点2に向かっています。このエッジは、テキスト・ラベルknowsと、頂点1と2の関係のタイプを識別するプロパティtypeで表されます。

図5-1 単純なプロパティ・グラフの例

図5-1の説明は次にあります
「図5-1 単純なプロパティ・グラフの例」の説明

Big Data Spatial and Graphプロパティ・グラフ・データ・モデルには標準が用意されていませんが、これはW3C標準ベースのResource Description Framework (RDF)グラフ・データ・モデルに似ています。プロパティ・グラフ・データ・モデルはRDFよりも単純であり、精密ではありません。このような相違点により、これは次のようなユースケースでよい候補になります。

  • ソーシャル・ネットワークでの影響の特定

  • トレンドおよび顧客行動の予測

  • パターン一致に基づく関係の発見

  • キャンペーンをカスタマイズするためのクラスタの特定

注意:

データベース側でOracleがサポートしているプロパティ・グラフ・データ・モデルでは、頂点にラベルを使用することはできません。ただし、「頂点のラベルの指定」で説明されているように、指定した頂点プロパティの値を1つ以上のラベルとして扱うことができます。

5.1.2 プロパティ・グラフのビッグ・データ・サポートとは

プロパティ・グラフは、HadoopおよびOracle NoSQL Databaseのビッグ・データに対してサポートされます。このサポートは、データ・アクセス・レイヤーと分析レイヤーで構成されます。Hadoopでのデータベースの選択肢により、スケーラブルで一貫したストレージ管理が提供されます。

図5-2は、Oracleプロパティ・グラフのアーキテクチャを示しています。

図5-2 Oracleプロパティ・グラフのアーキテクチャ

図5-2の説明が続きます
「図5-2 Oracleプロパティ・グラフのアーキテクチャ」の説明
5.1.2.1 インメモリー・アナリスト

インメモリー・アナリスト・レイヤーでは、パラレル・インメモリー実行を使用してプロパティ・グループを分析できます。これは、パス計算、ランキング、コミュニティ検出、推奨ムを含む、35を超える分析機能を提供します。

5.1.2.2 データ・アクセス・レイヤー

データ・アクセス・レイヤーは、プロパティ・グラフの作成および削除、頂点とエッジの追加および削除、キー値ペアを使用した頂点とエッジの検索、テキスト索引の作成、およびその他の操作の実行に使用できる、Java APIのセットを提供します。Java APIには、プロパティ・グラフ・データ・モデル用のTinkerPop Blueprintsグラフ・インタフェースの実装が含まれています。また、これらのAPIは、広く普及しているオープンソースのテキスト索引付けおよび検索エンジンであるApache LuceneおよびApache SolrCloudと統合されています。

5.1.2.3 ストレージ管理

プロパティ・グラフは、Oracle NoSQL DatabaseまたはApache HBaseのいずれかに格納できます。これらのデータベースは両方とも成熟しており、スケーラブルで、効率的なナビゲーション、問合せおよび分析をサポートします。両方とも、プロパティ・グラフの頂点およびエッジをモデル化するために表を使用します。

5.1.2.4 RESTful Webサービス

RESTful Webサービスを使用して、グラフ・データにアクセスしてグラフ操作を実行することもできます。たとえば、Linux curlコマンドを使用して、頂点とエッジを取得したり、グラフ要素を追加および削除したりすることができます。

5.2 プロパティ・グラフのデータ形式について

次のグラフ形式がサポートされます。

5.2.1 GraphMLデータ形式

GraphMLファイル形式では、XMLを使用してグラフを記述します。例5-1は、図5-1に示されているプロパティ・グラフのGraphMLの記述を示しています。

関連項目:

『The GraphML File Format』

http://graphml.graphdrawing.org/

例5-1 単純なプロパティ・グラフのGraphMLの記述

<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns">
    <key id="name" for="node" attr.name="name" attr.type="string"/>
    <key id="age" for="node" attr.name="age" attr.type="int"/>
    <key id="type" for="edge" attr.name="type" attr.type="string"/>
    <graph id="PG" edgedefault="directed">
        <node id="1">
            <data key="name">Alice</data>
            <data key="age">31</data>
        </node>
        <node id="2">
            <data key="name">Bob</data>
            <data key="age">27</data>
        </node>
        <edge id="3" source="1" target="2" label="knows">
            <data key="type">friends</data>
        </edge>
    </graph>
</graphml>

5.2.2 GraphSONデータ形式

GraphSONファイル形式では、JavaScript Object Notation (JSON)に基づいてグラフを記述します。例5-2は、図5-1に示されているプロパティ・グラフのGraphSONの記述を示しています。

関連項目:

『GraphSON Reader and Writer Library』

https://github.com/tinkerpop/blueprints/wiki/GraphSON-Reader-and-Writer-Library

例5-2 単純なプロパティ・グラフのGraphSONの記述

{
    "graph": {
        "mode":"NORMAL",
        "vertices": [
            {
                "name": "Alice",
                "age": 31,
                "_id": "1",
                "_type": "vertex"
            },
            {
                "name": "Bob",
                "age": 27,
                "_id": "2",
                "_type": "vertex"
            }       
        ],
        "edges": [
            {
                "type": "friends",
                "_id": "3",
                "_type": "edge",
                "_outV": "1",
                "_inV": "2",
                "_label": "knows"
            }
        ]
    }
}

5.2.3 GMLデータ形式

Graph Modeling Language (GML)ファイル形式では、ASCIIを使用してグラフを記述します。例5-3は、図5-1に示されているプロパティ・グラフのGMLの記述を示しています。

関連項目:

『GML: A Portable Graph File Format』、Michael Himsolt著

http://www.fim.uni-passau.de/fileadmin/files/lehrstuhl/brandenburg/projekte/gml/gml-technical-report.pdf

例5-3 単純なプロパティ・グラフのGMLの記述

graph [
   comment "Simple property graph"
   directed 1
   IsPlanar 1
   node [
      id 1
      label "1"
      name "Alice"
      age 31
        ]
   node [
      id 2
      label "2"
      name "Bob"
      age 27
        ]
   edge [
      source 1
      target 2
      label "knows"
      type "friends"
        ]
      ]

5.2.4 Oracleフラット・ファイル形式

Oracleフラット・ファイル形式はプロパティ・グラフのみを記述します。これは、その他のファイル形式よりも正確で、より優れたデータ型サポートを提供します。Oracleフラット・ファイル形式は、グラフを記述するために、頂点用とエッジ用にそれぞれ1つずつ、2つのファイルを使用します。レコードのフィールドはカンマで区切られます。

例5-4は、図5-1に示されているプロパティ・グラフを記述するOracleフラット・ファイルを示しています。

例5-4 単純なプロパティ・グラフのOracleフラット・ファイルの記述

頂点ファイル:

1,name,1,Alice,,
1,age,2,,31,
2,name,1,Bob,,
2,age,2,,27,

エッジ・ファイル:

1,1,2,knows,type,1,friends,, 

5.3 プロパティ・グラフの開始

プロパティ・グラフを開始するには、次の主要手順に従います。

  1. プロパティ・グラフを初めて使用する際、ソフトウェアがインストールされ、稼働可能であることを確認します。
  2. Java APIで提供されるクラスを使用して、Javaプログラムを作成します。

5.4 プロパティ・グラフ・データ用のJava APIの使用

プロパティ・グラフの作成には、Java APIを使用したプロパティ・グラフとそのオブジェクトの作成が含まれます。

5.4.1 Java APIの概要

プロパティ・グラフで使用できるJava APIには、次のものが含まれます。

5.4.1.1 Oracle Big Data Spatial and Graph Java API

Oracle Big Data Spatial and Graphのプロパティ・グラフ・サポートは、Apache HBaseおよびOracle NoSQL Database用のデータベース固有のAPIを提供します。データ・アクセス・レイヤーAPI (oracle.pg.*)は、Oracle NoSQL DatabaseおよびApache HBaseに格納されているプロパティ・グラフ用のTinkerPop Blueprints API、テキスト検索および索引付けを実装します。

Oracle Big Data Spatial and Graph APIを使用するには、次のクラスをJavaプログラムにインポートします。

import oracle.pg.nosql.*; // or oracle.pg.hbase.*
import oracle.pgx.config.*;
import oracle.pgx.common.types.*;

TinkerPop Blueprints Java APIも含めます。

関連項目:

Oracle Big Data Spatial and Graph Java APIリファレンス

5.4.1.2 TinkerPop Blueprints Java API

TinkerPop Blueprintsはプロパティ・グラフ・データ・モデルをサポートします。このAPIは、主にBig Data Spatial and Graphのデータ・アクセス・レイヤーJava APIを介して使用する、グラフ操作のためのユーティリティを提供します。

Blueprints APIを使用するには、次のクラスをJavaプログラムにインポートします。

import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.Edge;

関連項目:

『Blueprints: A Property Graph Model Interface API』

http://www.tinkerpop.com/docs/javadocs/blueprints/2.3.0/index.html

5.4.1.3 Apache Hadoop Java API

Apache Hadoop Java APIを使用すると、JavaコードをHadoop分散フレームワーク内で実行するMapReduceプログラムとして作成できます。

Hadoop Java APIを使用するには、次のクラスをJavaプログラムにインポートします。次に例を示します。

import org.apache.hadoop.conf.Configuration;

関連項目:

『Apache Hadoop Main 2.5.0-cdh5.3.2 API』

http://archive.cloudera.com/cdh5/cdh/5/hadoop/api/

5.4.1.4 Oracle NoSQL Database Java API

The Oracle NoSQL Database APIを使用すると、キー値(KV)ストアを作成および移入し、Hadoop、HiveおよびOracle NoSQL Databaseへのインタフェースを提供できます。

Oracle NoSQL Databaseをグラフ・データ・ストアとして使用するには、次のクラスをJavaプログラムにインポートします。次に例を示します。

import oracle.kv.*; 
import oracle.kv.table.TableOperation;

関連項目:

Oracle NoSQL Database Java APIリファレンス

http://docs.oracle.com/cd/NOSQL/html/javadoc/

5.4.1.5 Apache HBase Java API

Apache HBase APIを使用すると、キー値ペアを作成および操作できます。

HBaseをグラフ・データ・ストアとして使用するには、次のクラスをJavaプログラムにインポートします。次に例を示します。

import org.apache.hadoop.hbase.*; 
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.*; 
import org.apache.hadoop.hbase.util.Bytes; 
import org.apache.hadoop.conf.Configuration; 

5.4.2 グラフ・データのパラレル・ロード

グラフ・データのパラレル・ロードを実行するために、Java APIが提供されています。

頂点ファイル(または入力ストリーム)のセットとエッジ・ファイル(または入力ストリーム)のセットがある場合、それらを複数のチャンクに分割し、並列でデータベースにロードできます。チャンクの数は、ユーザーが指定した並列度(DOP)によって決定されます。

並列性は、頂点およびエッジ・フラット・ファイルを複数のチャンクに分割するスプリッタ・スレッドと、別個のデータベース接続を使用して各チャンクをデータベースにロードするローダー・スレッドによって実現されます。スプリッタ・スレッドとローダー・スレッドを接続するために、Javaパイプが使用されます -- スプリッタ: PipedOutputStreamおよびローダー: PipedInputStream

データ・ロードAPIの最も単純な使用方法は、1つのプロパティ・グラフ・インスタンス、1つの頂点ファイル、1つのエッジ・ファイルおよびDOPを指定することです。

次のロード・プロセスの例では、最適化されたOracleフラット・ファイル形式の頂点ファイルおよびエッジ・ファイルに格納されたグラフ・データをロードし、並列度48でロードを実行します。

opgdl = OraclePropertyGraphDataLoader.getInstance();
vfile = "../../data/connections.opv";
efile = "../../data/connections.ope";
opgdl.loadData(opg, vfile, efile, 48);
5.4.2.1 パーティションを使用したパラレル・データ・ロード

データ・ロードAPIを使用することにより、複数のパーティションを使用してデータをデータベースにロードできます。このAPIは、プロパティ・グラフ、頂点ファイル、エッジ・ファイル、DOP、パーティション合計数およびパーティション・オフセット(0からパーティション合計数 - 1まで)を必要とします。たとえば、2つのパーティションを使用してデータをロードするには、パーティション・オフセットは0および1である必要があります。つまり、グラフ全体をロードするために2つのデータ・ロードAPIコールがあり、これら2つのAPIコールの相違点は、パーティション・オフセット(0および1)のみになります。

次のコード・フラグメントは、4つのパーティションを使用してグラフ・データをロードします。データ・ローダーの各コールは、単一システム上または複数のシステム上の別々のJavaクライアントを使用して処理できます。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

int totalPartitions = 4;
int dop= 32; // degree of parallelism for each client.

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";
SimpleLogBasedDataLoaderListenerImpl dll = SimpleLogBasedDataLoaderListenerImpl.getInstance(100 /* frequency */,
                                       true /* Continue on error */);

// Run the data loading using 4 partitions (Each call can be run from a
// separate Java Client)

// Partition 1
OraclePropertyGraphDataLoader opgdlP1 = OraclePropertyGraphDataLoader.getInstance();
opgdlP1.loadData(opg, szOPVFile, szOPEFile, dop,  
   4 /* Total number of partitions, default 1 */,
   0 /* Partition to load (from 0 to totalPartitions - 1, default 0 */,
   dll);

// Partition 2
OraclePropertyGraphDataLoader opgdlP2 = OraclePropertyGraphDataLoader.getInstance();
opgdlP2.loadData(opg, szOPVFile, szOPEFile, dop,  4 /* Total number of partitions, default 1 */,
 1 /* Partition to load (from 0 to totalPartitions - 1, default 0 */, dll);


// Partition 3
OraclePropertyGraphDataLoader opgdlP3 = OraclePropertyGraphDataLoader.getInstance();
opgdlP3.loadData(opg, szOPVFile, szOPEFile, dop,  4 /* Total number of partitions, default 1 */,
 2 /* Partition to load (from 0 to totalPartitions - 1, default 0 */, dll);

// Partition 4
OraclePropertyGraphDataLoader opgdlP4 = OraclePropertyGraphDataLoader.getInstance();
opgdlP4.loadData(opg, szOPVFile, szOPEFile, dop,  4 /* Total number of partitions, default 1 */,
 3 /* Partition to load (from 0 to totalPartitions - 1, default 0 */, dll);
5.4.2.2 ファインチューニングを使用したパラレル・データ・ロード

データ・ロードAPIは、ロードされるソース頂点ファイルおよびエッジ・ファイル内のこれらの行のファインチューニングもサポートします。頂点(またはエッジ)オフセット行数と頂点(またはエッジ)最大行数を指定できます。オフセット行数から最大行数までのデータがロードされます。最大行数が-1である場合、ロード・プロセスはファイルの終わりに達するまでデータをスキャンします。

次のコード・フラグメントは、ファインチューニングを使用してグラフ・データをロードします。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

int totalPartitions = 4;
int dop= 32; // degree of parallelism for each client.

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";
SimpleLogBasedDataLoaderListenerImpl dll = SimpleLogBasedDataLoaderListenerImpl.getInstance(100 /* frequency */,
                                       true /* Continue on error */);

// Run the data loading using fine tuning
long lVertexOffsetlines = 0;
long lEdgeOffsetlines = 0;
long lVertexMaxlines = 100;
long lEdgeMaxlines = 100;
int totalPartitions = 1;
int idPartition = 0;

OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile,
 lVertexOffsetlines /* offset of lines to start loading 
 from partition, default 0*/,
 lEdgeOffsetlines /* offset of lines to start loading 
 from partition, default 0*/,
 lVertexMaxlines /* maximum number of lines to start loading 
 from partition, default -1 (all lines in partition)*/,
 lEdgeMaxlines /* maximun number of lines to start loading 
 from partition, default -1 (all lines in partition)*/,
 dop,
 totalPartitions /* Total number of partitions, default 1 */,
 idPartition /* Partition to load (from 0 to totalPartitions - 1, 
 default 0 */,
 dll);
5.4.2.3 複数のファイルを使用したパラレル・データ・ロード

Oracle Big Data Spatial and Graphは、データベースへの複数の頂点ファイルおよび複数のエッジ・ファイルのロードもサポートします。指定された頂点ファイルがDOPチャンクに分割され、DOPスレッドを使用してデータベースに並列にロードされます。同様に、複数のエッジ・ファイルも分割されて、並列にロードされます。

次のコード・フラグメントは、パラレル・データ・ロードAPIを使用して、複数の頂点ファン・ファイルおよびエッジ・ファイルを並列にロードします。この例では、入力ファイルを保持するために2つの文字列配列szOPVFilesおよびszOPEFilesを使用しています。この例では1つの頂点ファイルと1つのエッジ・ファイルのみを使用していますが、これら2つの配列に複数の頂点ファイルと複数のエッジ・ファイルを指定できます。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

String[] szOPVFiles = new String[] {"../../data/connections.opv"};
String[] szOPEFiles = new String[] {"../../data/connections.ope"};

// Clear existing vertices/edges in the property graph 
opg.clearRepository();
opg.setQueueSize(100); // 100 elements

// This object will handle parallel data loading over the property graph
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();

opgdl.loadData(opg, szOPVFiles, szOPEFiles, dop);

System.out.println("Total vertices: " + opg.countVertices());
System.out.println("Total edges: " + opg.countEdges());
5.4.2.4 グラフ・データのパラレル取得

プロパティ・グラフのパラレル問合せは、頂点(またはエッジ)のパラレル・スキャンを実行するための単純なJava APIを提供します。パラレル取得は、バックエンド・データベースとの分割間でのデータの配分を利用する最適化されたソリューションであり、各分割は別個のデータベース接続を使用して問い合せられます。

パラレル取得では、各要素が特定の分割からのすべての頂点(またはエッジ)を保持する配列が生成されます。問い合せられたシャードのサブセットは、特定の開始分割IDと指定された接続の配列のサイズによって分離されます。これにより、サブセットは[開始, 開始 - 1 + 接続の配列のサイズ]の範囲内の分割を考慮します。N分割を含む頂点表にあるすべての分割に、([0, N - 1]の範囲の)整数IDが割り当てられることに注意してください。

次のコードは、Apache HBaseを使用してプロパティ・グラフをロードし、接続の配列を開き、開いた接続を使用してパラレル問合せを実行してすべての頂点およびエッジを取得します。getVerticesPartitioned (getEdgesPartitioned)メソッドの呼出し数は、分割の合計数と使用される接続の数によって制御されます。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

// Clear existing vertices/edges in the property graph 
opg.clearRepository(); 

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";

// This object will handle parallel data loading
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 

// Create connections used in parallel query
HConnection[] hConns= new HConnection[dop];
for (int i = 0; i < dop; i++) { 
Configuration conf_new = 
HBaseConfiguration.create(opg.getConfiguration());
hConns[i] = HConnectionManager.createConnection(conf_new); 
}

long lCountV = 0;
// Iterate over all the vertices��� splits to count all the vertices
for (int split = 0; split < opg.getVertexTableSplits(); 
 split += dop) { 
Iterable<Vertex>[] iterables 
 = opg.getVerticesPartitioned(hConns /* Connection array */, 
 true /* skip store to cache */, 
 split /* starting split */); 
lCountV += consumeIterables(iterables); /* consume iterables using 
 threads */
}

// Count all vertices
System.out.println("Vertices found using parallel query: " + lCountV);

long lCountE = 0;
// Iterate over all the edges��� splits to count all the edges
for (int split = 0; split < opg.getEdgeTableSplits(); 
 split += dop) { 
Iterable<Edge>[] iterables 
 = opg.getEdgesPartitioned(hConns /* Connection array */, 
 true /* skip store to cache */, 
 split /* starting split */); 
lCountE += consumeIterables(iterables); /* consume iterables using 
 threads */
}

// Count all edges
System.out.println("Edges found using parallel query: " + lCountE);

// Close the connections to the database after completed
for (int idx = 0; idx < hConns.length; idx++) { 
hConns[idx].close();
}

Apache HBaseのかわりにOracle NoSQL Database接続を使用してプロパティ・グラフをロードするには、次のコードを使用する必要があります。

// Create connections used in parallel query
hConns = new KVStoreConfig[dop];
kvsc = opg.getKVStoreConfig();

for (i = 0; i < dop; i++) {hConns[i] = kvsc.clone(); }
opg.setNumSplits(dop);
5.4.2.5 サブグラフ抽出のための要素フィルタ・コールバックの使用

Oracle Big Data Spatial and Graphは、ユーザー定義の要素フィルタ・コールバックを使用した、容易なサブグラフ抽出のサポートを提供します。要素フィルタ・コールバックは、サブグラフに頂点(またはエッジ)を保持するために、頂点(またはエッジ)が満たす必要のある条件セットを定義します。ユーザーはVertexFilterCallbackおよびEdgeFilterCallback APIインタフェースを実装することによって、独自の要素フィルタを定義できます。

次のコード・フラグメントは、頂点が政治的役割を持たず、その出生地が米国であるかどうかを検証するVertexFilterCallbackを実装します。

/**
* VertexFilterCallback to retrieve a vertex from the United States 
* that does not have a political role 
*/
private static class NonPoliticianFilterCallback 
implements VertexFilterCallback
{
@Override
public boolean keepVertex(OracleVertexBase vertex) 
{
String country = vertex.getProperty("country");
String role = vertex.getProperty("role");

if (country != null && country.equals("United States")) {
if (role == null || !role.toLowerCase().contains("political")) {
return true;
}
}

return false;
}

public static NonPoliticianFilterCallback getInstance()
{
return new NonPoliticianFilterCallback();
}
}

次のコード・フラグメントは、VertexFilterCallbackを使用して特定の入力頂点に接続しているエッジのうち、その接続が政治家ではなく米国出身であるエッジのみを保持するEdgeFilterCallbackを実装します。

/**
 * EdgeFilterCallback to retrieve all edges connected to an input 
 * vertex with "collaborates" label, and whose vertex is from the 
 * United States with a role different than political
*/
private static class CollaboratorsFilterCallback 
implements EdgeFilterCallback
{
private VertexFilterCallback m_vfc;
private Vertex m_startV;

public CollaboratorsFilterCallback(VertexFilterCallback vfc, 
 Vertex v) 
{
m_vfc = vfc;
m_startV = v; 
}

@Override
public boolean keepEdge(OracleEdgeBase edge) 
{
if ("collaborates".equals(edge.getLabel())) {
if (edge.getVertex(Direction.IN).equals(m_startV) && 
m_vfc.keepVertex((OracleVertex) 
edge.getVertex(Direction.OUT))) {
return true;
}
else if (edge.getVertex(Direction.OUT).equals(m_startV) && 
 m_vfc.keepVertex((OracleVertex) 
edge.getVertex(Direction.IN))) {
return true;
}
}

return false;
}

public static CollaboratorsFilterCallback
getInstance(VertexFilterCallback vfc, Vertex v)
{
return new CollaboratorsFilterCallback(vfc, v);
}

}

前に定義したフィルタ・コールバックを使用して、次のコード・フラグメントは、プロパティ・グラフをロードし、フィルタ・コールバックのインスタンスを作成し、その後に政治家ではなく米国出身であるBarack Obamaのすべての協力者を取得します。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

// Clear existing vertices/edges in the property graph 
opg.clearRepository(); 

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";

// This object will handle parallel data loading
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 

// VertexFilterCallback to retrieve all people from the United States // who are not politicians
NonPoliticianFilterCallback npvfc = NonPoliticianFilterCallback.getInstance();

// Initial vertex: Barack Obama
Vertex v = opg.getVertices("name", "Barack Obama").iterator().next();

// EdgeFilterCallback to retrieve all collaborators of Barack Obama 
// from the United States who are not politicians
CollaboratorsFilterCallback cefc = CollaboratorsFilterCallback.getInstance(npvfc, v);

Iterable<<Edge> obamaCollabs = opg.getEdges((String[])null /* Match any 
of the properties */,
cefc /* Match the 
EdgeFilterCallback */
);
Iterator<<Edge> iter = obamaCollabs.iterator();

System.out.println("\n\n--------Collaborators of Barack Obama from " +
 " the US and non-politician\n\n");
long countV = 0;
while (iter.hasNext()) {
Edge edge = iter.next(); // get the edge
// check if obama is the IN vertex
if (edge.getVertex(Direction.IN).equals(v)) {
 System.out.println(edge.getVertex(Direction.OUT) + "(Edge ID: " + 
 edge.getId() + ")"); // get out vertex
}
else {
System.out.println(edge.getVertex(Direction.IN)+ "(Edge ID: " + 
 edge.getId() + ")"); // get in vertex
}

countV++;
}

デフォルトでは、すべての頂点の取得、すべてのエッジの取得(および並列アプローチ)などのすべての読取り操作は、opg.setVertexFilterCallback(vfc)およびopg.setEdgeFilterCallback(efc)メソッドを使用してプロパティ・グラフに関連付けられたフィルタ・コールバックを使用します。フィルタ・コールバック・セットがない場合は、すべての頂点(またはエッジ)およびエッジが取得されます。

次のコード・フラグメントは、プロパティ・グラフでデフォルトのエッジ・フィルタ・コールバック・セットを使用して、エッジを取得します。

// VertexFilterCallback to retrieve all people from the United States // who are not politicians
NonPoliticianFilterCallback npvfc = NonPoliticianFilterCallback.getInstance();

// Initial vertex: Barack Obama
Vertex v = opg.getVertices("name", "Barack Obama").iterator().next();

// EdgeFilterCallback to retrieve all collaborators of Barack Obama 
// from the United States who are not politicians
CollaboratorsFilterCallback cefc = CollaboratorsFilterCallback.getInstance(npvfc, v);

opg.setEdgeFilterCallback(cefc);

Iterable<Edge> obamaCollabs = opg.getEdges();
Iterator<Edge> iter = obamaCollabs.iterator();

System.out.println("\n\n--------Collaborators of Barack Obama from " +
 " the US and non-politician\n\n");
long countV = 0;
while (iter.hasNext()) {
Edge edge = iter.next(); // get the edge
// check if obama is the IN vertex
if (edge.getVertex(Direction.IN).equals(v)) {
 System.out.println(edge.getVertex(Direction.OUT) + "(Edge ID: " + 
 edge.getId() + ")"); // get out vertex
}
else {
System.out.println(edge.getVertex(Direction.IN)+ "(Edge ID: " + 
 edge.getId() + ")"); // get in vertex
}

countV++;
}
5.4.2.6 プロパティ・グラフ・データの読取りでの最適化フラグの使用

最適化フラグを使用すると、グラフ反復のパフォーマンスを向上させることができます。最適化フラグにより、情報がない、または最小限の情報(ID、ラベルおよび入力/出力頂点など)を持つオブジェクトとして、頂点(またはエッジ)を処理できます。これにより、反復中の各頂点またはエッジの処理にかかる時間が削減されます。

次の表に、プロパティ・グラフで頂点またはエッジを処理するときに使用できる最適化フラグを示します。

表5-1 プロパティ・グラフで頂点またはエッジを処理するための最適化フラグ

最適化フラグ 説明
DO_NOT_CREATE_OBJECT 頂点またはエッジを処理するときに、事前定義済の定数オブジェクトを使用します。
JUST_EDGE_ID エッジの処理時に、IDのみを持つエッジ・オブジェクトを作成します。
JUST_LABEL_EDGE_ID エッジの処理時に、IDとラベルのみを持つエッジ・オブジェクトを作成します。
JUST_LABEL_VERTEX_EDGE_ID エッジの処理時に、ID、ラベルおよび入力/出力頂点IDのみを持つエッジ・オブジェクトを作成します。
JUST_VERTEX_EDGE_ID エッジの処理時に、IDおよび入力/出力頂点IDのみを持つエッジ・オブジェクトを作成します。
JUST_VERTEX_ID 頂点の処理時に、IDのみを持つ頂点オブジェクトを作成します。

次のコード・フラグメントは、最適化フラグのセットを使用して、プロパティ・グラフの頂点およびエッジからすべてのIDのみを取得します。すべての頂点およびエッジの読取りによって取得されたオブジェクトには、IDのみが含まれ、キー/値プロパティや追加情報は含まれません。

import oracle.pg.common.OraclePropertyGraphBase.OptimizationFlag;
OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

// Clear existing vertices/edges in the property graph 
opg.clearRepository(); 

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";

// This object will handle parallel data loading
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 


// Optimization flag to retrieve only vertices IDs
OptimizationFlag optFlagVertex = OptimizationFlag.JUST_VERTEX_ID;

// Optimization flag to retrieve only edges IDs
OptimizationFlag optFlagEdge = OptimizationFlag.JUST_EDGE_ID;

// Print all vertices
Iterator<Vertex> vertices = 
opg.getVertices((String[])null /* Match any of the 
properties */,
null /* Match the VertexFilterCallback */, 
optFlagVertex /* optimization flag */ 
).iterator();

System.out.println("----- Vertices IDs----");
long vCount = 0;
while (vertices.hasNext()) {
OracleVertex v = vertices.next();
System.out.println((Long) v.getId());
vCount++;
}
System.out.println("Vertices found: " + vCount);

// Print all edges
Iterator<Edge> edges =
opg.getEdges((String[])null /* Match any of the properties */,
null /* Match the EdgeFilterCallback */, 
optFlagEdge /* optimization flag */ 
).iterator();

System.out.println("----- Edges ----");
long eCount = 0;
while (edges.hasNext()) {
Edge e = edges.next();
System.out.println((Long) e.getId());
eCount++;
}
System.out.println("Edges found: " + eCount);

デフォルトでは、すべての頂点の取得、すべてのエッジの取得(および並列アプローチ)などのすべての読取り操作は、opg.setDefaultVertexOptFlag(optFlagVertex)およびopg.setDefaultEdgeOptFlag(optFlagEdge)メソッドを使用してプロパティ・グラフに関連付けられた最適化フラグを使用します。頂点またはエッジの処理に対する最適化フラグが定義されていない場合、頂点およびエッジに関するすべての情報が取得されます。

次のコード・フラグメントは、プロパティ・グラフでデフォルト最適化フラグのセットを使用して、その頂点およびエッジからすべてのIDのみを取得します。

import oracle.pg.common.OraclePropertyGraphBase.OptimizationFlag;

// Optimization flag to retrieve only vertices IDs
OptimizationFlag optFlagVertex = OptimizationFlag.JUST_VERTEX_ID;

// Optimization flag to retrieve only edges IDs
OptimizationFlag optFlagEdge = OptimizationFlag.JUST_EDGE_ID;

opg.setDefaultVertexOptFlag(optFlagVertex);
opg.setDefaultEdgeOptFlag(optFlagEdge);

Iterator<Vertex> vertices = opg.getVertices().iterator();
System.out.println("----- Vertices IDs----");
long vCount = 0;
while (vertices.hasNext()) {
OracleVertex v = vertices.next();
System.out.println((Long) v.getId());
vCount++;
}
System.out.println("Vertices found: " + vCount);

// Print all edges
Iterator<Edge> edges = opg.getEdges().iterator();
System.out.println("----- Edges ----");
long eCount = 0;
while (edges.hasNext()) {
Edge e = edges.next();
System.out.println((Long) e.getId());
eCount++;
}
System.out.println("Edges found: " + eCount);
5.4.2.7 プロパティ・グラフのサブグラフの属性の追加および削除

Oracle Big Data Spatial and Graphは、ユーザーがカスタマイズした操作コールバックを使用した、頂点またはエッジ(あるいはその両方)のサブグラフへの属性(キー/値ペア)の更新をサポートします。操作コールバックは、(特定の属性および値を追加または削除することによって)頂点(またはエッジ)を更新するために、頂点(またはエッジ)が満たす必要のある条件セットを定義します。

VertexOpCallbackおよびEdgeOpCallback APIインタフェースを実装することにより、独自の属性操作を定義できます。更新操作に含まれる頂点(またはエッジ)によって満たされる必要のある条件を定義するneedOpメソッド、および要素の更新時に使用されるキー名とキー値をそれぞれ返すgetAttributeKeyNameメソッドとgetAttributeKeyValueメソッドをオーバーライドする必要があります。

次のコード・フラグメントは、Barack Obamaの協力者のみに関連付けられたobamaCollaborator属性を操作するVertexOpCallbackを実装します。このプロパティの値は、協力者の役職に基づいて指定されます。

private static class CollaboratorsVertexOpCallback 
implements VertexOpCallback
{
private OracleVertexBase m_obama;
private List<Vertex> m_obamaCollaborators;

public CollaboratorsVertexOpCallback(OraclePropertyGraph opg)
{
// Get a list of Barack Obama'sCollaborators
m_obama = (OracleVertexBase) opg.getVertices("name", 
 "Barack Obama")
.iterator().next();

Iterable<Vertex> iter = m_obama.getVertices(Direction.BOTH, 
"collaborates");
m_obamaCollaborators = OraclePropertyGraphUtils.listify(iter);
}

public static CollaboratorsVertexOpCallback 
getInstance(OraclePropertyGraph opg)
{
return new CollaboratorsVertexOpCallback(opg);
}

/**
 * Add attribute if and only if the vertex is a collaborator of Barack 
 * Obama
*/
@Override
public boolean needOp(OracleVertexBase v)
{
return m_obamaCollaborators != null && 
 m_obamaCollaborators.contains(v);
}

@Override
public String getAttributeKeyName(OracleVertexBase v)
{
return "obamaCollaborator";
}

/**
 * Define the property's value based on the vertex role
 */
@Override
public Object getAttributeKeyValue(OracleVertexBase v)
{
String role = v.getProperty("role");
role = role.toLowerCase();
if (role.contains("political")) {
return "political";
}
else if (role.contains("actor") || role.contains("singer") ||
 role.contains("actress") || role.contains("writer") ||
 role.contains("producer") || role.contains("director")) {
return "arts";
}
else if (role.contains("player")) {
return "sports";
}
else if (role.contains("journalist")) {
return "journalism";
}
else if (role.contains("business") || role.contains("economist")) {
return "business";
}
else if (role.contains("philant")) {
return "philanthropy";
}
return " ";
}
}

次のコード・フラグメントは、Barack Obamaの敵対者のみに関連付けられたobamaFeud属性を操作するEdgeOpCallbackを実装します。このプロパティの値は、協力者の役職に基づいて指定されます。

private static class FeudsEdgeOpCallback 
implements EdgeOpCallback
{
private OracleVertexBase m_obama;
private List<Edge> m_obamaFeuds;

public FeudsEdgeOpCallback(OraclePropertyGraph opg)
{
// Get a list of Barack Obama's feuds
m_obama = (OracleVertexBase) opg.getVertices("name", 
 "Barack Obama")
.iterator().next();

Iterable<Edge> iter = m_obama.getEdges(Direction.BOTH, 
"feuds");
m_obamaFeuds = OraclePropertyGraphUtils.listify(iter);
}

public static FeudsEdgeOpCallback getInstance(OraclePropertyGraph opg)
{
return new FeudsEdgeOpCallback(opg);
}

/**
 * Add attribute if and only if the edge is in the list of Barack Obama's 
 * feuds
*/
@Override
public boolean needOp(OracleEdgeBase e)
{
return m_obamaFeuds != null && m_obamaFeuds.contains(e);
}

@Override
public String getAttributeKeyName(OracleEdgeBase e)
{
return "obamaFeud";
}

/**
 * Define the property's value based on the in/out vertex role
 */
@Override
public Object getAttributeKeyValue(OracleEdgeBase e)
{
OracleVertexBase v = (OracleVertexBase) e.getVertex(Direction.IN);
if (m_obama.equals(v)) {
v = (OracleVertexBase) e.getVertex(Direction.OUT);
}
String role = v.getProperty("role");
role = role.toLowerCase();

if (role.contains("political")) {
return "political";
}
else if (role.contains("actor") || role.contains("singer") ||
 role.contains("actress") || role.contains("writer") ||
 role.contains("producer") || role.contains("director")) {
return "arts";
}
else if (role.contains("journalist")) {
return "journalism";
}
else if (role.contains("player")) {
return "sports";
}
else if (role.contains("business") || role.contains("economist")) {
return "business";
}
else if (role.contains("philanthropist")) {
return "philanthropy";
}
return " ";
}
}

前に定義した操作コールバックを使用して、次のコード・フラグメントはプロパティ・グラフをロードし、操作コールバックのインスタンスを作成し、その後にOraclePropertyGraphaddAttributeToAllVerticesおよびaddAttributeToAllEdgesメソッドを使用して属性を適切な頂点およびエッジに追加します。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

// Clear existing vertices/edges in the property graph 
opg.clearRepository(); 

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";

// This object will handle parallel data loading
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 

// Create the vertex operation callback
CollaboratorsVertexOpCallback cvoc = CollaboratorsVertexOpCallback.getInstance(opg);

// Add attribute to all people collaborating with Obama based on their role
opg.addAttributeToAllVertices(cvoc, true /** Skip store to Cache */, dop);

// Look up for all collaborators of Obama
// The function getVerticesAsString prints the vertices in the given iterable
Iterable<Vertex> collaborators = opg.getVertices("obamaCollaborator", "political");
System.out.println("Political collaborators of Barack Obama " + getVerticesAsString(collaborators));

collaborators = opg.getVertices("obamaCollaborator", "business");
System.out.println("Business collaborators of Barack Obama " + 
getVerticesAsString(collaborators));

// Add an attribute to all people having a feud with Barack Obama to set
// the type of relation they have
FeudsEdgeOpCallback feoc = FeudsEdgeOpCallback.getInstance(opg);
opg.addAttributeToAllEdges(feoc, true /** Skip store to Cache */, dop);

// Look up for all feuds of Obama
// The function getEdgesAsString prints the edges in the given iterable
Iterable<Edge> feuds = opg.getEdges("obamaFeud", "political");
System.out.println("\n\nPolitical feuds of Barack Obama " + getEdgesAsString(feuds));

feuds = opg.getEdges("obamaFeud", "business");
System.out.println("Business feuds of Barack Obama " + 
getEdgesAsString(feuds));

次のコード・フラグメントは、属性obamaCollaboratorにphilanthropyという値を持つ頂点を削除した後でAPI removeAttributeFromAllVerticesをコールするために使用できるVertexOpCallbackの実装を定義します。また、属性obamaFeudにbusinessという値を持つエッジを削除した後でAPI removeAttributeFromAllEdgesをコールするために使用できるEdgeOpCallbackの実装も定義します。

System.out.println("\n\nRemove 'obamaCollaborator' property from all the" + 
 "philanthropy collaborators");
PhilanthropyCollaboratorsVertexOpCallback pvoc = PhilanthropyCollaboratorsVertexOpCallback.getInstance();

opg.removeAttributeFromAllVertices(pvoc);

System.out.println("\n\nRemove 'obamaFeud' property from all the" + "business feuds");
BusinessFeudsEdgeOpCallback beoc = BusinessFeudsEdgeOpCallback.getInstance();

opg.removeAttributeFromAllEdges(beoc);

/**
 * Implementation of a EdgeOpCallback to remove the "obamaCollaborators" 
 * property from all people collaborating with Barack Obama that have a 
 * philanthropy role
 */
private static class PhilanthropyCollaboratorsVertexOpCallback implements VertexOpCallback
{
  public static PhilanthropyCollaboratorsVertexOpCallback getInstance()
  {
     return new PhilanthropyCollaboratorsVertexOpCallback();
  }
  
  /**
   * Remove attribute if and only if the property value for   
   * obamaCollaborator is Philanthropy
   */
  @Override
  public boolean needOp(OracleVertexBase v)
  {
    String type = v.getProperty("obamaCollaborator");
    return type != null && type.equals("philanthropy");
  }

  @Override
  public String getAttributeKeyName(OracleVertexBase v)
  {
    return "obamaCollaborator";
  }

  /**
   * Define the property's value. In this case can be empty
   */
  @Override
  public Object getAttributeKeyValue(OracleVertexBase v)
  {
    return " ";
  }
}

/**
 * Implementation of a EdgeOpCallback to remove the "obamaFeud" property
 * from all connections in a feud with Barack Obama that have a business role
 */
private static class BusinessFeudsEdgeOpCallback implements EdgeOpCallback
{
  public static BusinessFeudsEdgeOpCallback getInstance()
  {
    return new BusinessFeudsEdgeOpCallback();
  }

  /**
   * Remove attribute if and only if the property value for obamaFeud is       
   * business
   */
  @Override
  public boolean needOp(OracleEdgeBase e)
  {
    String type = e.getProperty("obamaFeud");
    return type != null && type.equals("business");
  }

 @Override
 public String getAttributeKeyName(OracleEdgeBase e)
 {
   return "obamaFeud";
 }

 /**
  * Define the property's value. In this case can be empty
  */
  @Override
  public Object getAttributeKeyValue(OracleEdgeBase e)
  {
    return " ";
  }
}
5.4.2.8 プロパティ・グラフ・メタデータの取得

データベース内のすべてのグラフ名など、グラフのメタデータと統計を取得できます。各グラフについて、最小/最大頂点ID、最小/最大エッジID、頂点プロパティ名、エッジ・プロパティ名、グラフ頂点内の分割の数、およびパラレル表スキャンをサポートするエッジ表などを取得します。

次のコード・フラグメントは、バックエンド・データベース(Oracle NoSQL DatabaseまたはApache HBase)に格納されている既存のプロパティ・グラフのメタデータおよび統計を取得します。必要な引数は、各データベースで異なります。

// Get all graph names in the database
List<String> graphNames = OraclePropertyGraphUtils.getGraphNames(dbArgs);

for (String graphName : graphNames) {
OraclePropertyGraph opg = OraclePropertyGraph.getInstance(args, 
graphName);

System.err.println("\n Graph name: " + graphName);
System.err.println(" Total vertices: " + 
 opg.countVertices(dop));
 
System.err.println(" Minimum Vertex ID: " + 
 opg.getMinVertexID(dop));
System.err.println(" Maximum Vertex ID: " + 
 opg.getMaxVertexID(dop));

// The function getPropertyNamesAsString prints the given set of properties
Set<String> propertyNamesV = new HashSet<String>();
opg.getVertexPropertyNames(dop, 0 /* timeout,0 no timeout */,
 propertyNamesV);

System.err.println(" Vertices property names: " + 
getPropertyNamesAsString(propertyNamesV));

System.err.println("\n\n Total edges: " + opg.countEdges(dop));
System.err.println(" Minimum Edge ID: " + opg.getMinEdgeID(dop));
System.err.println(" Maximum Edge ID: " + opg.getMaxEdgeID(dop));

Set<String> propertyNamesE = new HashSet<String>();
opg.getEdgePropertyNames(dop, 0 /* timeout,0 no timeout */, 
 propertyNamesE);

System.err.println(" Edge property names: " +
getPropertyNamesAsString(propertyNamesE));

System.err.println("\n\n Table Information: ");
System.err.println("Vertex table number of splits: " + 
 (opg.getVertexTableSplits()));
System.err.println("Edge table number of splits: " + 
 (opg.getEdgeTableSplits()));
}

5.4.3 プロパティ・グラフ・インスタンスのオープンおよびクローズ

プロパティ・グラフを記述する際、次のOracle Property Graphクラスを使用して、プロパティ・グラフ・インスタンスを適切にオープンおよびクローズします。

  • OraclePropertyGraph.getInstance: Oracleプロパティ・グラフのインスタンスをオープンします。このメソッドには、接続情報とグラフ名の2つのパラメータがあります。接続情報のフォーマットは、バックエンド・データベースとしてHBaseまたはOracle NoSQL Databaseのいずれを使用しているかによって異なります。

  • OraclePropertyGraph.clearRepository: プロパティ・グラフ・インスタンスからすべての頂点およびエッジを削除します。

  • OraclePropertyGraph.shutdown: グラフ・インスタンスをクローズします。

さらに、Oracle NoSQL DatabaseまたはHBase APIからの適切なクラスを使用する必要があります。

5.4.3.1 Oracle NoSQL Databaseの使用

Oracle NoSQL Databaseでは、OraclePropertyGraph.getInstanceメソッドはKVストア名、ホスト・コンピュータ名およびポート番号を接続に使用します。

String kvHostPort = "cluster02:5000";
String kvStoreName = "kvstore";
String kvGraphName = "my_graph";

// Use NoSQL Java API
KVStoreConfig kvconfig = new KVStoreConfig(kvStoreName, kvHostPort);

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(kvconfig, kvGraphName);
opg.clearRepository(); 
//     .
//     .  Graph description
//     .
// Close the graph instance
opg.shutdown();

アプリケーションでインメモリー・アナリスト機能が必要な場合、GraphConfigBuilderを使用してOracle NoSQL Databaseに対してグラフconfigを作成し、引数としてconfigを指定してOraclePropertyGraphをインスタンス化することをお薦めします。

例として、次のコード・スニペットはグラフconfigを作成し、OraclePropertyGraphインスタンスを取得し、いくつかのデータをそのグラフにロードして、インメモリー・アナリストを取得します。

  import oracle.pgx.config.*;
  import oracle.pgx.api.*;
  import oracle.pgx.common.types.*;

    ...
 
    String[] hhosts = new String[1];
    hhosts[0]          = "my_host_name:5000"; // need customization
    String szStoreName =  "kvstore";          // need customization
    String szGraphName = "my_graph";
    int dop            =  8;
 
    PgNosqlGraphConfig cfg = GraphConfigBuilder.forPropertyGraphNosql()
                                                     .setName(szGraphName)
                                                     .setHosts(Arrays.asList(hhosts))
                                                     .setStoreName(szStoreName)
                                                     .addEdgeProperty("lbl", PropertyType.STRING, "lbl")
                                                     .addEdgeProperty("weight", PropertyType.DOUBLE, "1000000")
                                                     .build();
 
    OraclePropertyGraph opg = OraclePropertyGraph.getInstance(cfg);  
 
    String szOPVFile = "../../data/connections.opv";
    String szOPEFile = "../../data/connections.ope";
 
    // perform a parallel data load
    OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
    opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 
 
    ...
    PgxSession session = Pgx.createSession("session-id-1");
    PgxGraph g = session.readGraphWithProperties(cfg);

    Analyst analyst = session.createAnalyst();
    ...
5.4.3.2 Apache HBaseの使用

Apache HBaseでは、OraclePropertyGraph.getInstanceメソッドはHadoopノードとApache HBaseポート番号を接続に使用します。

String hbQuorum = "bda01node01.example.com, bda01node02.example.com, bda01node03.example.com";
String hbClientPort = "2181"
String hbGraphName = "my_graph";
 
// Use HBase Java APIs
Configuration conf = HBaseConfiguration.create();
  conf.set("hbase.zookeeper.quorum", hbQuorum);
  conf.set("hbase.zookeper.property.clientPort", hbClientPort);
HConnection conn = HConnectionManager.createConnection(conf);
 
// Open the property graph
OraclePropertyGraph opg = OraclePropertyGraph.getInstance(conf, conn, hbGraphName);
opg.clearRepository(); 
//     .
//     .  Graph description
//     .
// Close the graph instance
opg.shutdown();
// Close the HBase connection
conn.close();

アプリケーションでインメモリー・アナリスト機能が必要な場合、GraphConfigBuilderを使用してグラフconfigを作成し、引数としてconfigを指定してOraclePropertyGraphをインスタンス化することをお薦めします。

例として、次のコード・スニペットはインメモリー分析の構成を設定し、Apache HBaseに対してグラフconfigを作成し、OraclePropertyGraphインスタンスをインスタンス化し、インメモリー・アナリストを取得して、グラフ内のトライアングルの数をカウントします。

    confPgx = new HashMap<PgxConfig.Field, Object>(); 
    confPgx.put(PgxConfig.Field.ENABLE_GM_COMPILER, false); 
    confPgx.put(PgxConfig.Field.NUM_WORKERS_IO, dop + 2); 
    confPgx.put(PgxConfig.Field.NUM_WORKERS_ANALYSIS, 8); // <= # of physical cores 
    confPgx.put(PgxConfig.Field.NUM_WORKERS_FAST_TRACK_ANALYSIS, 2); 
    confPgx.put(PgxConfig.Field.SESSION_TASK_TIMEOUT_SECS, 0);// no timeout set 
    confPgx.put(PgxConfig.Field.SESSION_IDLE_TIMEOUT_SECS, 0);  // no timeout set 
    ServerInstance instance = Pgx.getInstance();
    instance.startEngine(confPgx); 
 
int iClientPort = Integer.parseInt(hbClientPort);
int splitsPerRegion = 2;
 
PgHbaseGraphConfig cfg = GraphConfigBuilder.forPropertyGraphHbase()
                           .setName(hbGraphName)
                           .setZkQuorum(hbQuorum)
                           .setZkClientPort(iClientPort)
                           .setZkSessionTimeout(60000)
                           .setMaxNumConnections(dop)
                           .setSplitsPerRegion(splitsPerRegion)
                           .addEdgeProperty("lbl", PropertyType.STRING, "lbl")
                           .addEdgeProperty("weight", PropertyType.DOUBLE, "1000000")
                           .build();

PgxSession session = Pgx.createSession("session-id-1");
PgxGraph g = session.readGraphWithProperties(cfg);
Analyst analyst = session.createAnalyst();

long triangles = analyst.countTriangles(g, false);

5.4.4 頂点の作成

頂点を作成するには、次のOracle Property Graphメソッドを使用します。

  • OraclePropertyGraph.addVertex: グラフに頂点インスタンスを追加します。

  • OracleVertex.setProperty: 頂点にキー値プロパティを割り当てます。

  • OraclePropertyGraph.commit: すべての変更をプロパティ・グラフ・インスタンスに保存します。

次のコード・フラグメントは、opgプロパティ・グラフ・インスタンスに年齢、名前、体重、身長、性別のプロパティを指定して、V1およびV2という名前の2つの頂点を作成します。v1プロパティはデータ型を明示的に設定します。

// Create vertex v1 and assign it properties as key-value pairs
Vertex v1 = opg.addVertex(1l);
  v1.setProperty("age",  Integer.valueOf(31));
  v1.setProperty("name", "Alice");
  v1.setProperty("weight", Float.valueOf(135.0f));
  v1.setProperty("height", Double.valueOf(64.5d));
  v1.setProperty("female", Boolean.TRUE);
  
Vertex v2 = opg.addVertex(2l);
  v2.setProperty("age",  27);
  v2.setProperty("name", "Bob");
  v2.setProperty("weight", Float.valueOf(156.0f));
  v2.setProperty("height", Double.valueOf(69.5d));
  v2.setProperty("female", Boolean.FALSE); 

5.4.5 エッジの作成

エッジを作成するには、次のOracle Property Graphメソッドを使用します。

  • OraclePropertyGraph.addEdge: グラフにエッジ・インスタンスを追加します。

  • OracleEdge.setProperty: エッジにキー値プロパティを割り当てます。

次のコード・フラグメントは、2つの頂点(v1およびv2)と1つのエッジ(e1)を作成します。

// Add vertices v1 and v2
Vertex v1 = opg.addVertex(1l);
v1.setProperty("name", "Alice");
v1.setProperty("age", 31);

Vertex v2 = opg.addVertex(2l);  
v2.setProperty("name", "Bob");
v2.setProperty("age", 27);

// Add edge e1
Edge e1 = opg.addEdge(1l, v1, v2, "knows");
e1.setProperty("type", "friends");

5.4.6 頂点およびエッジの削除

頂点インスタンスとエッジ・インスタンスを個別に、またはすべて同時に削除できます。次のメソッドを使用します。

  • OraclePropertyGraph.removeEdge: 指定されたエッジをグラフから削除します。

  • OraclePropertyGraph.removeVertex: 指定された頂点をグラフから削除します。

  • OraclePropertyGraph.clearRepository: プロパティ・グラフ・インスタンスからすべての頂点およびエッジを削除します。

次のコード・フラグメントは、グラフ・インスタンスからエッジe1と頂点v1を削除します。頂点を削除するときに、隣接するエッジもグラフから削除されます。これは、すべてのエッジは開始頂点と終了頂点を持っている必要があるためです。開始頂点または終了頂点を削除した後、そのエッジは有効なエッジではなくなります。

// Remove edge e1
opg.removeEdge(e1);

// Remove vertex v1
opg.removeVertex(v1);

OraclePropertyGraphインスタンスからすべてのコンテンツを削除するには、OraclePropertyGraph.clearRepositoryメソッドを使用できます。ただし、この操作は元に戻せないため、慎重に使用してください。

5.4.7 データベースから埋込みインメモリー・アナリストへのグラフの読込み

Apache HBaseまたはOracle NoSQL Databaseから、同じクライアントJavaアプリケーション(単一のJVM)に埋め込まれたインメモリー・アナリストにグラフを読み込むことができます。次のApache HBaseの例の場合:

  • 正しいjava.io.tmpdir設定が必要です。

  • dop + 2は、リリース1.1.2よりも前のパフォーマンスの問題に対処する方法です。リリース1.1.2で有効ですが、かわりにdop値を構成設定に直接指定できます。

int dop = 8;                    // need customization
Map<PgxConfig.Field, Object> confPgx = new HashMap<PgxConfig.Field, Object>();
confPgx.put(PgxConfig.Field.ENABLE_GM_COMPILER, false);
confPgx.put(PgxConfig.Field.NUM_WORKERS_IO, dop + 2);   // use dop directly with release 1.1.2 or newer
confPgx.put(PgxConfig.Field.NUM_WORKERS_ANALYSIS, dop); // <= # of physical cores
confPgx.put(PgxConfig.Field.NUM_WORKERS_FAST_TRACK_ANALYSIS, 2);
confPgx.put(PgxConfig.Field.SESSION_TASK_TIMEOUT_SECS, 0);  // no timeout set
confPgx.put(PgxConfig.Field.SESSION_IDLE_TIMEOUT_SECS, 0);  // no timeout set

PgHbaseGraphConfig cfg = GraphConfigBuilder.forPropertyGraphHbase()
                          .setName("mygraph")
                          .setZkQuorum("localhost") // quorum, need customization
                          .setZkClientPort(2181)
                          .addNodeProperty("name", PropertyType.STRING, "default_name")
                          .build();

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(cfg);
ServerInstance localInstance = Pgx.getInstance();
localInstance.startEngine(confPgx);
PgxSession session = localInstance.createSession("session-id-1"); // Put your session description here.

Analyst analyst = session.createAnalyst();

// The following call will trigger a read of graph data from the database
PgxGraph pgxGraph = session.readGraphWithProperties(opg.getConfig());

long triangles = analyst.countTriangles(pgxGraph, false);
System.out.println("triangles " + triangles);
// After reading a graph in memory, modifying the graph on the database side should not affect in memory results:
// Remove edge e1
opg.removeEdge(e1);

// Remove vertex v1
opg.removeVertex(v1);

5.4.8 頂点のラベルの指定

「プロパティ・グラフとは」で説明されているように、データベースおよびデータ・アクセス・レイヤーには、頂点用のラベルは用意されていません。ただし、指定した頂点プロパティの値を1つ以上のラベルとして扱うことができます。このような変換が関連するのは、インメモリー・アナリストの場合のみです。

次の例では、プロパティ"country"がsetUseVertexPropertyValueAsLabel()への呼出しに指定されており、カンマ区切り","がsetPropertyValueDelimiter()への呼出しに指定されています。これら2つをまとめると、country頂点プロパティの値がカンマ区切りの頂点ラベルとして扱われることを意味します。たとえば、頂点Xの国プロパティの文字列値が"US"である場合、頂点ラベルはUSになり、頂点Yの文字列値が"UK,CN"である場合、2つのラベルUKおよびCNを持ちます。

GraphConfigBuilder.forPropertyGraph... 
   .setName("<your_graph_name>")
   ...
  .setUseVertexPropertyValueAsLabel("country")
  .setPropertyValueDelimiter(",")
  .build();

5.4.9 インメモリー・グラフの構築

「グラフ・データのメモリーへの読込み」以外にも、インメモリー・グラフをプログラムで作成できます。これにより、グラフのサイズが小さい場合やグラフのコンテンツが非常に動的である場合、開発を簡略化できます。主要なJavaクラスは、addVertexおよびaddEdge APIを使用して追加された頂点とエッジのセットを累計できるGraphBuilderです。すべての変更が行われた後、GraphBuilderによってインメモリー・グラフ・インスタンス(PgxGraph)を作成できます。

次のJavaコード・スニペットは、グラフの構築フローを示します。まだ存在していない頂点は隣接するエッジが作成されるときに動的に追加されるため、addVertexに対する明示的な呼出しはありません。

import oracle.pgx.api.*;

PgxSession session = Pgx.createSession("example");
GraphBuilder<Integer> builder = session.newGraphBuilder();

builder.addEdge(0, 1, 2);
builder.addEdge(1, 2, 3);
builder.addEdge(2, 2, 4);
builder.addEdge(3, 3, 4);
builder.addEdge(4, 4, 2);

PgxGraph graph = builder.build();

頂点プロパティを使用してグラフを構築するには、作成された頂点オブジェクトに対してsetPropertyを使用できます。

PgxSession session = Pgx.createSession("example");
GraphBuilder<Integer> builder = session.newGraphBuilder();

builder.addVertex(1).setProperty("double-prop", 0.1);
builder.addVertex(2).setProperty("double-prop", 2.0);
builder.addVertex(3).setProperty("double-prop", 0.3);
builder.addVertex(4).setProperty("double-prop", 4.56789);

builder.addEdge(0, 1, 2);
builder.addEdge(1, 2, 3);
builder.addEdge(2, 2, 4);
builder.addEdge(3, 3, 4);
builder.addEdge(4, 4, 2);

PgxGraph graph = builder.build();

頂点およびエッジ識別子としてLong整数を使用するには、GraphBuilderの新しいインスタンスの取得時にIdType.LONGを指定します。次に例を示します。

import oracle.pgx.common.types.IdType;
GraphBuilder<Long> builder = session.newGraphBuilder(IdType.LONG);

エッジの構築時に、addEdgeへの呼出しで前に作成した頂点オブジェクトを直接使用できます。

v1 = builder.addVertex(1l).setProperty("double-prop", 0.5)
v2 = builder.addVertex(2l).setProperty("double-prop", 2.0)

builder.addEdge(0, v1, v2)

頂点の場合と同じように、エッジもプロパティを持つことができます。次の例では、setLabelを使用してエッジ・ラベルを設定します。

builder.addEdge(4, v4, v2).setProperty("edge-prop", "edge_prop_4_2").setLabel("label")

5.4.10 プロパティ・グラフの削除

データベースからプロパティ・グラフを削除するには、OraclePropertyGraphUtils.dropPropertyGraphメソッドを使用します。このメソッドには、接続情報とグラフ名の2つのパラメータがあります。

接続情報のフォーマットは、バックエンド・データベースとしてHBaseまたはOracle NoSQL Databaseのいずれを使用しているかによって異なります。これは、OraclePropertyGraph.getInstanceに指定する接続情報と同じです。

5.4.10.1 Oracle NoSQL Databaseの使用

Oracle NoSQL Databaseでは、OraclePropertyGraphUtils.dropPropertyGraphメソッドはKVストア名、ホスト・コンピュータ名およびポート番号を接続に使用します。このコード・フラグメントは、my_graphという名前のグラフをOracle NoSQL Databaseから削除します。

String kvHostPort = "cluster02:5000";
String kvStoreName = "kvstore";
String kvGraphName = "my_graph";

// Use NoSQL Java API
KVStoreConfig kvconfig = new KVStoreConfig(kvStoreName, kvHostPort);

// Drop the graph
OraclePropertyGraphUtils.dropPropertyGraph(kvconfig, kvGraphName);
5.4.10.2 Apache HBaseの使用

Apache HBaseでは、OraclePropertyGraphUtils.dropPropertyGraphメソッドはHadoopノードとApache HBaseポート番号を接続に使用します。このコード・フラグメントは、my_graphという名前のグラフをApache HBaseから削除します。

String hbQuorum = "bda01node01.example.com, bda01node02.example.com, bda01node03.example.com";
String hbClientPort = "2181";
String hbGraphName = "my_graph";
 
// Use HBase Java APIs
Configuration conf = HBaseConfiguration.create();
    conf.set("hbase.zookeeper.quorum", hbQuorum);
    conf.set("hbase.zookeper.property.clientPort", hbClientPort);
 
// Drop the graph
OraclePropertyGraphUtils.dropPropertyGraph(conf, hbGraphName);

5.5 プロパティ・グラフ・データのテキスト索引付けの管理

Oracle Big Data Spatial and Graphの索引付けは、特定のキー/値またはキー/テキスト・ペア別に要素を高速に読み取ることを可能にします。これらの索引は、要素タイプ(頂点またはエッジ)、キー(および値)のセットおよび索引タイプに基づいて作成されます。

Oracle Big Data Spatial and Graphは、手動と自動の2つのタイプの索引付け構造をサポートしています。

  • 自動テキスト索引は、プロパティ・キーのセット別に頂点またはエッジの自動索引付けを行います。この主な目的は、特定のキー/値ペアに基づく頂点およびエッジの問合せパフォーマンスを向上させることです。

  • 手動テキスト索引付けでは、プロパティ・グラフの指定された頂点およびエッジのセットに対して複数の索引を定義できます。索引に含めるグラフ要素を指定する必要があります。

Oracle Big Data Spatial and Graphは、Oracle NoSQL DatabaseおよびApache HBaseのプロパティ・グラフに対して手動および自動テキスト索引を作成するためのAPIを提供します。索引は、使用可能な検索エンジン、Apache LuceneおよびSolrCloudを使用して管理されます。この節の続きでは、データ・アクセス・レイヤーのプロパティ・グラフ機能を使用してテキスト索引を作成する方法に焦点を当てます。

5.5.1 プロパティ・グラフ・データのテキスト索引の構成

テキスト索引の構成は、OracleIndexParametersオブジェクトを使用して定義されます。このオブジェクトには、検索エンジン、場所、ディレクトリ(またはシャード)の数、および並列度などの索引に関する情報が含まれます。

デフォルトでは、テキスト索引はメソッドopg.setDefaultIndexParameters(indexParams)を使用してプロパティ・グラフに関連付けられたOracleIndexParametersに基づいて構成されます。自動索引の初期作成により、将来索引付けされるキーのために構成およびテキスト検索エンジンが区切られます。

別のパラメータ・セットを指定して索引を作成することもできます。次のコード・フラグメントは、Luceneエンジンとともに物理ディレクトリを使用して既存のプロパティ・グラフに対して自動テキスト索引を作成します。

// Create an OracleIndexParameters object to get Index configuration (search engine, etc).
OracleIndexParameters indexParams = OracleIndexParameters.buildFS(args)  
 
// Create auto indexing on above properties for all vertices
opg.createKeyIndex("name", Vertex.class, indexParams.getParameters());

テキスト索引の初期構成を変更するには、最初に既存のグラフを削除してから、新しい構成を使用して索引を再作成する必要がある場合があります。

  • Apache Lucene検索エンジンを使用したテキスト索引の構成

  • SolrCloud検索エンジンを使用したテキスト索引の構成

Apache Lucene検索エンジンを使用したテキスト索引の構成

Apache Lucene検索エンジンを使用したテキスト索引では、LuceneIndexParameters構成オブジェクトを使用します。Lucene検索エンジンを使用した索引の構成パラメータには、次が含まれます。

  • ディレクトリの数: 自動索引に使用するApache Luceneディレクトリの数を指定する整数。複数のディレクトリを使用すると、記憶域とパフォーマンスのスケーラビリティを実現できます。デフォルト値は1に設定されています。

  • バッチ・サイズ: Apache Luceneでのバッチ処理用のドキュメントに使用するバッチ・サイズを指定する整数。デフォルトで使用されるバッチ・サイズは10000です。

  • バッチのコミット・サイズ:コミット操作が実行される前にApache Lucene索引に追加されるドキュメントの数を指定する整数。デフォルトで使用されるバッチのコミット・サイズは500000です。

  • データ型処理フラグ: Apache Luceneのデータ型処理を有効にするかどうかを指定するブール。データ型処理を有効にすると、数値および日時データ型に対する検索が高速になります。

  • ディレクトリ名: Apache Luceneディレクトリが作成されるベース・パスの場所を指定する文字列配列。

次のコード・フラグメントは、Apache Lucene検索エンジンとともに物理ディレクトリを使用してテキスト索引の構成を作成します。

OracleIndexParameters indexParams = 
      OracleIndexParameters.buildFS(4, 4, 10000, 50000, true, 
                                   "/home/data/text-index");

SolrCloud検索エンジンを使用したテキスト索引の構成

SolrCloud検索エンジンを使用したテキスト索引は、バックグラウンドでSolrIndexParametersオブジェクトを使用して、索引構築時に使用されるSolrCloudホスト名、シャードの数およびレプリケーション・ファクタを識別します。SolrCloud検索エンジンを使用した索引の構成パラメータには、次が含まれます。

  • 構成名: Oracle Property GraphのSolrCloud構成ファイルが格納されるApache Zookeeperディレクトリの名前。例: opgconfig。構成ファイルには、必要なフィールドのスキーマ(schema.xml)および記憶域設定(solrconfig.xml)が含まれます。

  • サーバーURL: SolrCloudサービスに接続するために使用されるSolrCloudサーバーURL。例: http://localhost:2181/solr

  • SolrCloudノード・セット: コレクションのシャードが格納されるSolrCloudサービス内のノードのホスト名。例: node01:8983_solr,node02:8983_solr,node03:8983_solr。値がnullに設定されている場合、コレクションはサービス内で使用可能なすべてのSolrCloudノードを使用して作成されます。

  • Zookeeperのタイムアウト: Zookeeper接続を待機するために使用されるタイムアウト(秒単位)を表す正の整数。

  • シャードの数: テキスト索引コレクション用として作成するシャードの数。SolrCloud構成でHDFSディレクトリを使用している場合、シャードの数が、SolrCloudノード・セットに指定されているSolrCloudノードの数を超えないようにする必要があります。

  • レプリケーション・ファクタ: SolrCloudコレクションで使用されるレプリケーション・ファクタ。デフォルト値は1に設定されています。

  • ノード当たりのシャードの最大数: 各SolrCloudノードで作成できるシャードの最大数。この値は、シャードの数をSolrCloudノード・セット内のノードの数で割った値より小さくしないようにする必要があります。

  • DOP: プロパティ・グラフから頂点(またはエッジ)を読み込み、キー/値ペアに索引を付けるときに使用する並列度。デフォルト値は1に設定されています。

  • バッチ・サイズ: Apache SolrCloudでのバッチ処理用のドキュメントに使用するバッチ・サイズを指定する整数。デフォルトで使用されるバッチ・サイズは10000です。

  • バッチのコミット・サイズ:コミット操作が実行される前にApache SolrCloud索引に追加されるドキュメントの数を指定する整数。デフォルトで使用されるバッチのコミット・サイズは500000 (50万)です。

  • 書込みタイムアウト: 索引操作が完了するまで待機するために使用するタイムアウト(秒単位)。通信エラーが原因で索引操作が失敗した場合、タイムアウトに達するか操作が完了するまで必要に応じて操作が繰り返し再試行されます。

次のコード・フラグメントは、SolrCloudを使用してテキスト索引の構成を作成します。

String configName = "opgconfig";
String solrServerUrl = "nodea:2181/solr"
String solrNodeSet = "nodea:8983_solr,nodeb:8983_solr," +  
                     "nodec:8983_solr,noded:8983_solr";
 
int zkTimeout = 15;
int numShards = 4;
int replicationFactor = 1;
int maxShardsPerNode = 1;
 
OracleIndexParameters indexParams = 
                 OracleIndexParameters.buildSolr(configName, 
                                       solrServerUrl, 
                                       solrNodeSet, 
                                       zkTimeout,
                                       numShards,
                                       replicationFactor,
                                       maxShardsPerNode,
                                       4,
                                       10000,
                                       500000,
                                       15);
SolrCloudを使用する場合、「ZookeeperへのコレクションのSolrCloud構成のアップロード」で説明されているように、最初にテキスト索引のためのコレクションの構成をApache Zookeeperにロードする必要があります。

5.5.2 プロパティ・グラフ・データの自動索引の使用

自動テキスト索引は、プロパティ・キーのセット別に頂点またはエッジの自動索引付けを行います。その主な目的は、特定のキー/値ペアに基づく頂点およびエッジに対する索引速度を上げることです。特定のキーの自動索引が有効である場合、データベース索引を実行する代わりに、キー/値ペアの索引が索引に対してテキスト索引として実行されます。

プロパティ・グラフに対する自動索引を記述する場合、次のOracleプロパティ・グラフ・メソッドを使用して自動索引を作成、削除および操作します。

  • OraclePropertyGraph.createKeyIndex(String key, Class elementClass, Parameter[] parameters): 特定のプロパティ・キー別にelementClass型の要素すべての自動索引を作成します。索引は、指定したパラメータに基づいて構成されます。

  • OraclePropertyGraph.createKeyIndex(String[] keys, Class elementClass, Parameter[] parameters): プロパティ・キー・セット別にelementClass型の要素すべての自動索引を作成します。索引は、指定したパラメータに基づいて構成されます。

  • OraclePropertyGraph.dropKeyIndex(String key, Class elementClass): 特定のプロパティ・キー別にelementClass型の要素すべての自動索引を削除します。

  • OraclePropertyGraph.dropKeyIndex(String[] keys, Class elementClass): 特定のプロパティ・キー・セット別にelementClass型の要素すべての自動索引を削除します。

  • OraclePropertyGraph.getAutoIndex(Class elementClass): elementClass型の自動索引の索引インスタンスを取得します。

  • OraclePropertyGraph.getIndexedKeys(Class elementClass): elementClass型の要素すべての自動索引で現在使用されている索引付けされたキー・セットを取得します。

提供されているExampleNoSQL6およびExampleHBase6の例では、入力ファイルからプロパティ・グラフを作成し、頂点に自動テキスト索引を作成し、Apache Luceneを使用していくつかのテキスト検索問合せを実行します。

次のコード・フラグメントは、name、role、religion、countryのプロパティ・キーを指定して、既存のプロパティ・グラフの頂点に自動索引を作成します。自動テキスト索引は、/home/data/text-indexディレクトリの下にある4つのサブディレクトリに格納されます。Apache Luceneデータ型処理が有効になります。この例では、再索引付けタスクのためにDOP (並列度) 4を使用しています。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
      args,  szGraphName);
 
String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";
 
// Do a parallel data loading
OraclePropertyGraphDataLoader opgdl = 
OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 
    
// Create an automatic index using Apache Lucene engine. 
// Specify Index Directory parameters (number of directories, 
// number of connections to database, batch size, commit size, 
// enable datatypes, location)
OracleIndexParameters indexParams = 
     OracleIndexParameters.buildFS(4, 4, 10000, 50000, true, 
             "/home/data/text-index ");
opg.setDefaultIndexParameters(indexParams);
    
// specify indexed keys
String[] indexedKeys = new String[4];
indexedKeys[0] = "name";
indexedKeys[1] = "role";
indexedKeys[2] = "religion";
indexedKeys[3] = "country";
 
// Create auto indexing on above properties for all vertices
opg.createKeyIndex(indexedKeys, Vertex.class);

デフォルトでは、索引はopg.setDefaultIndexParameters(indexParams)メソッドを使用してプロパティ・グラフに関連付けられたOracleIndexParametersに基づいて構成されます。

別のパラメータ・セットを指定して索引を作成することもできます。これは次のコード・スニペットに示されています。

// Create an OracleIndexParameters object to get Index configuration (search engine, etc).
OracleIndexParameters indexParams = OracleIndexParameters.buildFS(args)  
 
// Create auto indexing on above properties for all vertices
opg.createKeyIndex("name", Vertex.class, indexParams.getParameters());

次の例のコード・フラグメントは、すべての頂点に対して問合せを実行し、キー値ペアname:Barack Obamaを持つすべての一致する頂点を検索します。この操作は、テキスト索引の検索を実行します。

さらに、getVertices APIコールでuseWildCardsパラメータを指定することにより、ワイルドカード検索がサポートされます。ワイルドカード検索は、指定されたプロパティ・キーに対して自動索引が有効化されている場合にのみサポートされます。Apache Luceneを使用したテキスト検索構文の詳細は、https://lucene.apache.org/core/2_9_4/queryparsersyntax.htmlを参照してください。

// Find all vertices with name Barack Obama. 
    Iterator<Vertices> vertices = opg.getVertices("name", "Barack Obama").iterator();
    System.out.println("----- Vertices with name Barack Obama -----");
    countV = 0;
    while (vertices.hasNext()) {
      System.out.println(vertices.next());
      countV++;
    }
    System.out.println("Vertices found: " + countV);
 
   // Find all vertices with name including keyword "Obama"
   // Wildcard searching is supported.
    boolean useWildcard = true;
    Iterator<Vertices> vertices = opg.getVertices("name", "*Obama*",useWildcard).iterator();
    System.out.println("----- Vertices with name *Obama* -----");
    countV = 0;
    while (vertices.hasNext()) {
      System.out.println(vertices.next());
      countV++;
    }
    System.out.println("Vertices found: " + countV);

前述のコード例では、次のような出力が生成されます。

----- Vertices with name Barack Obama-----
Vertex ID 1 {name:str:Barack Obama, role:str:political authority, occupation:str:44th president of United States of America, country:str:United States, political party:str:Democratic, religion:str:Christianity}
Vertices found: 1
 
----- Vertices with name *Obama* -----
Vertex ID 1 {name:str:Barack Obama, role:str:political authority, occupation:str:44th president of United States of America, country:str:United States, political party:str:Democratic, religion:str:Christianity}
Vertices found: 1

5.5.3 プロパティ・グラフ・データの手動索引の使用

手動索引は、プロパティ・グラフの頂点およびエッジに対して複数の索引の定義をサポートしています。手動索引の場合、索引の要素を手動で挿入、取得および選択する必要があります。

プロパティ・グラフに対する手動索引を記述する場合、次のOracleプロパティ・グラフ・メソッドを使用して手動索引を追加、削除および操作します。

  • OraclePropertyGraph.createIndex(String name, Class elementClass, Parameter[] parameters): elementClass型の要素すべてに指定した名前を使用して手動索引を作成します。

  • OraclePropertyGraph.dropIndex(String name): 特定の手動索引を削除します。

  • OraclePropertyGraph.getIndex(String name, Class elementClass): elementClass型の特定の手動索引の索引インスタンスを取得します。

  • OraclePropertyGraph.getIndices(): プロパティ・グラフ内で作成したすべての手動で索引の索引インスタンスの配列を取得します。

提供されているExampleNoSQL7およびExampleHBase7の例では、入力ファイルからプロパティ・グラフを作成し、エッジに手動テキスト索引を作成し、いくつかのデータを索引に含めて、Apache SolrCloudを使用していくつかのテキスト検索問合せを実行します。

SolrCloudを使用する場合、「ZookeeperへのコレクションのSolrCloud構成のアップロード」で説明されているように、最初にテキスト索引のためのコレクションの構成をApache Zookeeperにロードする必要があります。

次のコード・フラグメントは、4つのシャード(ノードごとに1つのシャード)とレプリケーション係数1を使用して既存のプロパティ・グラフに手動テキスト索引を作成します。シャードの数は、SolrCloudクラスタ上のノードの数と一致します。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(args, 
                                                          szGraphName);
 
String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";
 
// Do a parallel data loading
OraclePropertyGraphDataLoader opgdl = 
OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 
    
// Create a manual text index using SolrCloud// Specify Index Directory parameters: configuration name, Solr Server URL, Solr Node set, 
// replication factor, zookeeper timeout (secs),
// maximum number of shards per node,  
   // number of connections to database, batch size, commit size, 
         // write timeout (in secs)
             String configName = "opgconfig";
             String solrServerUrl = "nodea:2181/solr"
             String solrNodeSet = "nodea:8983_solr,nodeb:8983_solr," +  
                                  "nodec:8983_solr,noded:8983_solr";
 
         int zkTimeout = 15;
         int numShards = 4;
         int replicationFactor = 1;
         int maxShardsPerNode = 1;
 
OracleIndexParameters indexParams = 
                 OracleIndexParameters.buildSolr(configName, 
                                       solrServerUrl, 
                                       solrNodeSet, 
                                       zkTimeout,
                                       numShards,
                                       replicationFactor,
                                       maxShardsPerNode,
                                       4,
                                       10000,
                                       500000,
                                       15);
opg.setDefaultIndexParameters(indexParams);
    
 
// Create manual indexing on above properties for all vertices
OracleIndex<Edge> index = ((OracleIndex<Edge>) opg.createIndex("myIdx", Edge.class));
 
Vertex v1 = opg.getVertices("name", "Barack Obama").iterator().next();
 
Iterator<Edge> edges
                = v1.getEdges(Direction.OUT, "collaborates").iterator();
 
          while (edges.hasNext()) {
             Edge edge = edges.next();
             Vertex vIn = edge.getVertex(Direction.IN);
             index.put("collaboratesWith", vIn.getProperty("name"), edge);
          }

次のコード・フラグメントは、手動索引に対して問合せを実行して、キー値ペアcollaboratesWith:Beyonceを持つすべてのエッジを取得します。さらに、get APIコールでuseWildCardsパラメータを指定することにより、ワイルドカード検索がサポートされます。

// Find all edges with collaboratesWith Beyonce. 
   // Wildcard searching is supported using true parameter.
    edges = index.get("collaboratesWith", "Beyonce").iterator();
    System.out.println("----- Edges with name Beyonce -----");
    countE = 0;
    while (edges.hasNext()) {
      System.out.println(edges.next());
      countE++;
    }
    System.out.println("Edges found: "+ countE);
 
// Find all vertices with name including Bey*. 
   // Wildcard searching is supported using true parameter.
    edges = index.get("collaboratesWith", "*Bey*", true).iterator();
    System.out.println("----- Edges with collaboratesWith Bey* -----");
    countE = 0;
    while (edges.hasNext()) {
      System.out.println(edges.next());
      countE++;
    }
    System.out.println("Edges found: " + countE);

前述のコード例では、次のような出力が生成されます。

----- Edges with name Beyonce -----
Edge ID 1000 from Vertex ID 1 {country:str:United States, name:str:Barack Obama, occupation:str:44th president of United States of America, political party:str:Democratic, religion:str:Christianity, role:str:political authority} =[collaborates]=> Vertex ID 2 {country:str:United States, music genre:str:pop soul , name:str:Beyonce, role:str:singer actress} edgeKV[{weight:flo:1.0}]
Edges found: 1
 
----- Edges with collaboratesWith Bey* -----
Edge ID 1000 from Vertex ID 1 {country:str:United States, name:str:Barack Obama, occupation:str:44th president of United States of America, political party:str:Democratic, religion:str:Christianity, role:str:political authority} =[collaborates]=> Vertex ID 2 {country:str:United States, music genre:str:pop soul , name:str:Beyonce, role:str:singer actress} edgeKV[{weight:flo:1.0}]
Edges found: 1

5.5.4 プロパティ・グラフ・テキスト索引に対する検索問合せの実行

自動および手動テキスト索引に対してテキスト検索問合せを実行できます。これらの機能は、特定のキー/値ペアに基づく問合せと、(ワイルドカード、ファジー検索および範囲問合せなどの拡張問合せオプションを使用した)単一または複数のキーに対するテキスト検索の実行とでは異なります。

  • Apache Luceneを使用したテキスト索引に対する索引問合せの実行

  • SolrCloudを使用したテキスト索引に対する索引問合せの実行

Apache Luceneを使用したテキスト索引に対する索引問合せの実行

次のコード・フラグメントは、Apache Luceneを使用して自動索引を作成し、特定のキー/値ペアを指定してテキスト索引に対する問合せを実行します。

// Do a parallel data loading
OraclePropertyGraphDataLoader opgdl = 
               OraclePropertyGraphDataLoader.getInstance();

opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 
    
// Create an automatic index using Apache Lucene engine. 
// Specify Index Directory parameters (number of directories, 
// number of connections to database, batch size, commit size, 
// enable datatypes, location)
OracleIndexParameters indexParams = 
            OracleIndexParameters.buildFS(4, 4, 10000, 50000, true, 
                                          "/home/data/text-index ");
opg.setDefaultIndexParameters(indexParams);

// Create manual indexing on above properties for all vertices
OracleIndex<Edge> index = ((OracleIndex<Edge>) opg.createIndex("myIdx", Edge.class));
 
Vertex v1 = opg.getVertices("name", "Barack Obama").iterator().next();
 
Iterator<Edge> edges
                = v1.getEdges(Direction.OUT, "collaborates").iterator();
 
while (edges.hasNext()) {
  Edge edge = edges.next();
  Vertex vIn = edge.getVertex(Direction.IN);
  index.put("collaboratesWith", vIn.getProperty("name"), edge);
  index.put("country", vIn.getProperty("country"), edge);
}
 
// Wildcard searching is supported using true parameter.
Iterator<Edge> edges = index.get("country", "United States").iterator();
System.out.println("----- Edges with query: " + queryExpr + " -----");
long countE = 0;
while (edges.hasNext()) {
  System.out.println(edges.next());
  countE++;
}
System.out.println("Edges found: "+ countE);

この場合、テキスト索引により、キーおよび値オブジェクトから索引問合せが生成されます。また、useWildcardsフラグが指定または有効化されていない場合、取得される結果には正確な一致のみが含まれます。値オブジェクトが数値または日時値である場合、生成される問合せは、値によって下限および上限が定義されているかどうかとは関係なく、両端を含む範囲問合せになります。数値または日時の一致のみが取得されます。

値が文字列である場合、データ型とは関係なく一致するすべてのキー/値ペアが取得されます。このタイプの問合せの結果として生成されるテキスト問合せは、オプションの検索条件セット(サポート対象のデータ型ごとに1つずつ)が含まれるブール問合せです。データ型の処理の詳細は、「データ型の処理」を参照してください。

したがって、前のコード例では、問合せ式country1:"United States" OR country9:"United States" OR … OR countryE:"United States" (Luceneのデータ型処理が有効である場合)、または country:"1United States" OR country:"2United States" OR … OR country:"EUnited States" (Luceneのデータ型処理が無効である場合)を生成します。

文字列値オブジェクトでワイルドカードが有効である場合、値はApache Lucene構文を使用して書き込む必要があります。Apache Luceneを使用したテキスト検索構文の詳細は、https://lucene.apache.org/core/2_9_4/queryparsersyntax.htmlを参照してください

問合せの実行対象のデータ型クラスを指定することにより、一致するキー/値ペアのデータ型をフィルタできます。次のコード・フラグメントは、文字列データ型のみを持つ単一のキー/値ペアを使用してテキスト索引に対して問合せを実行します。次のコードは、問合せ式country1:"United States" (Luceneのデータ型処理が有効である場合)またはcountry:"1United States" (Luceneのデータ型処理が無効である場合)を生成します。

// Wildcard searching is supported using true parameter.
Iterator<Edge> edges = index.get("country", "United States", true, String.class).iterator();

System.out.println("----- Edges with query: " + queryExpr + " -----");
long countE = 0;
while (edges.hasNext()) {
  System.out.println(edges.next());
  countE++;
}
System.out.println("Edges found: "+ countE);

ブール演算子を使用して処理する場合は、問合せで適切な一致が見つかるように、後続の各キー/値ペアにデータ型の接頭辞/接尾辞を追加する必要があります。自動および手動テキスト索引に必要な問合せ構文およびデータ型識別子を使用して独自のLuceneテキスト検索問合せを作成するユーザーを支援するためにユーティリティが用意されています。

LuceneIndex内のメソッドbuildSearchTerm(key, value, dtClass)は、キー(または値)にデータ型識別子を追加し、特定のデータ型およびApache Luceneのデータ型処理構成に基づいて値を必要な文字列表現に変換することにより、field:query_expr形式の問合せ式を作成します。

次のコード・フラグメントは、buildSearchTermメソッドを使用して、前の例で使用した問合せ式country1:United* (Luceneのデータ型処理が有効である場合)またはcountry:1United* (Luceneのデータ型処理が無効である場合)を生成します。

String szQueryStrCountry = index.buildSearchTerm("country", 
                                  "United*", String.class);

キーおよび値を個別オブジェクトとして扱ってWildcardQueryのような異なるLucene問合せを構築するために、LuceneIndex内のメソッドappendDatatypesSuffixToKey(key, dtClass)およびappendDatatypesSuffixToValue(value, dtClass)は、適切なデータ型識別子を追加し、特定のデータ型に基づいて値を必要なLucene文字列表現に変換します。

次のコード・フラグメントは、appendDatatypesSuffixToKeyメソッドを使用してLuceneテキスト問合せで必要なフィールド名を生成します。Luceneのデータ型処理が有効である場合、返される文字列により、文字列データ型識別子がキー(country1)の接尾辞として追加されます。それ以外の場合、取得された文字列は元のキー(country)になります。

String key = index.appendDatatypesSuffixToKey("country", String.class);

次のコード・フラグメントは、appendDatatypesSuffixToValueメソッドを使用して、Luceneテキスト問合せで必要な問合せ本体式を生成します。Luceneのデータ型処理が無効である場合、返される文字列により、文字列データ型識別子がキー(1United*)の接頭辞として追加されます。他のすべての場合、返される文字列は、値の文字列表現(United*)になります。

String value = index.appendDatatypesSuffixToValue("United*", String.class);

LuceneIndexは、メソッドbuildSearchTermObject(key, value, dtClass)を使用した条件オブジェクトの生成もサポートしています。条件オブジェクトは通常、取得対象のドキュメントのフィールドおよび値を制約するためにLucene問合せオブジェクトの様々な型の間で使用されます。次のコード・フラグメントは、buildSearchTermObjectメソッドを使用してWildcardQueryオブジェクトを作成する方法を示します。

Term term = index.buildSearchTermObject("country", "United*", String.class);  
Query query = new WildcardQuery(term);

SolrCloudを使用したテキスト索引に対する索引問合せの実行

次のコード・フラグメントは、SolrCloudを使用して自動索引を作成し、特定のキー/値ペアを指定してテキスト索引に対する問合せを実行します。

// Create a manual text index using SolrCloud// Specify Index Directory parameters: configuration name, Solr Server URL, Solr Node set, 
// replication factor, zookeeper timeout (secs),
// maximum number of shards per node,  
// number of connections to database, batch size, commit size, 
// write timeout (in secs)
String configName = "opgconfig";
String solrServerUrl = "nodea:2181/solr"
String solrNodeSet = "nodea:8983_solr,nodeb:8983_solr," +  
                     "nodec:8983_solr,noded:8983_solr";
 
int zkTimeout = 15;
int numShards = 4;
int replicationFactor = 1;
int maxShardsPerNode = 1;
 
OracleIndexParameters indexParams = 
                 OracleIndexParameters.buildSolr(configName, 
                                       solrServerUrl, 
                                       solrNodeSet, 
                                       zkTimeout,
                                       numShards,
                                       replicationFactor,
                                       maxShardsPerNode,
                                       4,
                                       10000,
                                       500000,
                                       15);
opg.setDefaultIndexParameters(indexParams);
    
// specify indexed keys
String[] indexedKeys = new String[4];
indexedKeys[0] = "name";
indexedKeys[1] = "role";
indexedKeys[2] = "religion";
indexedKeys[3] = "country";
 
// Create auto indexing on above properties for all vertices
opg.createKeyIndex(indexedKeys, Vertex.class); 

// Create manual indexing on above properties for all vertices
OracleIndex<Vertex> index = ((OracleIndex<Vertex>) opg.getAutoIndex(Vertex.class);
 
Iterator<Vertex> vertices = index.get("country", "United States").iterator();
System.out.println("----- Vertices with query: " + queryExpr + " -----");
countV = 0;
while (vertices.hasNext()) {
  System.out.println(vertices.next());
  countV++;
}
System.out.println("Vertices found: "+ countV);

この場合、テキスト索引により、値オブジェクトから索引が生成されます。また、useWildcardsフラグが指定または有効化されていない場合、取得される結果には正確な一致のみが含まれます。値オブジェクトが数値または日時値である場合、生成される問合せは、値によって下限および上限が定義されているかどうかとは関係なく、両端を含む範囲問合せになります。数値または日時の一致のみが取得されます。

値が文字列である場合、データ型とは関係なく一致するすべてのキー/値ペアが取得されます。このタイプの問合せの結果として生成されるテキスト問合せは、オプションの検索条件セット(サポート対象のデータ型ごとに1つずつ)が含まれるブール問合せです。データ型の処理の詳細は、「データ型の処理」を参照してください。

したがって、前のコード例では、問合せ式country_str:"United States" OR country_ser:"United States" OR … OR country_json:"United States"を生成します。

ワイルドカードが有効な状態で文字列値オブジェクトを使用するには、値がApache Lucene構文を使用して書き込まれる必要があります。Apache Luceneを使用したテキスト検索構文の詳細は、「データ型の処理」を参照してください

問合せの実行対象のデータ型クラスを指定することにより、一致するキー/値ペアのデータ型をフィルタできます。次のコード・フラグメントは、文字列データ型のみを持つ単一のキー/値ペアを使用してテキスト索引に対して問合せを実行します。次のコードは、問合せ式country_str:"United States"を作成します。

// Wildcard searching is supported using true parameter.
Iterator<Edge> edges = index.get("country", "United States", true, String.class).iterator();
    System.out.println("----- Edges with query: " + queryExpr + " -----");
    countE = 0;
    while (edges.hasNext()) {
      System.out.println(edges.next());
      countE++;
    }
    System.out.println("Edges found: "+ countE);

ブール演算子を使用して処理する場合は、問合せで適切な一致が見つかるように、後続の各キー/値ペアにデータ型の接頭辞/接尾辞を追加する必要があります。自動および手動テキスト索引に必要な問合せ構文およびデータ型識別子を使用して独自のSolrCloudテキスト検索問合せを作成するユーザーを支援するためにユーティリティ・セットが用意されています。

SolrIndex内のメソッドbuildSearchTerm(key, value, dtClass)は、キー(または値)にデータ型識別子を追加し、索引に必要なデータ型形式を使用して値を必要な文字列表現に変換することにより、field:query_expr形式の問合せ式を作成します。

次のコード・フラグメントは、buildSearchTermメソッドを使用して、前の例で使用した問合せ式country_str:United*を作成します。

String szQueryStrCountry = index.buildSearchTerm("country", 
                                  "United*", String.class);

キーおよび値を個別オブジェクトとして扱ってWildcardQueryのような異なるSolrClud問合せを構築するために、SolrIndex内のメソッドappendDatatypesSuffixToKey(key, dtClass)およびappendDatatypesSuffixToValue(value, dtClass)は、適切なデータ型識別子を追加し、特定のデータ型に基づいてキーおよび値を必要なSolrCloud文字列表現に変換します。

次のコード・フラグメントは、appendDatatypesSuffixToKeyメソッドを使用してSolrCloudテキスト問合せで必要なフィールド名を生成します。取得した文字列は、文字列データ型識別子をキーの接尾辞(country_str)として追加します。

String key = index.appendDatatypesSuffixToKey("country", String.class);

次のコード・フラグメントは、appendDatatypesSuffixToValueメソッドを使用して、SolrCloudテキスト問合せで必要な問合せ本体式を生成します。返される文字列は、値の文字列表現(United*)になります。

String value = index.appendDatatypesSuffixToValue("United*", String.class);

5.5.5 データ型の処理

Oracleのプロパティ・グラフ・サポートは、値のデータ型に基づいて要素のキー/値ペアを索引付けおよび格納します。データ型処理の主な目的は、数値や日付範囲の問合せなど、包括的な問合せのサポートを提供することです。

デフォルトでは、特定のキー/値ペアに対する検索は、その値のデータ型に基づく問合せ式まで行われます。たとえば、キー値ペアage:30を持つ頂点を検索する場合は、整数のデータ型が指定されたすべての年齢フィールドに対して問合せが実行されます。値が問合せ式である場合は、API get(String key, Object value, Class dtClass, Boolean useWildcards)をコールすることにより、検索する値のデータ型クラスも指定できます。データ型が指定されていない場合、問合せ式はすべての使用可能なデータ型と一致します。

ブール演算子を使用して処理する場合は、問合せで適切な一致が見つかるように、後続の各キー/値ペアにデータ型の接頭辞/接尾辞を追加する必要があります。次の各トピックでは、Apache LuceneおよびSolrCloudでこの接頭辞/接尾辞を追加する方法について説明します。

5.5.5.1 Apache Luceneでのデータ型識別子の追加

Luceneのデータ型処理が有効化されている場合、問合せ式のキーの接尾辞として適切なデータ型識別子を追加する必要があります。これは、キーに対してString.concat()の演算を実行することによって行うことができます。Luceneのデータ型処理が無効化されている場合、データ型識別子を値Stringに接頭辞として挿入する必要があります。表5-1は、Apache Luceneを使用したテキスト索引付けに使用可能なデータ型識別子を示しています(LuceneIndexのJavadocも参照)。

表5-2 Apache Luceneデータ型識別子

Luceneデータ型識別子 説明

TYPE_DT_STRING

String

TYPE_DT_BOOL

Boolean

TYPE_DT_DATE

Date

TYPE_DT_FLOAT

Float

TYPE_DT_DOUBLE

Double

TYPE_DT_INTEGER

Integer

TYPE_DT_LONG

Long

TYPE_DT_CHAR

Character

TYPE_DT_SHORT

Short

TYPE_DT_BYTE

Byte

TYPE_DT_SPATIAL

Spatial

TYPE_DT_SERIALIZABLE

Serializable

次のコード・フラグメントは、Luceneのデータ型処理を使用してエッジに手動索引を作成し、データを追加してから、手動索引に対して問合せを実行し、ワイルドカードを使用してキー/値ペアcollaboratesWith:Beyonce AND country1:United*を持つすべてのエッジを取得します。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(args,               
                                                          szGraphName);
 
String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";
 
// Do a parallel data loading
OraclePropertyGraphDataLoader opgdl = 
OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 
    
// Specify Index Directory parameters (number of directories, 
   // number of connections to database, batch size, commit size, 
         // enable datatypes, location)
OracleIndexParameters indexParams = 
     OracleIndexParameters.buildFS(4, 4, 10000, 50000, true, 
            "/home/data/text-index ");
opg.setDefaultIndexParameters(indexParams);
// Create manual indexing on above properties for all edges
OracleIndex<Edge> index = ((OracleIndex<Edge>) opg.createIndex("myIdx", Edge.class));
 
Vertex v1 = opg.getVertices("name", "Barack Obama").iterator().next();
 
Iterator<Edge> edges
                = v1.getEdges(Direction.OUT, "collaborates").iterator();
 
          while (edges.hasNext()) {
             Edge edge = edges.next();
             Vertex vIn = edge.getVertex(Direction.IN);
             index.put("collaboratesWith", vIn.getProperty("name"), edge);
             index.put("country", vIn.getProperty("country"), edge);
          }
 
// Wildcard searching is supported using true parameter.
    String key = "country";
    key = key.concat(String.valueOf(oracle.pg.text.lucene.LuceneIndex.TYPE_DT_STRING));
   
    String queryExpr = "Beyonce AND " + key + ":United*";
    edges = index.get("collaboratesWith", queryExpr, true /*UseWildcard*/).iterator();
    System.out.println("----- Edges with query: " + queryExpr + " -----");
    countE = 0;
    while (edges.hasNext()) {
      System.out.println(edges.next());
      countE++;
    }
    System.out.println("Edges found: "+ countE);

前述のコード例では、次のような出力が生成される可能性があります。

----- Edges with name Beyonce AND country1:United* -----
Edge ID 1000 from Vertex ID 1 {country:str:United States, name:str:Barack Obama, occupation:str:44th president of United States of America, political party:str:Democratic, religion:str:Christianity, role:str:political authority} =[collaborates]=> Vertex ID 2 {country:str:United States, music genre:str:pop soul , name:str:Beyonce, role:str:singer actress} edgeKV[{weight:flo:1.0}]
Edges found: 1

次のコード・フラグメントは、頂点に自動索引を作成し、Luceneのデータ型処理を無効化し、データを追加してから、前の例からの手動索引に対して問合せを実行し、ワイルドカードを使用してキー/値ペアcountry:United* AND role:1*political*を持つすべての頂点を取得します。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(args,               
                                                          szGraphName);
 
String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";
 
// Do a parallel data loading
OraclePropertyGraphDataLoader opgdl = 
OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 
    
// Create an automatic index using Apache Lucene engine. 
// Specify Index Directory parameters (number of directories, 
   // number of connections to database, batch size, commit size, 
         // enable datatypes, location)
OracleIndexParameters indexParams = 
     OracleIndexParameters.buildFS(4, 4, 10000, 50000, false, "/ home/data/text-index ");
opg.setDefaultIndexParameters(indexParams);
    
// specify indexed keys
String[] indexedKeys = new String[4];
indexedKeys[0] = "name";
indexedKeys[1] = "role";
indexedKeys[2] = "religion";
indexedKeys[3] = "country";
 
// Create auto indexing on above properties for all vertices
opg.createKeyIndex(indexedKeys, Vertex.class);
 
// Wildcard searching is supported using true parameter.
    String value = "*political*";
    value = String.valueOf(LuceneIndex.TYPE_DT_STRING) + value;
String queryExpr = "United* AND role:" + value;
    
 
vertices = opg.getVertices("country", queryExpr,  true /*useWildcard*/).iterator();
    System.out.println("----- Vertices with query: " + queryExpr + " -----");
    countV = 0;
    while (vertices.hasNext()) {
      System.out.println(vertices.next());
      countV++;
    }
    System.out.println("Vertices found: " + countV);

前述のコード例では、次のような出力が生成される可能性があります。

----- Vertices with query: United* and role:1*political* -----
Vertex ID 30 {name:str:Jerry Brown, role:str:political authority, occupation:str:34th and 39th governor of California, country:str:United States, political party:str:Democratic, religion:str:roman catholicism}
Vertex ID 24 {name:str:Edward Snowden, role:str:political authority, occupation:str:system administrator, country:str:United States, religion:str:buddhism}
Vertex ID 22 {name:str:John Kerry, role:str:political authority, country:str:United States, political party:str:Democratic, occupation:str:68th United States Secretary of State, religion:str:Catholicism}
Vertex ID 21 {name:str:Hillary Clinton, role:str:political authority, country:str:United States, political party:str:Democratic, occupation:str:67th United States Secretary of State, religion:str:Methodism}
Vertex ID 19 {name:str:Kirsten Gillibrand, role:str:political authority, country:str:United States, political party:str:Democratic, occupation:str:junior United States Senator from New York, religion:str:Methodism}
Vertex ID 13 {name:str:Ertharin Cousin, role:str:political authority, country:str:United States, political party:str:Democratic}
Vertex ID 11 {name:str:Eric Holder, role:str:political authority, country:str:United States, political party:str:Democratic, occupation:str:United States Deputy Attorney General}
Vertex ID 1 {name:str:Barack Obama, role:str:political authority, occupation:str:44th president of United States of America, country:str:United States, political party:str:Democratic, religion:str:Christianity}
Vertices found: 8
5.5.5.2 SolrCloudでのデータ型識別子の追加

SolrCloudテキスト索引のブール演算では、問合せ式のキーの接尾辞として適切なデータ型識別子を追加する必要があります。これは、キーに対してString.concat()の演算を実行することによって行うことができます。表5-3は、SolrCloudを使用したテキスト索引付けに使用可能なデータ型識別子を示しています(SolrIndexのJavadocも参照)。

表5-3 SolrCloudデータ型識別子

Solrデータ型識別子 説明

TYPE_DT_STRING

String

TYPE_DT_BOOL

Boolean

TYPE_DT_DATE

Date

TYPE_DT_FLOAT

Float

TYPE_DT_DOUBLE

Double

TYPE_DT_INTEGER

Integer

TYPE_DT_LONG

Long

TYPE_DT_CHAR

Character

TYPE_DT_SHORT

Short

TYPE_DT_BYTE

Byte

TYPE_DT_SPATIAL

Spatial

TYPE_DT_SERIALIZABLE

Serializable

次のコード・フラグメントは、SolrCloudを使用してエッジに手動索引を作成し、データを追加してから、手動索引に対して問合せを実行し、ワイルドカードを使用してキー/値ペアcollaboratesWith:Beyonce AND country1:United*を持つすべてのエッジを取得します。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(args,       
                                                          szGraphName);
 
String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";
 
// Do a parallel data loading
OraclePropertyGraphDataLoader opgdl = 
OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 
    
// Create a manual text index using SolrCloud// Specify Index Directory parameters: configuration name, Solr Server URL, Solr Node set, 
// replication factor, zookeeper timeout (secs),
// maximum number of shards per node,  
   // number of connections to database, batch size, commit size, 
         // write timeout (in secs)
             String configName = "opgconfig";
             String solrServerUrl = "nodea:2181/solr";
             String solrNodeSet = "nodea:8983_solr,nodeb:8983_solr," +  
                                  "nodec:8983_solr,noded:8983_solr";
 
         int zkTimeout = 15;
         int numShards = 4;
         int replicationFactor = 1;
         int maxShardsPerNode = 1;
 
OracleIndexParameters indexParams = 
                 OracleIndexParameters.buildSolr(configName, 
                                       solrServerUrl, 
                                       solrNodeSet, 
                                       zkTimeout,
                                       numShards,
                                       replicationFactor,
                                       maxShardsPerNode,
                                       4,
                                       10000,
                                       500000,
                                       15);
opg.setDefaultIndexParameters(indexParams);
    
// Create manual indexing on above properties for all vertices
OracleIndex<Edge> index = ((OracleIndex<Edge>) opg.createIndex("myIdx", Edge.class));
 
Vertex v1 = opg.getVertices("name", "Barack Obama").iterator().next();
 
Iterator<Edge> edges
                = v1.getEdges(Direction.OUT, "collaborates").iterator();
 
          while (edges.hasNext()) {
             Edge edge = edges.next();
             Vertex vIn = edge.getVertex(Direction.IN);
             index.put("collaboratesWith", vIn.getProperty("name"), edge);
             index.put("country", vIn.getProperty("country"), edge);
          }
 
// Wildcard searching is supported using true parameter.
    String key = "country";
    key = key.concat(oracle.pg.text.solr.SolrIndex.TYPE_DT_STRING);
   
    String queryExpr = "Beyonce AND " + key + ":United*";
    edges = index.get("collaboratesWith", queryExpr, true /** UseWildcard*/).iterator();
    System.out.println("----- Edges with query: " + queryExpr + " -----");
    countE = 0;
    while (edges.hasNext()) {
      System.out.println(edges.next());
      countE++;
    }
    System.out.println("Edges found: "+ countE);

前述のコード例では、次のような出力が生成される可能性があります。

----- Edges with name Beyonce AND country_str:United* -----
Edge ID 1000 from Vertex ID 1 {country:str:United States, name:str:Barack Obama, occupation:str:44th president of United States of America, political party:str:Democratic, religion:str:Christianity, role:str:political authority} =[collaborates]=> Vertex ID 2 {country:str:United States, music genre:str:pop soul , name:str:Beyonce, role:str:singer actress} edgeKV[{weight:flo:1.0}]
Edges found: 1

5.5.6 ZookeeperへのコレクションのSolrCloud構成のアップロード

Oracle Big Data Spatial and Graphプロパティ・グラフでSolrCloudテキスト索引を使用する前に、コレクションの構成をZookeeperにアップロードする必要があります。これは、SolrCloudクラスタ・ノードのいずれかでZkCliツールを使用して実行できます。

事前定義済のコレクション構成ディレクトリは、インストール・ホームの下にあるdal/opg-solr-configにあります。次に、PropertyGraph構成ディレクトリのアップロード方法の例を示します。

  1. インストール・ホームの下にあるdal/opg-solr-configを、Solrクラスタ・ノードのいずれかにある/tmpディレクトリにコピーします。次に例を示します。

    scp –r dal/opg-solr-config user@solr-node:/tmp
    
  2. 同じノードでZkCliツールを使用して、次の例のように次のコマンドを実行します。

    $SOLR_HOME/bin/zkcli.sh -zkhost 127.0.0.1:2181/solr -cmd upconfig –confname opgconfig -confdir /tmp/opg-solr-config

5.5.7 プロパティ・グラフ・データのテキスト索引の構成設定の更新

Oracleのプロパティ・グラフ・サポートは、Apache LuceneおよびSolrCloudとの統合によって手動および自動テキスト索引を管理します。作成時に、テキスト検索で使用される検索エンジンとその他の構成設定を指定するOracleIndexParametersオブジェクトを作成する必要があります。プロパティ・グラフのテキスト索引が作成された後、これらの構成設定を変更することはできません。自動索引の場合、すべての頂点索引キーは単一のテキスト索引によって管理され、すべてのエッジ索引キーは最初の頂点またはエッジ・キーが索引付けされるときに指定された構成を使用して、異なるテキスト索引によって管理されます。

構成設定を変更する必要がある場合は、最初に現在の索引を無効にしてから、新しいOracleIndexParametersオブジェクトを使用してそれを再度作成する必要があります。次のコード・フラグメントは、既存のプロパティ・グラフに対して2つのApache Luceneベースの自動索引(頂点およびエッジ)を作成し、それらを無効にしてから、SolrCloudを使用するために再作成します。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
      args,  szGraphName);
 
String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";
 
// Do parallel data loading
OraclePropertyGraphDataLoader opgdl =
OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop);
 
// Create an automatic index using Apache Lucene.
// Specify Index Directory parameters (number of directories,
// number of connections to database, batch size, commit size,
// enable datatypes, location)
OracleIndexParameters luceneIndexParams =
     OracleIndexParameters.buildFS(4, 4, 10000, 50000, true,
             "/home/oracle/text-index ");
 
// Specify indexed keys
String[] indexedKeys = new String[4];
indexedKeys[0] = "name";
indexedKeys[1] = "role";
indexedKeys[2] = "religion";
indexedKeys[3] = "country";
 
// Create auto indexing on above properties for all vertices
opg.createKeyIndex(indexedKeys, Vertex.class, luceneIndexParams.getParameters());
 
// Create auto indexing on weight for all edges
opg.createKeyIndex("weight", Edge.class, luceneIndexParams.getParameters());
 
// Disable auto indexes to change parameters
opg.getOracleIndexManager().disableVertexAutoIndexer();
opg.getOracleIndexManager().disableEdgeAutoIndexer();
 
 
// Recreate text indexes using SolrCloud
// Specify Index Directory parameters: configuration name, Solr Server URL, Solr Node set,
// replication factor, zookeeper timeout (secs),
// maximum number of shards per node,
// number of connections to database, batch size, commit size,
// write timeout (in secs)
String configName = "opgconfig";
String solrServerUrl = "nodea:2181/solr";
String solrNodeSet = "nodea:8983_solr,nodeb:8983_solr," +
   "nodec:8983_solr,noded:8983_solr";
 
int zkTimeout = 15;
int numShards = 4;
int replicationFactor = 1;
int maxShardsPerNode = 1;
 
OracleIndexParameters solrIndexParams =
OracleIndexParameters.buildSolr(configName,
                                solrServerUrl,
                                solrNodeSet,
                                zkTimeout,
                                numShards,
                                replicationFactor,
                                maxShardsPerNode,
                                4,
                                10000,
                                500000,
                                15);
 
// Create auto indexing on above properties for all vertices
opg.createKeyIndex(indexedKeys, Vertex.class, solrIndexParams.getParameters());
 
// Create auto indexing on weight for all edges
opg.createKeyIndex("weight", Edge.class, solrIndexParams.getParameters());

5.5.8 プロパティ・グラフ・データのテキスト索引でのパラレル問合せの使用

Oracle Big Data Spatial and Graphのテキスト索引では、パラレル問合せ実行を使用して、特定のキー/値またはキー/テキスト・ペア別に数百万の頂点およびエッジに対してテキスト問合せを実行できます。

パラレル・テキスト問合せは、SolrCloud(またはApache Luceneのサブディレクトリ)内のシャード間での索引データの配分を利用する最適化されたソリューションであり、各シャードは別個の索引接続を使用して問い合せられます。これには、読取り操作のパフォーマンスを向上させて索引から複数の要素を取得するために、複数のスレッドとSolrCloud (またはApache Lucene)検索エンジンへの接続が関連します。このアプローチでは、スコアに基づく一致結果のランク付けは行われません。

パラレル・テキスト問合せでは、各要素がシャードからの指定されたK/Vペアに一致する属性を持つすべての頂点(またはエッジ)を保持する配列が生成されます。問い合せられたシャードのサブセットは、特定の開始サブディレクトリIDと指定された接続の配列のサイズによって区切られます。これにより、サブセットは[開始, 開始 - 1 + 接続の配列のサイズ]の範囲内のシャードを考慮します。Nシャードを含む索引にあるすべてのシャードに、([0, N - 1]の範囲の)整数IDが割り当てられることに注意してください。

Apache Luceneを使用したパラレル・テキスト問合せ

LuceneIndexgetPartitionedメソッドを呼び出して、サブディレクトリのセットへの接続の配列(SearcherManagerオブジェクト)、検索するキー/値ペア、および開始サブディレクトリIDを指定することにより、Apache Luceneを使用したパラレル・テキスト問合せを使用できます。各サブディレクトリは索引のその他のサブディレクトリに依存していないため、各接続が適切なサブディレクトリにリンクしている必要があります。

次のコード・フラグメントは、Apache Lucene検索エンジンを使用して自動テキスト索引を生成し、パラレル・テキスト問合せを実行します。LuceneIndexクラスでのgetPartitionedメソッドの呼出し数は、サブディレクトリの合計数と使用される接続の数によって制御されます。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

// Clear existing vertices/edges in the property graph 
opg.clearRepository(); 

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";

// This object will handle parallel data loading
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 

// Create an automatic index
OracleIndexParameters indexParams 
= OracleIndexParameters.buildFS(dop /* number of directories */,
dop /* number of connections
used when indexing */,
10000 /* batch size before commit*/,
500000 /* commit size before Lucene commit*/,
true /* enable datatypes */,
"./lucene-index" /* index location */);

opg.setDefaultIndexParameters(indexParams);

// Create auto indexing on name property for all vertices
System.out.println("Create automatic index on name for vertices");
opg.createKeyIndex("name", Vertex.class);

// Get the LuceneIndex object 
SearcherManager[] conns = new SearcherManager[dop];
LuceneIndex<Vertex> index = (LuceneIndex<Vertex>) opg.getAutoIndex(Vertex.class);


long lCount = 0;
for (int split = 0; split < index.getTotalShards(); 
 split += conns.length) {
// Gets a connection object from subdirectory split to 
//(split + conns.length)
for (int idx = 0; idx < conns.length; idx++) { 
conns[idx] = index.getOracleSearcherManager(idx + split); 
}

// Gets elements from split to split + conns.length
Iterable<Vertex>[] iterAr 
= index.getPartitioned(conns /* connections */, 
 "name"/* key */, 
 "*" /* value */, 
 true /* wildcards */, 
 split /* start split ID */);

lCount = countFromIterables(iterAr); /* Consume iterables in parallel */

// Do not close the connections to the subdirectories after completion,
// because those connections are used by the LuceneIndex object itself.
}

// Count all vertices
System.out.println("Vertices found using parallel query: " + lCount);

SolrCloudを使用したパラレル・テキスト検索

SolrIndexgetPartitionedメソッドを呼び出して、SolrCloudへの接続の配列(CloudSolrServerオブジェクト)、検索するキー/値ペア、および開始シャードIDを指定することにより、SolrCloudを使用したパラレル・テキスト問合せを使用できます。

次のコード・フラグメントは、SolrCloud検索エンジンを使用して自動テキスト索引を生成し、パラレル・テキスト問合せを実行します。SolrIndexクラスでのgetPartitionedメソッドの呼出し数は、索引内のシャードの合計数と使用される接続の数によって制御されます。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

// Clear existing vertices/edges in the property graph 
opg.clearRepository(); 

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";

// This object will handle parallel data loading
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 

String configName = "opgconfig";
String solrServerUrl = args[4];//"localhost:2181/solr"
String solrNodeSet = args[5]; //"localhost:8983_solr";
 
int zkTimeout = 15; // zookeeper timeout in seconds
int numShards = Integer.parseInt(args[6]); // number of shards in the index
int replicationFactor = 1; // replication factor
int maxShardsPerNode = 1; // maximum number of shards per node
 
// Create an automatic index using SolrCloud
OracleIndexParameters indexParams = 
 OracleIndexParameters.buildSolr(configName, 
 solrServerUrl, 
 solrNodeSet, 
 zkTimeout /* zookeeper timeout in seconds */,
 numShards /* total number of shards */,
 replicationFactor /* Replication factor */,
 maxShardsPerNode /* maximum number of shardsper node*/,
 4 /* dop used for scan */,
 10000 /* batch size before commit*/,
 500000 /* commit size before SolrCloud commit*/,
 15 /* write timeout in seconds */);

opg.setDefaultIndexParameters(indexParams);

// Create auto indexing on name property for all vertices
System.out.println("Create automatic index on name for vertices");
opg.createKeyIndex("name", Vertex.class);

// Get the SolrIndex object 
SearcherManager[] conns = new SearcherManager[dop];
SolrIndex<Vertex> index = (SolrIndex<Vertex>) opg.getAutoIndex(Vertex.class);

// Open an array of connections to handle connections to SolrCloud needed for parallel text search
CloudSolrServer[] conns = new CloudSolrServer[dop];


for (int idx = 0; idx < conns.length; idx++) {
conns[idx] = index.getCloudSolrServer(15 /* write timeout in 
secs*/);
}

// Iterate to cover all the shards in the index
long lCount = 0;
for (int split = 0; split < index.getTotalShards(); 
 split += conns.length) {
// Gets elements from split to split + conns.length
Iterable<Vertex>[] iterAr = index.getPartitioned(conns /* connections */, 
 "name"/* key */, 
 "*" /* value */, 
 true /* wildcards */, 
 split /* start split ID */);

lCount = countFromIterables(iterAr); /* Consume iterables in parallel */
}

// Close the connections to the subdirectories after completed
for (int idx = 0; idx < conns.length; idx++) { 
conns[idx].shutdown();
} 

// Count results
System.out.println("Vertices found using parallel query: " + lCount);

5.5.9 プロパティ・グラフ・データのテキスト索引に対するネイティブ問合せオブジェクトの使用

問合せオブジェクトの直接使用は上級ユーザーを対象としており、これらのユーザーは、テキスト索引エンジン(Apache LuceneまたはSolrCloud)の基礎となる問合せ機能を最大限に活用できるようになります。たとえば、一致スコアにboostを追加したりソート句を追加したりするなど、テキスト検索に制約を追加できます。

テキスト検索とともに問合せオブジェクトを使用すると、制約を満たしながら、テキスト問合せと一致する属性(または属性セット)とともにすべての頂点(またはエッジ)を保持する反復可能オブジェクトが作成されます。このアプローチでは、一致スコアに基づいて結果が自動的にランク付けされます。

問合せ本体内で句を構築するには、照合対象のキー/値ペアによって使用されるデータ型、および使用される検索エンジンの構成を考慮する必要がある場合があります。検索条件の構築の詳細は、「データ型の処理」を参照してください。

Apache Luceneを使用したネイティブ問合せオブジェクトの使用

LuceneIndexでメソッドget(Query)を呼び出すことにより、Apache Luceneを使用してネイティブ問合せオブジェクトを使用できます。LuceneIndexでメソッドgetPartitioned(SearcherManager[], Query, int)を呼び出して、サブディレクトリのセットへの接続の配列(SearcherManagerオブジェクト)、Lucene問合せオブジェクト、および開始サブディレクトリIDを指定することにより、ネイティブ問合せオブジェクトを使用したパラレル・テキスト問合せを使用することもできます。各サブディレクトリは索引のその他のサブディレクトリに依存していないため、各接続が適切なサブディレクトリにリンクしている必要があります。

次のコード・フラグメントは、Apache Lucene検索エンジンを使用して自動テキスト索引を生成し、Lucene問合せを作成し、パラレル・テキスト問合せを実行します。LuceneIndexクラスでのgetPartitionedメソッドの呼出し数は、サブディレクトリの合計数と使用される接続の数によって制御されます。

import oracle.pg.text.lucene.LuceneIndex;
import org.apache.lucene.search.*;
import org.apache.lucene.index.*;

...

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

// Clear existing vertices/edges in the property graph 
opg.clearRepository(); 

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";

// This object will handle parallel data loading
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 

// Create an automatic index
OracleIndexParameters indexParams = OracleIndexParameters.buildFS(dop /* number of directories */,
dop /* number of connections
used when indexing */,
10000 /* batch size before commit*/,
500000 /* commit size before Lucene commit*/,
true /* enable datatypes */,
"./lucene-index" /* index location */);

opg.setDefaultIndexParameters(indexParams);

// Create auto indexing on name and country properties for all vertices
System.out.println("Create automatic index on name and country for vertices");
String[] indexedKeys = new String[2];
indexedKeys[0]="name";
indexedKeys[1]="country";
opg.createKeyIndex(indexedKeys, Vertex.class);

// Get the LuceneIndex object 
LuceneIndex<Vertex> index = (LuceneIndex<Vertex>) opg.getAutoIndex(Vertex.class);

// Search first for Key name with property value Beyon* using only string 
//data types
Term term = index.buildSearchTermObject("name", "Beyo*", String.class);
Query queryBey = new WildcardQuery(term);

// Add another condition to query all the vertices whose country is 
//"United States"
String key = index.appendDatatypesSuffixToKey("country", String.class);
String value = index.appendDatatypesSuffixToValue("United States", String.class);

Query queryCountry = new PhraseQuery();
StringTokenizer st = new StringTokenizer(value);
while (st.hasMoreTokens()) {
  queryCountry.add(new Term(key, st.nextToken()));
};

//Concatenate queries
BooleanQuery bQuery = new BooleanQuery();
bQuery.add(queryBey, BooleanClause.Occur.MUST);
bQuery.add(queryCountry, BooleanClause.Occur.MUST);

long lCount = 0;
SearcherManager[] conns = new SearcherManager[dop];
for (int split = 0; split < index.getTotalShards(); split += conns.length) {
  // Gets a connection object from subdirectory split to 
  //(split + conns.length). Skip the cache so we clone the connection and
  // avoid using the connection used by the index.
  for (int idx = 0; idx < conns.length; idx++) { 
    conns[idx] = index.getOracleSearcherManager(idx + split, 
                                      true /* skip looking in the cache*/                 
); 
  }

  // Gets elements from split to split + conns.length
  Iterable<Vertex>[] iterAr = index.getPartitioned(conns /* connections */, 
                                                   bQuery,  
                                                   split /* start split ID */);

  lCount = countFromIterables(iterAr); /* Consume iterables in parallel */

  // Do not close the connections to the sub-directories after completed,
  // as those connections are used by the index itself

}

// Count all vertices
System.out.println("Vertices found using parallel query: " + lCount);

SolrCloudを使用したネイティブ問合せオブジェクトの使用

SolrIndexでメソッドget(SolrQuery)を呼び出すことにより、SolrCloudに対してネイティブ問合せオブジェクトを直接使用できます。SolrIndexでメソッドgetPartitioned(CloudSolrServer[],SolrQuery,int)を呼び出して、SolrCloudへの接続の配列 (CloudSolrServerオブジェクト)、SolrQueryオブジェクト、および開始シャードIDを指定することにより、ネイティブ問合せオブジェクトを使用したパラレル・テキスト問合せを使用することもできます。

次のコード・フラグメントは、Apache SolrCloud検索エンジンを使用して自動テキスト索引を生成し、SolrQueryオブジェクトを作成し、パラレル・テキスト問合せを実行します。SolrIndexクラスでのgetPartitionedメソッドの呼出し数は、サブディレクトリの合計数と使用される接続の数によって制御されます。

import oracle.pg.text.solr.*;
import org.apache.solr.client.solrj.*;

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 args, szGraphName);

// Clear existing vertices/edges in the property graph 
opg.clearRepository(); 

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";

// This object will handle parallel data loading
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop); 

String configName = "opgconfig";
String solrServerUrl = args[4];//"localhost:2181/solr"
String solrNodeSet = args[5]; //"localhost:8983_solr";
 
int zkTimeout = 15; // zookeeper timeout in seconds
int numShards = Integer.parseInt(args[6]); // number of shards in the index
int replicationFactor = 1; // replication factor
int maxShardsPerNode = 1; // maximum number of shards per node
 
// Create an automatic index using SolrCloud
OracleIndexParameters indexParams = 
 OracleIndexParameters.buildSolr(configName, 
 solrServerUrl, 
 solrNodeSet, 
 zkTimeout          /* zookeeper timeout in seconds */,
 numShards          /* total number of shards */,
 replicationFactor  /* Replication factor */,
 maxShardsPerNode   /* maximum number of shardsper node*/,
 4                  /* dop used for scan */,
 10000              /* batch size before commit*/,
 500000             /* commit size before SolrCloud commit*/,
 15                 /* write timeout in seconds */
);

opg.setDefaultIndexParameters(indexParams);

// Create auto indexing on name property for all vertices
System.out.println("Create automatic index on name and country for vertices");
String[] indexedKeys = new String[2];
indexedKeys[0]="name";
indexedKeys[1]="country";
opg.createKeyIndex(indexedKeys, Vertex.class);

// Get the SolrIndex object 
SolrIndex<Vertex> index = (SolrIndex<Vertex>) opg.getAutoIndex(Vertex.class);

// Search first for Key name with property value Beyon* using only string 
//data types
String szQueryStrBey = index.buildSearchTerm("name", "Beyo*", String.class);
String key = index.appendDatatypesSuffixToKey("country", String.class);
String value = index.appendDatatypesSuffixToValue("United States", String.class);

String szQueryStrCountry = key + ":" + value;
Solrquery query = new SolrQuery(szQueryStrBey + " AND " + szQueryStrCountry);

//Query using get operation
index.get(query);

// Open an array of connections to handle connections to SolrCloud needed 
// for parallel text search
CloudSolrServer[] conns = new CloudSolrServer[dop];

for (int idx = 0; idx < conns.length; idx++) {
conns[idx] = index.getCloudSolrServer(15 /* write timeout in 
secs*/);
}

// Iterate to cover all the shards in the index
long lCount = 0;
for (int split = 0; split < index.getTotalShards(); 
 split += conns.length) {
// Gets elements from split to split + conns.length
Iterable<Vertex>[] iterAr = index.getPartitioned(conns /* connections */, 
 query, 
 split /* start split ID */);

lCount = countFromIterables(iterAr); /* Consume iterables in parallel */
}

// Close the connections to SolCloud after completion
for (int idx = 0; idx < conns.length; idx++) { 
  conns[idx].shutdown();
}

// Count results
System.out.println("Vertices found using parallel query: " + lCount);

5.5.10 プロパティ・グラフ・データのテキスト索引に対するネイティブ問合せ結果の使用

プロパティ・グラフ・データに対してネイティブ問合せ結果を直接使用すると、ユーザーがテキスト索引エンジン(Apache LuceneまたはSolrCloud)の問合せ機能を最大限に活用できるようになります。この方法により、ユーザーは、テキスト・エンジンに対して様々なタイプの問合せ(ファセット問合せなど)を実行し、取得した結果を頂点(またはエッジ)オブジェクトに解析できます。

問合せ関係とともにテキスト検索を使用すると、特定の結果オブジェクトからすべての頂点を保持するIterableオブジェクトが生成されます。このアプローチでは、結果セット順序に基づいて結果が自動的にランク付けされます。

Apache LuceneまたはSolrCloud索引に対して検索問合せを直接実行するには、照合対象のキー/値ペアによって使用されるデータ型、および使用される検索エンジンの構成を考慮する必要がある場合があります。検索条件の構築の詳細は、「データ型の処理」を参照してください。

  • Apache Luceneを使用したネイティブ問合せ結果の使用

  • SolrCloudを使用したネイティブ問合せ結果の使用

Apache Luceneを使用したネイティブ問合せ結果の使用

LuceneIndexでメソッドget(TopDocs)を呼び出すことにより、Apache Luceneを使用してネイティブ問合せ結果を使用できます。TopDocsオブジェクトには、特定のApache Luceneディレクトリに対するテキスト検索問合せと一致するドキュメント・セットが用意されています。LuceneIndexは、TopDocsオブジェクト内で見つかったドキュメントからのすべての頂点(またはエッジ)を保持するIterableオブジェクトを作成します。

Apache Luceneを使用したOracleプロパティ・グラフ・テキスト索引は、複数のApache Luceneディレクトリを使用して作成されます。索引付けされた頂点およびエッジは、記憶域のスケーラビリティおよび問合せのパフォーマンスを高めるためにディレクトリ間で分散されます。プロパティ・グラフのテキスト索引内のすべてのデータに対して問合せを実行する必要がある場合、各Apache Luceneディレクトリに対して問合せを実行します。LuceneIndex内のAPI getOracleSearcherを使用することにより、ディレクトリに関連付けられたIndexSearcherオブジェクトを簡単に取得できます。

次のコード・フラグメントは、Apache Lucene検索エンジンを使用して自動テキスト索引を生成し、Lucene問合せを作成し、これをIndexSearcherオブジェクトに対して実行してTopDocsオブジェクトを取得します。後で、特定の結果オブジェクトから頂点のIterableオブジェクトが作成されます。

import oracle.pg.text.lucene.LuceneIndex;
import org.apache.lucene.search.*;
import org.apache.lucene.index.*;

...

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 ���);

// Create an automatic index
OracleIndexParameters indexParams = OracleIndexParameters.buildFS(dop /* number of directories */,
dop /* number of connections
used when indexing */,
10000 /* batch size before commit*/,
500000 /* commit size before Lucene commit*/,
true /* enable datatypes */,
"./lucene-index" /* index location */);

opg.setDefaultIndexParameters(indexParams);

// Create auto indexing on name and country properties for all vertices
System.out.println("Create automatic index on name and country for vertices");
String[] indexedKeys = new String[2];
indexedKeys[0]="name";
indexedKeys[1]="country";
opg.createKeyIndex(indexedKeys, Vertex.class);

// Get the LuceneIndex object 
LuceneIndex<Vertex> index = (LuceneIndex<Vertex>) opg.getAutoIndex(Vertex.class);

// Search first for Key name with property value Beyon* using only string 
//data types
Term term = index.buildSearchTermObject("name", "Beyo*", String.class);
Query queryBey = new WildcardQuery(term);

// Add another condition to query all the vertices whose country is 
//"United States"
String key = index.appendDatatypesSuffixToKey("country", String.class);
String value = index.appendDatatypesSuffixToValue("United States", String.class);

Query queryCountry = new PhraseQuery();
StringTokenizer st = new StringTokenizer(value);
while (st.hasMoreTokens()) {
  queryCountry.add(new Term(key, st.nextToken()));
};

//Concatenate queries
BooleanQuery bQuery = new BooleanQuery();
bQuery.add(queryBey, BooleanClause.Occur.MUST);
bQuery.add(queryCountry, BooleanClause.Occur.MUST);


// Get the IndexSearcher object needed to execute the query. 
// The index searcher object is mapped to a single Apache Lucene directory
SearcherManager searcherMgr = 
         index.getOracleSearcherManager(0, true /* skip looking in the cache*/); 
IndexSearcher indexSearcher = searcherMgr.acquire();
// search for the first 1000 results in the current index directory 0
TopDocs docs = index.search(bQuery, 1000); 

long lCount = 0;
Iterable<Vertex> it = index.get(docs);

while (it.hasNext()) {
  System.out.println(it.next());
  lCount++;
}
System.out.println("Vertices found: "+ lCount);

SolrCloudを使用したネイティブ問合せ結果の使用

SolrIndexでメソッドget(QueryResponse)を呼び出すことにより、SolrCloudを使用してネイティブ問合せ結果を使用できます。QueryResponseオブジェクトには、特定のSolrCloudコレクションに対するテキスト検索問合せと一致するドキュメント・セットが用意されています。SolrIndexは、QueryResponseオブジェクト内で見つかったドキュメントからのすべての頂点(またはエッジ)を保持するIterableオブジェクトを作成します。

次のコード・フラグメントは、Apache SolrCloud検索エンジンを使用して自動テキスト索引を生成し、SolrQueryオブジェクトを作成し、これをCloudSolrServerオブジェクトに対して実行してQueryResponseオブジェクトを取得します。後で、特定の結果オブジェクトから頂点のIterableオブジェクトが作成されます。

import oracle.pg.text.solr.*;
import org.apache.solr.client.solrj.*;

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(
 ���);

String configName = "opgconfig";
String solrServerUrl = args[4];//"localhost:2181/solr"
String solrNodeSet = args[5]; //"localhost:8983_solr";
 
int zkTimeout = 15; // zookeeper timeout in seconds
int numShards = Integer.parseInt(args[6]); // number of shards in the index
int replicationFactor = 1; // replication factor
int maxShardsPerNode = 1; // maximum number of shards per node
 
// Create an automatic index using SolrCloud
OracleIndexParameters indexParams = 
 OracleIndexParameters.buildSolr(configName, 
 solrServerUrl, 
 solrNodeSet, 
 zkTimeout          /* zookeeper timeout in seconds */,
 numShards          /* total number of shards */,
 replicationFactor  /* Replication factor */,
 maxShardsPerNode   /* maximum number of shardsper node*/,
 4                  /* dop used for scan */,
 10000              /* batch size before commit*/,
 500000             /* commit size before SolrCloud commit*/,
 15                 /* write timeout in seconds */
);

opg.setDefaultIndexParameters(indexParams);

// Create auto indexing on name property for all vertices
System.out.println("Create automatic index on name and country for vertices");
String[] indexedKeys = new String[2];
indexedKeys[0]="name";
indexedKeys[1]="country";
opg.createKeyIndex(indexedKeys, Vertex.class);

// Get the SolrIndex object 
SolrIndex<Vertex> index = (SolrIndex<Vertex>) opg.getAutoIndex(Vertex.class);

// Search first for Key name with property value Beyon* using only string 
//data types
String szQueryStrBey = index.buildSearchTerm("name", "Beyo*", String.class);
String key = index.appendDatatypesSuffixToKey("country", String.class);
String value = index.appendDatatypesSuffixToValue("United States", String.class);

String szQueryStrCountry = key + ":" + value;
Solrquery query = new SolrQuery(szQueryStrBey + " AND " + szQueryStrCountry);

CloudSolrServer conn = index.getCloudSolrServer(15 /* write timeout in 
secs*/);

//Query using get operation
QueryResponse qr = conn.query(query, SolrRequest.METHOD.POST);
Iterable<Vertex> it = index.get(qr);

long lCount = 0;

while (it.hasNext()) {
  System.out.println(it.next());
  lCount++;
}

System.out.println("Vertices found: "+ lCount);

5.6 PGQLを使用したプロパティ・グラフ・データに対する問合せ

Oracle Big Data Spatial and Graphは、豊富なグラフ・パターン一致機能セットをサポートしています。

これには、PGQL (Property Graph Query Language)と呼ばれるSQLに似た宣言言語が用意されています。PGQLを使用すると、頂点とエッジ、および頂点とエッジのプロパティに関する制約で構成されたグラフ問合せパターンを表現できます。詳細は、次を参照してください。

プロパティ・グラフ問合せの例を次に示します。これにより、古来の有名な格言である「敵の敵は味方である」から着想を得たグラフ・パターンが定義されます。この例では、変数xyzが頂点に使用され、変数e1e2がエッジに使用されます。エッジ・ラベルに対する制約があり、問合せによって頂点xおよびynameプロパティの値が返されます(予測されます。)。

SELECT x.name, z.name
WHERE
  x -[e1:'feuds']-> y,
  y -[e2:'feuds']-> z

前の問合せを正常に実行するには、インメモリー・グラフの構築時に、頂点/エッジ・プロパティに加えて、エッジ・ラベルを読み込むために必要なフラグを設定します。Oracle NoSQL Databaseのグラフ構成の例は、次のとおりです。

cfg = GraphConfigBuilder.setName(...) .hasEdgeLabel(true).setLoadEdgeLabel(true) .addEdgeProperty(...).build();

問合せは、Groovyシェル環境で実行することも、Javaから実行することもできます。たとえば、前の問合せをApache HBaseまたはOracle NoSQL Database用のGroovyシェルから実行するには、最初にグラフをデータベースからインメモリー・アナリストに読み込み、インメモリー・グラフを取得し、queryPgql関数を呼び出します。

// Read graph data from a backend database into memory
// Note that opg is an instance of OraclePropertyGraph class
opg-hbase> G = session.readGraphWithProperties(opg.getConfig());
opg-hbase> 

resultSet = G.queryPgql("SELECT x.name, z.name WHERE x -[e1 WITH label = 'feuds']-> y,  y -[e2 WITH label = 'feuds']-> z")

結果セット内で最初に予測した変数の型および変数名を取得するには、次を入力できます。

opg-hbase> resultElement = resultElements.get(0)
opg-hbase> type = resultElement.getElementType() // STRING
opg-hbase> varName = resultElement.getVarName() // x.name

また、結果セットを反復することもできます。次に例を示します。

opg-hbase> resultSet.getResults().each { \
       // the variable 'it' is implicitly declared to references each PgqlResult instance
     }

最後に、結果を表示(出力)できます。たとえば、最初の10の行を表示するには、次のようにします。

opg-hbase> resultSet.print(10) // print the first 10 results

関連項目:

PGQLを使用してインメモリー・グラフに対してパターンマッチング問合せを発行する例は、「グラフを使用したパターンマッチング問合せの使用」を参照してください

5.7 プロパティ・グラフ・データを使用したApache Sparkの使用

Apache Sparkは、大量のデータを効率的に処理することを可能にし、データを処理するためのライブラリ・セット(SQL、MLlib、Spark StreamingおよびDataFrame)が用意されています。Apache Sparkでは、HDFS、Oracle NoSQL DatabaseおよびApache HBaseなどの様々なソースからデータを読み込むことができます。

Oracle NoSQL DatabaseまたはApache HBaseに格納されているグラフ・データに対してApache Sparkジョブを実行するために、ヘルパー・メソッドのセットが用意されています。この方法により、Apache Sparkベースのアプリケーションにグラフを簡単にロードできるため、Spark SQLを使用して情報を問い合せたり、MLlibに用意されている関数を実行したりできるようになります。

インタフェースSparkUtilsBaseには、頂点(およびエッジ)表に格納されている頂点またはエッジの情報をすべて収集するためのメソッドのセットが用意されています。この情報には、頂点(またはエッジ)識別子、プロパティ名と値、およびラベル、入力および出力頂点(エッジの場合のみ)が含まれます。SparkUtilsは、(CDH 5.7および5.9に含まれる) Sparkバージョン1.6を使用します。

SparkUtilsBaseには、バックエンド表からグラフ情報にデータ変換するために次のメソッドが含まれます。

  • getGraphElementReprOnDB(dbObj): バックエンド・データベースに格納されている頂点(またはエッジ)のデータベース表現を取得します。

  • getElementID(Object graphElementReprOnDB): グラフ要素(頂点またはエッジ) IDを取得します。

  • getPropertyValue(Object graphElementReprOnDB, String key): 特定のプロパティ・キーのグラフ要素のプロパティ値を取得します。

  • getPropertyNames(Object graphElementReprOnDB): バックエンド・データベースから特定のグラフ要素表現のプロパティ名のセットを返します。

  • isElementForVertex(Object graphElementReprOnDB): データベース結果から取得した特定のグラフ要素オブジェクトが頂点の表現であるかどうかを検証します。

  • isElementForEdge(Object graphElementReprOnDB): データベース結果から取得した特定のグラフ要素オブジェクトが頂点の表現であるかどうかを検証します。

  • getInVertexID(Object graphElementReprOnDB): エッジのデータベース表現から入力頂点IDを取得します。

  • getOutVertexID(Object graphElementReprOnDB): エッジのデータベース表現から出力頂点IDを取得します。

  • getEdgeLabel(Object graphElementReprOnDB): エッジのデータベース表現からエッジ・ラベルを取得します。

5.7.1 Apache HBase内のプロパティ・グラフ・データを使用したApache Sparkの使用

oracle.pg.hbase.SparkUtilsクラスには、Apache HBaseに格納されている<graph_name>VT. (または<graph_name>GE.)表内の行として表現される頂点(またはエッジ)に関する情報を収集するメソッドが含まれます。Apache HBaseでは、表をスキャンする場合、各行には対応するorg.apache.hadoop.hbase.client.Resultオブジェクトがあります。

SparkUtilsを使用してApache Sparkジョブをプロパティ・グラフに対して実行するには、最初にグラフ・データをApache Spark RDDオブジェクトにロードする必要があります。これを行うには、sc (アプリケーションのSparkコンテキスト)を作成する必要があります。次の例では、Sparkコンテキスト・オブジェクトを作成します。

import org.apache.spark.SparkContext.*;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import oracle.pg.hbase.SparkUtils; 
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.mapreduce.TableInputFormat;
import org.apache.hadoop.conf.Configuration;

SparkContext sc = new SparkContext(new SparkConf().setAppName("Example")
                                                  .setMaster("spark://localhost:7077"));

このコンテキストを使用して、newAPIHadoopRDDメソッドを呼び出すことにより、HadoopファイルからRDDを簡単に取得できます。これを行うには、Apache HBaseに格納されている頂点およびエッジ表にアクセスするためのHadoop構成オブジェクトを最初に作成する必要があります。構成オブジェクトは、Apache HBaseに接続するために使用するパラメータ(Zookeeper定数、Zookeperクライアント・ポートおよび表名など)を指定します。この構成オブジェクトは、newAPIHadoopRDDとともにInputFormatおよびそのキーと値のクラスによって使用されます。このメソッドの結果は、RDD[(ImmutableBytesWritable, Result)]型のRDDになります。

次の例では、Apache HBaseに接続し、グラフの頂点表を読み込むための構成オブジェクトを作成します。socialNetVT.が、グラフの頂点に関する情報が含まれるApache HBase表の名前であることを前提とします。後で、この構成を使用して頂点表からRDDを取得します。

Configuration hBaseConfVertices = HBaseConfiguration.create();
hBaseConfVertices.set(TableInputFormat.INPUT_TABLE, "socialNetVT.")
hBaseConfVertices.set("hbase.zookeeper.quorum", "node041,node042,node043")
hBaseConfVertices.set("hbase.zookeeper.port", "2181")

JavaPairRDD<ImmutableBytesWritable,Result> bytesResultVertices = 
sc.newAPIHadoopRDD(hBaseConfVertices, 
                   TableInputFormat.class,
                   ImmutableBytesWritable.class, 
                    Result.class)

同様に、次の例では、Apache HBaseに格納されているエッジ表に接続し、表の行のRDDを取得するための構成オブジェクトを作成します。socialNetGE.は、エッジ定義が含まれる表の名前です。

Configuration hBaseConfEdges = HBaseConfiguration.create();
hBaseConfEdges.set(TableInputFormat.INPUT_TABLE, "socialNetGE.")
hBaseConfEdges.set("hbase.zookeeper.quorum", "node041,node042,node043")
hBaseConfEdges.set("hbase.zookeeper.port", "2181")

JavaPairRDD<ImmutableBytesWritable,Result> bytesResultEdges = 
sc.newAPIHadoopRDD(hbaseConfEdges, 
                   TableInputFormat.class,
                   ImmutableBytesWritable.class,
                   Result.class)

各結果オブジェクトにはグラフのエッジの各ノードの属性が含まれるため、その情報を抽出するためにこれらのRDDに変換を適用する必要があります。oracle.pg.hbase.SparkUtilsは、このような変換を定義する上で役に立つ複数のメソッドを実装します。

たとえば、結果オブジェクトから各頂点属性値を抽出し、頂点のIDおよび名前を格納するJava BeanクラスであるMyVertexのオブジェクト・インスタンスを作成する変換を定義できます。次の例では、頂点を表す特定の結果オブジェクトから識別子および名前キー/値ペアを抽出するためにSparkUtilsを使用するメソッドres2vertexを定義します。

public static MyVertex res2vertex(Result res) throws Exception
{
SparkUtils su = SparkUtils.getInstance();
	Object dbRepr = su.getGraphElementReprOnDB(res);
	long id = su.getElementId(dbRepr);
	String name = (String)su.getPropertyValue(dbRepr, "name");
	return new MyVertex(id,name);
}

メソッドgetGraphElemetReprOnDBは、Apache HBaseに格納されているグラフ要素表現を返し、パラメータがnullまたは対応するクラスの非インスタンスである場合はIllegalArgumentException例外をスローします。この表現はデータベース固有(Apache HBaseでのみ使用可能)であり、戻り値はインタフェースに定義されている他のAPIのみによって使用される必要があります。Apache HBaseの場合、dbReprResultクラスのnull以外のインスタンスです。データベース表現オブジェクトが生成されたら、これを、インタフェースに定義されている他の任意のメソッドのパラメータとして渡すことができます。

メソッドgetElementIdは頂点のIDを返し、メソッドgetPropertyValueはオブジェクトdbReprから属性値nameを取得します。不適切なパラメータが渡された場合、例外IOExceptionおよびjava.text.ParseExceptionがスローされます。

次の例では、エッジを表す特定の結果オブジェクトから識別子、ラベルおよび入力/出力頂点を抽出するためにSparkUtilsを使用するメソッドres2edgeを定義します。

public static MyEdge res2Edge( Result res) throws Exception
{
SparkUtils su = SparkUtils.getInstance();
	Object dbRepr = su.getGraphElementReprOnDB(res);
	long rowId    = su.getElementId(dbRepr);
	String label  = (String)su.getEdgeLabel(dbRepr);
	long inVertex = (long)su.getInVertexId(dbRepr);
	long outVertex = (long)su.getOutVertexId(dbRepr);
	return new MyEdge(rowId,inVertex,outVertex,label);
}

これらの変換が生成されたら、これらをbytesResultVerticesおよびbytesResultEdgesの値セットにマップできます。次に例を示します。

JavaRDD<Result> resultVerticesRDD = bytesResult.values();
JavaRDD<Vertex> nodesRDD = resultVerticesRDD.map(result ->  MyConverters.res2vertex(result));
JavaRDD<Result> resultEdgesRDD = bytesResultEdges.values();
JavaRDD<Edge> edgesRDD = resultEdgesRDD.map(result -> MyConverters.res2Edge(result));

これにより、Sparkアプリケーションで、nodesRDDおよびedgesRDDの操作を開始できます。たとえば、Spark SQL問合せを実行するために対応するデータ・フレームを作成できます。次の例では、SQLコンテキストを作成し、nodesRDDおよびedgesRDDから2つのデータ・フレームを取得し、ID 1を持つ頂点のすべての友人を取得する問合せを実行します。

SQLContext sqlCtx = new SQLContext(sc);
DataFrame verticesDF = sqlCtx.createDataFrame(verticesRDD);
verticesDF.registerTempTable("VERTICES_TABLE");

DataFrame edgesDF = sqlCtx.createDataFrame(edgesRDD);
edgesDF.registerTempTable("EDGES_TABLE");

sqlCtx.sql("select name from (select target from EDGES_TABLE WHERE source = 1) REACHABLE
left join VERTICES_TABLE on VERTICES_TABLE.id = REACHABLE.target ").show();

この場合、SparkではクラスMyVertexおよびMyEdgeを使用してデータ・フレームの列名を探すために、これらのクラスが重要な役割を果たします。

Apache HBaseからグラフ・データを直接読み込んだり、Apache Spark内のグラフに対して操作を実行したりする以外にも、「インメモリー・アナリストを使用したApache Spark内のグラフ・データの分析」で説明されているように、インメモリー・アナリストを使用してApache Spark内のグラフ・データを分析できます。

5.7.2 Oracle NoSQL Databaseに格納されているプロパティ・グラフ・データとApache Sparkとの統合

oracle.pg.nosql.SparkUtilsクラスには、Oracle NoSQL Databaseに格納されている<graph_name>VT_ (または<graph_name>GE_)表内の行として表現される頂点(またはエッジ)に関する情報を収集するメソッドが含まれます。Oracle NoSQL Databaseでは、表をスキャンする場合、表内の各行には対応するoracle.kv.table.Rowオブジェクトがあります。

SparkUtilsを使用してApache Sparkジョブをプロパティ・グラフに対して実行するには、最初にグラフ・データをApache Spark RDDオブジェクトにロードする必要があります。これを行うには、sc (アプリケーションのSparkコンテキスト)を作成する必要があります。次の例は、Sparkコンテキスト・オブジェクトを作成する方法を示します。

import java.io.*;
import org.apache.spark.SparkContext.*;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.DataFrame;
import oracle.kv.hadoop.table.TableInputFormat;
import oracle.kv.table.PrimaryKey;
import oracle.kv.table.Row;
import org.apache.hadoop.conf.Configuration;

SparkConf sparkConf = new SparkConf().setAppName("Testing SparkUtils").setMaster(���local���);
			
JavaSparkContext sc = new JavaSparkContext(sparkConf);	

このコンテキストを使用して、newAPIHadoopRDDメソッドを呼び出すことにより、HadoopファイルからRDDを簡単に取得できます。RDDを作成するには、Oracle NoSQL Databaseに格納されている頂点およびエッジ表にアクセスするためのHadoop構成オブジェクトを最初に作成する必要があります。この構成オブジェクトは、newAPIHadoopRDDとともにInputFormatおよびそのキーと値のクラスによって使用されます。このメソッドの結果は、RDD[(PrimaryKey, Row)]型のRDDになります。

次の例では、Oracle NoSQL Databaseに接続し、グラフの頂点表を読み込むための構成オブジェクトを作成します。socialNetVT_が、グラフの頂点情報が含まれる表の名前であることを前提とします。後で、この構成を使用して頂点表からRDDを取得します。

   Configuration noSQLNodeConf = new Configuration();
   noSQLNodeConf.set("oracle.kv.kvstore", "kvstore");
   noSQLNodeConf.set("oracle.kv.tableName", ���socialNetVT_���);
   noSQLNodeConf.set("oracle.kv.hosts", "localhost:5000");

同様に、次の例では、Oracle NoSQL Databaseに格納されているエッジ表に接続し、表の行のRDDを取得するための構成オブジェクトを作成します。socialNetGE_は、エッジ・データが含まれる表の名前です。

  Configuration noSQLEdgeConf = new Configuration();
  noSQLEdgeConf.set("oracle.kv.kvstore", "kvstore");
  noSQLEdgeConf.set("oracle.kv.tableName", ���socialNetGE_���);
  noSQLEdgeConf.set("oracle.kv.hosts", "localhost:5000"); 

JavaPairRDD<PrimaryKey,Row> bytesResultVertices = sc.newAPIHadoopRDD(noSQLNodeConf,
            oracle.kv.hadoop.table.TableInputFormat.class,PrimaryKey.class, Row.class);
                                                                               
JavaPairRDD<PrimaryKey,Row> bytesResultEdges = sc.newAPIHadoopRDD(noSQLEdgeConf,
            oracle.kv.hadoop.table.TableInputFormat.class,
            PrimaryKey.class, Row.class);

行オブジェクトにはグラフの頂点またはエッジの1つ以上の属性が含まれる場合があるため、関連情報を取得するためにこれらのRDDに変換を適用する必要があります。oracle.pg.nosql.SparkUtilsは、このような変換を定義する上で役に立つ複数のメソッドを実装します。

たとえば、結果オブジェクトから頂点プロパティ値を抽出し、頂点のIDおよび名前を格納するJava BeanクラスであるMyVertexのオブジェクト・インスタンスを作成する変換を定義できます。次の例では、頂点を表す特定の行オブジェクトから識別子および名前キー/値ペアを抽出するためにSparkUtilsを使用するメソッドres2vertexを定義します。

public static MyVertex res2vertex(Row res) throws Exception
{
	SparkUtils su = SparkUtils.getInstance();
	Object dbRepr = su.getGraphElementReprOnDB(res);
	long id = su.getElementId(dbRepr);
	String name = (String)su.getPropertyValue(dbRepr, "name");
	return new MyVertex(id,name);
}

メソッドgetGraphElemetReprOnDBは、Oracle NoSQL Databaseに格納されているグラフ要素表現を返し、パラメータがnullまたは対応するクラスの非インスタンスである場合はIllegalArgumentException例外をスローします。この表現はデータベース固有であり、戻り値はインタフェースに定義されている他のAPIのみによって使用される必要があります。Oracle NoSQL Databaseの場合、dbReprRowクラスのnull以外のインスタンスです。データベース表現オブジェクトが生成されたら、これを、インタフェースに定義されている他の任意のメソッドのパラメータとして渡すことができます。

メソッドgetElementIdは頂点のIDを返し、メソッドgetPropertyValueはオブジェクトdbReprから属性値“name”を取得します。不適切なパラメータが渡された場合、例外IOExceptionおよびjava.text.ParseExceptionがスローされます。

同様に、ID、ラベルおよび入力/出力頂点ID値を格納するJava Beanクラスを使用して、行オブジェクトからMyEdgeのオブジェクト・インスタンスを作成するための変換を定義できます。次の例では、エッジを表す特定の行オブジェクトから識別子、ラベルおよび入力/出力頂点IDを抽出するためにSparkUtilsを使用するメソッドres2edgeを定義します。

public static MyEdge res2Edge( Row res) throws Exception
{
	SparkUtils su = SparkUtils.getInstance();
	Object dbRepr = su.getGraphElementReprOnDB(res);
	long rowId    = su.getElementId(dbRepr);
	String label  = (String)su.getEdgeLabel(dbRepr);
	long inVertex = (long)su.getInVertexId(dbRepr);
	long outVertex = (long)su.getOutVertexId(dbRepr);
	return new MyEdge(rowId,inVertex,outVertex,label);
}

これらの変換が生成されたら、これらをbytesResultVerticesおよびbytesResultEdgesの値セットにマップできます。

JavaRDD<Row> resultVerticesRDD = bytesResult.values();
JavaRDD<Vertex> nodesRDD = resultVerticesRDD.map(result ->  MyConverters.res2vertex(result));
JavaRDD<Row> resultEdgesRDD = bytesResultEdges.values();
JavaRDD<Edge> edgesRDD = resultEdgesRDD.map(result -> MyConverters.res2Edge(result));

前の手順の後、nodesRDDおよびedgesRDDの操作を開始できます。たとえば、Spark SQL問合せを実行するために対応するデータ・フレームを作成できます。次の例では、SQLコンテキストを作成し、nodesRDDおよびedgesRDDから2つのデータ・フレームを取得し、ID 1を持つ頂点のすべての友人を取得する問合せを実行します。

SQLContext sqlCtx = new SQLContext(sc);
DataFrame verticesDF = sqlCtx.createDataFrame(verticesRDD);
verticesDF.registerTempTable("VERTICES_TABLE");

DataFrame edgesDF = sqlCtx.createDataFrame(edgesRDD);
edgesDF.registerTempTable("EDGES_TABLE");

sqlCtx.sql("select name from (select target from EDGES_TABLE WHERE source = 1) REACHABLE
left join VERTICES_TABLE on VERTICES_TABLE.id = REACHABLE.target ").show();

この場合、SparkではクラスMyVertexおよびMyEdgeを使用してデータ・フレームの列名を確認するために、これらのクラスが重要な役割を果たします。

Oracle NoSQL Databaseからグラフ・データを直接読み込んだり、Apache Spark内のグラフに対して操作を実行したりする以外にも、「インメモリー・アナリストを使用したApache Spark内のグラフ・データの分析」で説明されているように、インメモリー・アナリストを使用してApache Spark内のグラフ・データを分析できます。

5.8 セキュアなOracle NoSQL Databaseのサポート

Oracle Big Data Spatial and Graphプロパティ・グラフ・サポートは、Oracle NoSQL Databaseのセキュア・インストールと非セキュア・インストールの両方で機能します。このトピックでは、セキュアなOracle NoSQL Database設定でプロパティ・グラフ機能を使用する方法についての情報を提供します。

ここでは、セキュアなOracle NoSQL Databaseがすでにインストールされていると想定します(http://docs.oracle.com/cd/NOSQL/html/SecurityGuide/secure_installation.htmlにある『Oracle NoSQL Databaseセキュリティ・ガイド』の「Oracle NoSQL Databaseのセキュア・インストールの実行」で説明されているプロセス)。

セキュア・データベースにアクセスするには、正しい資格情報を持っている必要があります。次のようなユーザーを作成します。

kv-> plan create-user -name myusername -admin -wait

このユーザーにreadwriteおよびdbaadminロールを付与します。次に例を示します。

kv-> plan grant -user myusername -role readwrite -wait
kv-> plan grant -user myusername -role dbadmin -wait

client.securityファイルからlogin_properties.txtを生成する際、ユーザー名が正しいことを確認します。次に例を示します。

oracle.kv.auth.username=myusername

Oracleプロパティ・グラフのクライアント側で、セキュアなOracle NoSQL Databaseと対話するためのセキュリティ関連ファイルおよびライブラリを持っている必要があります。最初に、次のファイル(ディレクトリ)をKVROOT/security/からクライアント側にコピーします。

client.security
client.trust	
login.wallet/
login_properties.txt

セキュア・データベースへのアクセスに必要なパスワードを保持するためにOracle Walletを使用する場合、次の3つのライブラリをクライアント側にコピーして、クラス・パスを正しく設定します。

oraclepki.jar
osdt_cert.jar
osdt_core.jar

データベースとOracleプロパティ・グラフのクライアント側を正しく構成した後、次の2つのアプローチのいずれかを使用して、セキュアなNoSQL Databaseに格納されているグラフに接続できます。

  • Java VM設定を次の形式で使用して、ログイン・プロパティ・ファイルを指定します。

    -Doracle.kv.security=/<your-path>/login_properties.txt

    このJava VMプロパティは、J2EEコンテナにデプロイされたアプリケーション(インメモリー分析を含む)にも設定できます。たとえば、WebLogicサーバーを起動する前に、次の形式で環境変数を設定してログイン・プロパティ構成ファイルを参照できます。

    setenv JAVA_OPTIONS "-Doracle.kv.security=/<your-path>/login_properties.txt"

    次に、通常どおりにOraclePropertyGraph.getInstance(kconfig, szGraphName)を呼び出してOraclePropertyGraphインスタンスを作成します。

  • OraclePropertyGraph.getInstance(kconfig, szGraphName, username, password, truStoreFile)を呼び出し、usernameおよびpasswordにはセキュアなOracle NoSQL Databaseにアクセスするための正しい資格情報、truStoreFileにはクライアント側トラスト・ストア・ファイルclient.trustへのパスを指定します。

    次のコード・フラグメントは、セキュアなOracle NoSQL Databaseにプロパティ・グラフを作成し、データをロードしてから、グラフ内の頂点およびエッジの数をカウントします。

    // This object will handle operations over the property graph 
    OraclePropertyGraph opg = OraclePropertyGraph.getInstance(kconfig,
    szGraphName,
    username,
    password,
    truStoreFile);
    
    // Clear existing vertices/edges in the property graph 
    opg.clearRepository();
    opg.setQueueSize(100); // 100 elements
    
    String szOPVFile = "../../data/connections.opv";
    String szOPEFile = "../../data/connections.ope";
    // This object will handle parallel data loading over the property graph
    System.out.println("Load data for graph " + szGraphName);
    OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
    opgdl.loadData(opg, szOPVFile, szOPEFile, dop);
    // Count all vertices
    long countV = 0;
    Iterator<Vertex> vertices = opg.getVertices().iterator();
    while (vertices.hasNext()) {
    vertices.next();
    countV++;
    }
    
    System.out.println("Vertices found: " + countV);
    // Count all edges
    long countE = 0;
    Iterator<Edge> edges = opg.getEdges().iterator();
    while (edges.hasNext()) {
    edges.next();
    countE++;
    }
    
    System.out.println("Edges found: " + countE);
    

5.9 Apache HBaseに格納されているグラフでのセキュリティの実装

Oracle Big Data Spatial and Graphのプロパティ・グラフを保護するために、Apache HBaseでKerberos認証を使用することが推奨されます。

Oracleのプロパティ・グラフ・サポートは、Cloudera Hadoop (CDH)クラスタのセキュア・インストールと非セキュア・インストールの両方で機能します。このトピックでは、セキュアなApache HBaseインストールについての情報を提供します。

Oracle Big Data Spatial and Graphのプロパティ・グラフを保護するために、Apache HBaseでKerberos認証を使用することが推奨されます。

このトピックでは、Kerberosを使用してセキュアなApache HBaseが構成されており、クライアント・マシンにKerberosライブラリがインストールされ、正しい資格情報を持っていると想定します。詳細は、http://www.cloudera.com/content/cloudera/en/documentation/core/latest/topics/cdh_sg_hbase_authentication.htmlの『Configuring Kerberos Authentication for HBase』を参照してください。Kerberosクラスタおよびクライアントの設定方法の情報は、 http://web.mit.edu/kerberos/krb5-latest/doc/index.htmlの『MIT Kerberos Documentation』を参照してください。

クライアント側で、対応HDFSデーモンと対話するために、Kerberos資格情報を持っている必要があります。さらに、(krb5.confにある)Kerberos構成情報を変更して、レルムおよびホスト名マッピングをセキュアなCDHクラスタで使用されるKerberosレルムに含める必要があります。

次のコード・フラグメントは、BDA.COM上のセキュアなCDHクラスタで使用されるレルムとホスト名マッピングを示しています。

[libdefaults]
 default_realm = EXAMPLE.COM
 dns_lookup_realm = false
 dns_lookup_kdc = false
 ticket_lifetime = 24h
 renew_lifetime = 7d
 forwardable = yes

[realms]
 EXAMPLE.COM = {
kdc = hostname1.example.com:88
kdc = hostname2.example.com:88
admin_server = hostname1.example.com:749
default_domain = example.com
 }
BDA.COM = {
kdc = hostname1.bda.com:88
kdc = hostname2.bda.com:88
admin_server = hostname1.bda.com:749
default_domain = bda.com
 }

[domain_realm]
 .example.com = EXAMPLE.COM
 example.com = EXAMPLE.COM
 .bda.com = BDA.COM
 bda.com = BDA.COM

krb5.confを変更した後、Java Authentication and Authorization Service (JAAS)構成ファイルを使用して資格情報をアプリケーションに提供することにより、Apache HBaseに格納されているグラフに接続できます。これは、非セキュアなApache HBaseインストールを使用するアプリケーションがすでに存在する場合に、コードをまったく変更することなく前述の例と同じ機能を提供します。

JAAS構成が設定されたHBaseでプロパティ・グラフ・サポートを使用するには、次の形式の内容を含むファイルを作成し、keytabおよびprincipalエントリを独自の情報に置き換えます。

Client {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
useTicketCache=true
keyTab="/path/to/your/keytab/user.keytab"
principal="your-user/your.fully.qualified.domain.name@YOUR.REALM";
};

次のコード・フラグメントは、BDA.COM上のセキュアなCDHクラスタで使用されるレルムを含むJAASファイルの例を示しています。

Client {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
useTicketCache=true
keyTab="/path/to/keytab/user.keytab"
principal="hbaseuser/hostname1@BDA.COM";
};

セキュアなHBaseアプリケーションを実行するには、java.security.auth.login.configフラグを使用して、作成したJAAS構成ファイルを指定する必要があります。次の形式のコマンドを使用して、アプリケーションを実行できます。

java -Djava.security.auth.login.config=/path/to/your/jaas.conf/ -classpath ./classes/:../../lib/'*' YourJavaApplication

その後、通常どおりにOraclePropertyGraph.getInstance(conf, hconn, szGraphName)を呼び出してOracleプロパティ・グラフを作成できます。

Oracle Big Data Spatial and Graphプロパティ・グラフ・サポートをセキュアなApache HBaseインストールで使用するための別の方法は、セキュアなHBase構成を使用することです。次のコード・フラグメントは、prepareSecureConfig()を使用してセキュアなHBase構成を取得する方法を示しています。このAPIは、Apache HadoopおよびApache HBaseで使用されるセキュリティ認証設定、および認可されたチケットを認証および取得するためのKerberos資格情報セットを必要とします。

次のコード・フラグメントは、セキュアなApache HBaseにプロパティ・グラフを作成し、データをロードしてから、グラフ内の頂点およびエッジの数をカウントします。

String szQuorum= "hostname1,hostname2,hostname3";
String szCliPort = "2181"; 
String szGraph = "SecureGraph";

String hbaseSecAuth="kerberos";
String hadoopSecAuth="kerberos";
String hmKerberosPrincipal="hbase/_HOST@BDA.COM";
String rsKerberosPrincipal="hbase/_HOST@BDA.COM";
String userPrincipal = "hbase/hostname1@BDA.COM";
String keytab= "/path/to/your/keytab/hbase.keytab";
int dop= 8;

Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", szQuorum);
conf.set("hbase.zookeeper.property.clientPort", szCliPort);

// Prepare the secure configuration providing the credentials in the keytab
conf = OraclePropertyGraph.prepareSecureConfig(conf, 
 hbaseSecAuth, 
 hadoopSecAuth, 
 hmKerberosPrincipal, 
 rsKerberosPrincipal, 
 userPrincipal, 
 keytab);
HConnection hconn = HConnectionManager.createConnection(conf);

OraclePropertyGraph opg=OraclePropertyGraph.getInstance(conf, hconn, szGraph);
opg.setInitialNumRegions(24);
opg.clearRepository();

String szOPVFile = "../../data/connections.opv";
String szOPEFile = "../../data/connections.ope";

// Do a parallel data loading
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
opgdl.loadData(opg, szOPVFile, szOPEFile, dop);
opg.commit();

5.10 プロパティ・グラフ・データでのGroovyシェルの使用

Oracle Big Data Spatial and Graphプロパティ・グラフ・サポートには、組込みのGroovyシェル(オリジナルのGremlin Groovyシェル・スクリプトに基づく)が含まれています。このコマンドライン・シェル・インタフェースを使用して、Java APIを参照できます。

Groovyシェルを起動するには、インストール・ホーム(デフォルトでは/opt/oracle/oracle-spatial-graph/property_graph)の下にあるdal/groovyディレクトリに移動します。次に例を示します。

cd /opt/oracle/oracle-spatial-graph/property_graph/dal/groovy/

ここには、Oracle NoSQL DatabaseとApache HBaseにそれぞれ接続するためのスクリプトgremlin-opg-nosql.shおよびgremlin-opg-hbase.shが含まれています。

注意:

gremlinトラバースの例を実行するには、最初に次のインポート操作を実行する必要があります。
import com.tinkerpop.pipes.util.structures.*;

次の例は、Oracle NoSQL Databaseに接続し、グラフ名myGraphを持つOraclePropertyGraphのインスタンスを取得し、いくつかのサンプル・グラフ・データをロードして、頂点およびエッジのリストを取得します。

$ ./gremlin-opg-nosql.sh
 
opg-nosql>
opg-nosql> hhosts = new String[1];
==>null
 
opg-nosql> hhosts[0] = "bigdatalite:5000";
==>bigdatalite:5000
 
opg-nosql> cfg = GraphConfigBuilder.forPropertyGraphNosql().setName("myGraph").setHosts(Arrays.asList(hhosts)).setStoreName("mystore").addEdgeProperty("lbl", PropertyType.STRING, "lbl").addEdgeProperty("weight", PropertyType.DOUBLE, "1000000").build();
==>{"db_engine":"NOSQL","loading":{},"format":"pg","name":"myGraph","error_handling":{},"hosts":["bigdatalite:5000"],"node_props":[],"store_name":"mystore","edge_props":[{"type":"string","name":"lbl","default":"lbl"},{"type":"double","name":"weight","default":"1000000"}]}
 
opg-nosql> opg = OraclePropertyGraph.getInstance(cfg);
==>oraclepropertygraph with name myGraph
 
opg-nosql> opgdl = OraclePropertyGraphDataLoader.getInstance();
==>oracle.pg.nosql.OraclePropertyGraphDataLoader@576f1cad
 
opg-nosql> opgdl.loadData(opg, new FileInputStream("../../data/connections.opv"), new FileInputStream("../../data/connections.ope"), 1, 1, 0, null);
==>null
 
opg-nosql> opg.getVertices();
==>Vertex ID 5 {country:str:Italy, name:str:Pope Francis, occupation:str:pope, religion:str:Catholicism, role:str:Catholic religion authority}
[... other output lines omitted for brevity ...]
 
opg-nosql>  opg.getEdges();
==>Edge ID 1139 from Vertex ID 64 {country:str:United States, name:str:Jeff Bezos, occupation:str:business man} =[leads]=> Vertex ID 37 {country:str:United States, name:str:Amazon, type:str:online retailing} edgeKV[{weight:flo:1.0}]
[... other output lines omitted for brevity ...]

次の例は、インメモリー分析用のいくつかの構成パラメータをカスタマイズします。ここでは、Apache HBaseに接続し、グラフ名myGraphを持つOraclePropertyGraphのインスタンスを取得し、いくつかのサンプル・グラフ・データをロードし、頂点およびエッジのリストを取得し、インメモリー・アナリストを取得して、組込み分析の1つであるトライアングル・カウンティングを実行します。

$ ./gremlin-opg-hbase.sh
opg-hbase>
opg-hbase> dop=2;   // degree of parallelism
==>2
opg-hbase> confPgx = new HashMap<PgxConfig.Field, Object>();
opg-hbase> confPgx.put(PgxConfig.Field.ENABLE_GM_COMPILER, false);
==>null
opg-hbase> confPgx.put(PgxConfig.Field.NUM_WORKERS_IO, dop + 2);
==>null
opg-hbase> confPgx.put(PgxConfig.Field.NUM_WORKERS_ANALYSIS, 3);
==>null
opg-hbase> confPgx.put(PgxConfig.Field.NUM_WORKERS_FAST_TRACK_ANALYSIS, 2);
==>null
opg-hbase> confPgx.put(PgxConfig.Field.SESSION_TASK_TIMEOUT_SECS, 0);
==>null
opg-hbase> confPgx.put(PgxConfig.Field.SESSION_IDLE_TIMEOUT_SECS, 0);
==>null
opg-hbase> instance = Pgx.getInstance()
==>null
opg-hbase> instance.startEngine(confPgx) 
==>null

opg-hbase> cfg = GraphConfigBuilder.forPropertyGraphHbase() .setName("myGraph") .setZkQuorum("bigdatalite") .setZkClientPort(iClientPort) .setZkSessionTimeout(60000) .setMaxNumConnections(dop) .setLoadEdgeLabel(true) .setSplitsPerRegion(1) .addEdgeProperty("lbl", PropertyType.STRING, "lbl") .addEdgeProperty("weight", PropertyType.DOUBLE, "1000000") .build();
==>{"splits_per_region":1,"max_num_connections":2,"node_props":[],"format":"pg","load_edge_label":true,"name":"myGraph","zk_client_port":2181,"zk_quorum":"bigdatalite","edge_props":[{"type":"string","default":"lbl","name":"lbl"},{"type":"double","default":"1000000","name":"weight"}],"loading":{},"error_handling":{},"zk_session_timeout":60000,"db_engine":"HBASE"}
 
opg-hbase> opg = OraclePropertyGraph.getInstance(cfg);  
==>oraclepropertygraph with name myGraph
 
 
opg-hbase> opgdl = OraclePropertyGraphDataLoader.getInstance();
==>oracle.pg.hbase.OraclePropertyGraphDataLoader@3451289b
 
opg-hbase> opgdl.loadData(opg, "../../data/connections.opv", "../../data/connections.ope", 1, 1, 0, null);
==>null
 
opg-hbase> opg.getVertices();
==>Vertex ID 78 {country:str:United States, name:str:Hosain Rahman, occupation:str:CEO of Jawbone}
...
 
opg-hbase> opg.getEdges();
==>Edge ID 1139 from Vertex ID 64 {country:str:United States, name:str:Jeff Bezos, occupation:str:business man} =[leads]=> Vertex ID 37 {country:str:United States, name:str:Amazon, type:str:online retailing} edgeKV[{weight:flo:1.0}]
[... other output lines omitted for brevity ...]
 
opg-hbase> session = Pgx.createSession("session-id-1");
opg-hbase> g = session.readGraphWithProperties(cfg);
opg-hbase> analyst = session.createAnalyst();
 
opg-hbase>  triangles = analyst.countTriangles(false).get();
==>22

Java APIの詳細は、インストール・ホーム(デフォルトでは/opt/oracle/oracle-spatial-graph/property_graph/)の下のdoc/dal/およびdoc/pgx/にあるJavadocリファレンス情報を参照してください。

5.11 プロパティ・グラフ・データのRESTサポート

一連のRESTful APIによって、HTTP/RESTプロトコルを介してデータ・アクセス・レイヤーJava APIが公開されます。

これらのRESTful APIは、プロパティ・グラフの作成、更新、問合せおよびトラバースをサポートし、さらに、テキスト検索問合せの実行、gremlinを使用したグラフのトラバース問合せの実行、およびOracle NoSQL DatabaseやApache HBaseなどの複数のデータベース・バックエンドからのグラフの処理をサポートしています。

次のトピックでは、データ・アクセス・レイヤー(DAL)に含まれるREST APIを使用して、Oracle Big Data Spatial and Graphプロパティ・グラフ・サポートのためにRESTful Webサービスを作成する方法について説明します。このサービスを後でApache TomcatまたはOracle WebLogic Server (12cリリース2以上)にデプロイできます。

5.11.1 REST Webアプリケーション・アーカイブ(WAR)ファイルの構築

このトピックでは、Oracle Big Data Spatial and Graphでプロパティ・グラフのRESTful APIを使用するために、Webアプリケーション・アーカイブ(WAR)ファイルを作成する方法について説明します。

  1. 製品のホーム・ディレクトリの下にあるwebappディレクトリに移動します。
    cd /opt/oracle/oracle-spatial-graph/property_graph/dal/webapp
  2. 使用可能なMavenリポジトリからサード・パーティのライブラリをダウンロードできるように、HTTP_PROXY環境変数を設定します(必要な場合)。次に例を示します。
    setenv HTTP_PROXY www-myproxy.com:80
    export HTTP_PROXY=www-myproxy.com:80
    
  3. スクリプトfetch_required_libraries.shを実行して、RESTful APIに必要なサード・パーティのライブラリをダウンロードします。
  4. サード・パーティのライブラリを格納するディレクトリを指定します。ディレクトリが存在しない場合は、自動的に作成されます。次に例を示します。
    Please enter the directory name where the REST third party libraries will be stored (e.g. /tmp/extlib-unified-rest ): /tmp/extlib-unified-rest

    ディレクトリの作成時および各サード・パーティ・ライブラリのダウンロード時に、スクリプトによって一連の進捗状況の詳細がリストされます。スクリプトの最後に、次のようなメッセージが表示されます。

    Done. The final downloaded jars are in the following directory:
    -rw-r--r--   1 user group  305001 Aug 21  2007 commons-httpclient-3.1.jar
    -rw-r--r--   1 user group   46509 Mar 20  2013 gremlin-java-2.3.0.jar
    -rw-r--r--   1 user group   30226 Oct 13  2016 jackson-jaxrs-base-2.8.4.jar
    -rw-r--r--   1 user group   15807 Oct 13  2016 jackson-jaxrs-json-provider-2.8.4.jar
    -rw-r--r--   1 user group   34589 Oct 13  2016 jackson-module-jaxb-annotations-2.8.4.jar
    -rw-r--r--   1 user group   69940 Jan 19  2017 jersey-entity-filtering-2.25.1.jar
    -rw-r--r--   1 user group   21691 Jan 19  2017 jersey-media-json-jackson-2.25.1.jar
    -rw-r--r--   1 user group   67859 Jan 19  2017 jersey-media-multipart-2.25.1.jar
    -rw-r--r--   1 user group   63977 Jul 17  2015 mimepull-1.9.6.jar
    -rw-r--r--   1 user group   41473 Mar 20  2013 rexster-core-2.3.0.jar
    -rw-r--r--   1 user group   81352 Mar 20  2013 rexster-protocol-2.3.0.jar
    -rw-r--r--   1 user group  712325 Mar 20  2013 rexster-server-2.3.0.jar
    
  5. スクリプトassemble_unified_rest.shを実行して、RESTFul Webアプリケーション・アーカイブを作成します。
    sh assemble_unified_rest.sh
  6. opg_unified.warの構築に使用する一時ディレクトリを指定します。次に例を示します。
    Please enter a temporary work directory name (e.g. /tmp/work_unified): /tmp/work_unified

    スクリプトは、RESTful Webアプリケーション・アーカイブの構築に必要なすべての中間ファイルを保持するために、このディレクトリを使用して、システムの現在の日付(MMDDhhmmss)を使用する一時作業ディレクトリを作成します。これらには、RESTful API、サード・パーティのライブラリ、およびREST構成が含まれます。ディレクトリを作成してこれらの中間ファイルの保持に使用できることを確認する必要があります。

    Is it OK to use /tmp/work_unified/0823150126 to hold some intermediate files? (Yes|No): Yes
  7. 製品のホーム・ディレクトリを指定します。次に例を示します。
    Move on...
    Please enter the directory name to property graph directory (e.g. /opt/oracle/oracle-spatial-graph/property_graph): /opt/oracle/oracle-spatial-graph/property_graph
    
    opt/oracle/oracle-spatial-graph/property_graph seems to be valid

  8. RESTfulサード・パーティ・ライブラリを保持しているディレクトリを指定します。

    これは、前に指定したディレクトリです。例: /tmp/extlib-unified-rest

    必要なディレクトリを設定した後、スクリプトによってREST APIが更新され、Jerseyを使用してREST Webアプリケーション・アーカイブが構成されます。プロセスの最後に、生成されたwarファイルの最終的なサイズおよび場所を示すメッセージが出力されます。次に例を示します。

    assed sanity checking.
    Updating rest logic
    Updating the web application
    Done. The final web application is 
    -rw-r--r-- 1 user group 108219486 Aug 24 08:59 /tmp/work_unified/0823150126/opg_unified.war
    

    この手順を実行すると、作成されたタイムスタンプベースの一時ディレクトリ名(この例では0823150126/)が異なるものになることに注意してください。

5.11.2 RESTfulプロパティ・グラフWebサービスのデプロイ

このトピックでは、opg_unified.warファイルをOracle WebLogic 12.2.0.1またはApache Server Apache Tomcatにデプロイする方法について説明します。

  1. 「REST Webアプリケーション・アーカイブ(WAR)ファイルの構築」で説明されているように、RESTサード・パーティ・ライブラリをダウンロードし、opg_unified.war REST Webアプリケーション・アーカイブ(WAR)ファイルを作成したことを確認します。

  2. 次のコマンドを使用して、opg_unified.warにあるrexster.xmlファイルを抽出します。

    cd /tmp/work_unified/<MMDDhhmmss>/
    jar xf opg_unified.war WEB-INF/classes/rexster.xml
    
  3. REST構成ファイル(rexster.xml)を変更して、デフォルトのバックエンド、バックエンドの追加リスト(存在する場合)、およびプロパティ・グラフ要求を処理するときに使用される使用可能なグラフのリストを指定します。このファイルの詳細は、RESTfulプロパティ・グラフ・サービス構成ファイル(rexster.xml)を参照してください。

  4. 次のようにrexster.xmlファイルを更新して、opg_unified.warを再構築します。

    jar uf opg_unified.war WEB-INF/classes/rexster.xml
  5. 選択したJ2EEコンテナにopg_unified.warをデプロイします。

デプロイメント・コンテナのオプション:

Apache Tomcatを使用したデプロイメント

この項では、Apache Tomcat 8.5.14 (以上)を使用してRESTfulプロパティ・グラフWebサービスをデプロイする方法について説明します。Apache Tomcatは、Java ServletとJavaServer Pages (JSP)を実装するオープンソースのWebサーバーであり、Webアプリケーションを実行するHTTP Webサーバー環境を構築します。Apache Tomcatの詳細は、http://tomcat.apache.org/を参照してください。

  1. Apache Tomcat 8.5.14をダウンロードしてインストールします。

  2. 次のように、Apache Tomcat ServerのWebアプリケーション・ディレクトリに移動し、opg_unified.warファイルをコピーします。

    cd $CATALINA_BASE
    cp -f /tmp/work_unified/<MMDDhhmmss>/opg_unified.war webapps
    

    この操作で、warファイルが展開されてWebアプリケーションがデプロイされます。(Apache TomcatにおけるWebアプリケーションのデプロイの詳細は、Apache Tomcatのドキュメントを参照してください。)

  3. ブラウザで次のURLをオープンしてデプロイされたことを確認します(Webアプリケーションがポート8080にデプロイされることを前提としています): http://<hostname>:8080/opg_unified

    「Welcome to the unified property graph REST interface!」というタイトルのページが表示されます

Oracle WebLogic Serverを使用したデプロイメント

この項では、Oracle WebLogic Server 12cバージョン12.2.1.2.0を使用してRESTfulプロパティ・グラフ・エンドポイントをデプロイする方法について説明します。Oracle WebLogic Serverの詳細は、その製品ドキュメントを参照してください。

  1. Oracle WebLogic Server 12cリリース2 (12.2.1.2.0)をダウンロードしてインストールします。

  2. Jersey 2.5.1 (JAX-RS 2.0. RI)の共有の事前構築済共有ライブラリを登録します(WebLogic Serverインストールに含まれている)。このライブラリは、Big Data Spatial and Graphプロパティ・グラフのRESTful Webサービスなど、Jersey 2.5.1に基づくアプリケーションの実行に必要です。

    1. WebLogic Server管理コンソール(http://localhost:7001/console)にログインします。

    2. 「Deployments」を選択します。

    3. 「Install」をクリックして、共有ライブラリをインストールします。

    4. 「Path」フィールドで、ディレクトリ: MW_HOME\wlserver\common\deployable-librariesを入力するか、このディレクトリまでナビゲートします。

    5. jax-rs-2.0.warファイルを選択し、「Next」をクリックします。

    6. 「Install this deployment as a library」を選択します。

    7. 「Next」をクリックします。

    8. 「Finish」をクリックします。

  3. opg_unified.warを変更して、WebLogic Serverによってすでに提供されているサード・パーティ・ライブラリjerseyおよびhk2を削除します。

    1. opg_unified.warが作成されたwork_unifiedディレクトリの下に一時作業ディレクトリを作成します。次に例を示します。

      cd /tmp/work_unified/<MMDDhhmmss>/
      mkdir work_weblogic
      cd work_weblogic
      
    2. opg_unified.warのコンテンツを一時ディレクトリに抽出します。次に例を示します。

      jar xf ../opg_unified.war
    3. Jersey 2.25サード・パーティ・ライブラリをWEB-INF/libディレクトリから削除します。

      rm –rf WEB-INF/lib/jersey-client-2.25.1.jar
      rm –rf WEB-INF/lib/jersey-common-2.25.1.jar 
      rm –rf WEB-INF/lib/jersey-container-servlet-core-2.25.1.jar 
      rm –rf WEB-INF/lib/jersey-entity-filtering-2.25.1.jar 
      rm –rf WEB-INF/lib/jersey-guava-2.25.1.jar 
      rm –rf WEB-INF/lib/jersey-server-2.25.1.jar
      rm –rf WEB-INF/lib/hk2-api-2.5.0-b32.jar 
      rm –rf WEB-INF/lib/hk2-locator-2.5.0-b32.jar 
      rm –rf WEB-INF/lib/hk2-utils-2.5.0-b32.jar
      

    4. opg_unified.warを再構築します。

      jar cfM ../opg_unified.war * 
  4. WebLogic Serverインストールのautodeployディレクトリに移動し、ファイルをコピーします。次に例を示します。

    cd <domain_name>/autodeploy
    cp -rf /tmp/work_unified/<MMDDhhmmss>/opg_unified.war <domain_name>/autodeploy
    

    上の例で、<domain_name>はWebLogic Serverのドメイン名です。

    開発モードまたは本番モードでWebLogic Serverドメインを実行できますが、自動デプロイメント機能を使用できるのは開発モードのみであることに注意してください。

  5. ブラウザで次のURLをオープンしてデプロイされたことを確認します(Webアプリケーションがポート7001にデプロイされることを前提としています): http://<hostname>:7001/opg_unified

    「Welcome to the unified property graph REST interface!」というタイトルのページが表示されます

5.11.2.1 RESTfulプロパティ・グラフ・サービス構成ファイル(rexster.xml)

Oracle Big Data Spatial and Graphは、Tinkerpop Rexster RESTful APIを拡張してプロパティ・グラフにRESTful機能を提供します。RESTfulサービスの構成を有効にするために、サービスの起動時に設定およびロードする必要があるデータベース・バックエンドおよびグラフの構成を含むrexster.xmlファイルが、opg_unified.warに含まれています。

rexster.xmlファイルは、少なくとも4つのメイン・セクション(またはタグ)を持つXMLベースの構成ファイルです。

  • <script-engines>: プロパティ・グラフに対するスクリプトの実行に使用されるスクリプト・エンジン。デフォルトでは、gremlin-groovyが使用されます。

  • <oracle-pool-size>: プロパティ・グラフに許可される同時接続の数。デフォルトでは、構成でプール・サイズ3が使用されます。

  • <oracle-property-graph-backends>: RESTful APIが使用する必要があるデータベース・バックエンドに関する情報。デフォルトでは、<default-backend>true</default-backend>タグを指定した少なくとも1つのバックエンド構成を定義する必要があります。この構成は、すべてのRESTful APIサービスのデフォルトのデータベース接続として使用されます。

  • <graphs>: サービスの起動時に要求を処理するために使用可能なグラフのリスト。このリストに定義されたグラフは、関連付けられたデータベース構成に基づいて作成されます。

デフォルトでは、rexster.xmlによって、<oracle-property-graph-backends>セクションに少なくとも1つのバックエンド構成を定義する必要があります。各バックエンドは、backend-nameおよびbackend-type (apache_hbaseまたはoracle_nosqlのいずれか)によって識別されます。追加のデータベース・パラメータはバックエンドのプロパティとして指定する必要があります。Apache HBaseの場合、これらのプロパティにZookeeper定数およびZookeeperクライアント・ポートが含まれます。Oracle NoSQL Databaseの場合、これらのデータベース・パラメータにデータベース・ホストとポートおよびKVストア名が含まれます。

構成ファイルに、同じまたは異なるバックエンド・タイプに属する複数のバックエンド構成を含めることができます。

次のスニペットは、2つのバックエンド(最初の1つはApache HBaseデータベースに対するもので、2番目はOracle NoSQL Databaseに対するもの)を持つrexster.xmlの構成を示します。

<backend>
  <backend-name>hbase_connection</backend-name>
  <backend-type>apache_hbase</backend-type>
  <default-backend>true</default-backend>
  <properties>
    <quorum>127.0.0.1</quorum>
    <clientport>2181</clientport>
  </properties>
</backend>

<backend>
  <backend-name>nosql_connection</backend-name>
  <backend-type>oracle_nosql</backend-type>
  <properties>
    <host>127.0.0.1</host>
    <port>5000</port>
    <storeName>kvstore</storeName>
  </properties>
</backend>

デフォルトのバックエンドは、rexster.xmlファイルのグラフ・セクションで前に定義されていないグラフで実行されるすべてのプロパティ・グラフRESTful操作のデフォルトのデータベース構成として使用されるため、サービス用に設定される必要があります。前の例では、hbase_connectionsという名前のバックエンドがデフォルトのバックエンドとして設定されます。

<graphs> XML要素は、ユーザーの要求に使用可能なプロパティ・グラフのリストを識別します。各グラフは、graph-name およびgraph-type (oracle.pg.hbaseまたはoracle.pg.nosql.OraclePropertyGraphConfiguration)によって識別されます。追加のデータベース・パラメータは、グラフのタイプに基づくプロパティとして指定する必要があります。hbaseグラフの場合、これらのプロパティにZookeeper定数およびZookeeperクライアント・ポートが含まれます。nosqlグラフの場合、これらのデータベース・パラメータにデータベース・ホストとポートおよびKVストア名が含まれます。

さらに、extensionsサブセクションでtp:gremlin値を指定したallowタグを使用することによってgremlin問合せを実行する機能など、グラフで実行できる拡張機能があるかどうかを指定できます。

次のスニペットは、2つのプロパティ・グラフ(Apache HBaseデータベースを使用するconnectionsグラフおよびOracle NoSQL Databaseを使用するtestグラフ)を持つrexster.xmlの構成を示します。

<graphs>
  <graph> 
    <graph-name>connections</graph-name>
    <graph-type>oracle.pg.hbase.OraclePropertyGraphConfiguration</graph-type>
    <properties> 
      <quorum>127.0.0.1</quorum>     
      <clientport>2181</clientport> 
    </properties>
    <extensions> 
      <allows> 
        <allow>tp:gremlin</allow> 
      </allows> 
    </extensions>
  </graph> 
  <graph>
    <graph-name>connections</graph-name>
    <graph-type>oracle.pg.nosql.OraclePropertyGraphConfiguration</graph-type>
    <properties> 
      <storeName>kvstore</storeName> 
      <host>127.0.0.1</host> 
      <port>5000</port> 
    </properties>
    <extensions> 
      <allows> 
        <allow>tp:gremlin</allow> 
      </allows> 
    </extensions>
  </graph>
</graphs>

HTTPリクエスト(GET、POST、PUT、DELETE)操作が特定のグラフ名に対して実行されると、サービスはrexster.xml構成ファイルに定義されたグラフ・データベース構成を参照します。グラフが構成ファイルに含まれていない場合は、「graph cannot be found」というエラー・メッセージが表示されてリクエストは失敗し、操作は完了しません。

グラフの作成サービスでHTTP POSTリクエストを実行することによって、後続のHTTPリクエストで使用されるように新しいグラフを動的にサービスに追加できます。

5.11.3 プロパティ・グラフREST API操作の情報

このトピックでは、プロパティ・グラフREST APIの操作について説明します。

5.11.3.1 GET操作(プロパティ・グラフ)

このトピックでは、プロパティ・グラフREST APIのGET操作について説明します。

注意:

プロパティ・グラフの索引の詳細は、プロパティ・グラフ・データの自動索引の使用およびプロパティ・グラフ・データの手動索引の使用の次の項目を参照してください。

/graphs/{graphname}/indices

説明: 指定されたグラフに作成されているすべての手動索引の名前およびクラスを取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。

使用上の注意

このGET操作は、OraclePropertyGraph.getIndices()メソッドの呼出しを実行します。

次のURLは、connectionsという名前のグラフのすべての手動索引を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/indices

結果は次のようになります。

    {
        results: [ 
            name: "myIdx",
            class: "vertex"
        ],
        totalSize:1,
        queryTime: 9.112078
    }

/graphs/{graphname}/indices/{indexName}?key=<key>&value=<value>

説明 特定のキー値ペアを持つ指定された索引内の要素を取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • indexName:

    索引の名前。
  • <key>:

    キー値ペアのキー。
  • <value>:

    キー値ペアの値。

使用上の注意

キー値ペアを指定していない場合、指定した手動索引に関する情報が表示されます。索引が存在しない場合、「Could not find index」というメッセージが返されます。

このGET操作は、OracleIndex.get(key,value)メソッドの呼出しを実行します。

次のURLは、キー値ペアname-Beyonceを持つmyIdx索引内のすべての頂点を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/indices/myIdx?key=name&value=Beyonce

結果は次のようになります。

{
  "results": [
    {
      "country": {
        "type": "string",
        "value": "United States"
      },
      "music genre": {
        "type": "string",
        "value": "pop soul "
      },
      "role": {
        "type": "string",
        "value": "singer actress"
      },
      "name": {
        "type": "string",
        "value": "Beyonce"
      },
      "_id": 2,
      "_type": "vertex"
    }
  ],
  "totalSize": 1,
  "queryTime": 79.910928
}

/graphs/{graphname}/indices/{indexName}/count?key=<key>&value=<value>

説明: 特定のキー値ペアを持つ指定された索引内の要素の数を取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • indexName:

    索引の名前。
  • <key>:

    キー値ペアのキー。
  • <value>:

    キー値ペアの値。

使用上の注意

このGET操作は、OracleIndex.count(key,value)メソッドの呼出しを実行します。

次のURLは、connectionsグラフのmyIdx索引内のキー値ペアname-Beyonceを持つ頂点の数を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/indices/myIdx/count?key=name&value=Beyonce

結果は次のようになります。

  {
    totalSize: 1,
    queryTime: 20.781228
  }

/graphs/{graphname}/keyindices

説明: 指定されたグラフのすべての自動テキスト索引に関する情報を取得します。現在自動索引で使用されている索引付けされたキーを提供します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。

使用上の注意

このGET操作は、VertexEdgeの両方のクラスに対するOraclePropertyGraph.getIndexedKeys(class)メソッドの呼出しを実行します。

次のURLは、connectionsグラフのすべての自動索引に関する情報を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/keyindices

結果は次のようになります。

    {
        keys:         {
            edge: [ ],
            vertex:      [
                "name"
            ]
        },
        queryTime: 28.776229
    }

/graphs/{graphname}/keyindices/{class}

説明: 特定のタイプのすべての要素に対する自動索引で現在使用されている索引付けされたキーを取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • class:

    キー索引の要素のクラス・タイプ。

使用上の注意

このGET操作は、OraclePropertyGraph.getIndexedKeys(class)メソッドの呼出しを実行します。

次のURLは、connectionsグラフのすべての自動索引を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/keyindices/vertex/

結果は次のようになります。

    {
        results:  [
            "name"
        ],
        queryTime: 28.776229
    }

/backends

説明: すべての使用可能なバックエンドおよびその構成情報を返します。

パラメータ

(なし。)

使用上の注意

(なし。)

次のURLは、すべての構成済バックエンドを取得します。

http://localhost:7001/opg_unified/dal/backends/

結果は次のようになります。

    {
        backends: [
            {
                backendName: "hbase_connection",
                isDefault: false,
                port: "2181",
                backendType: "HBaseBackendConnection",
                quorum: " localhost "
            },
            {
                host: "localhost",
                backendName: "nosql_connection",
                isDefault: true,
                store: "kvstore",
                port: "5000",
                backendType: "OracleNoSQLBackendConnection"
            }
        ],
        queryTime: 0.219886,
        upTime: "0[d]:02[h]:33[m]:40[s]"    
    }

/backends/default

説明: グラフによって使用されるデフォルトのバックエンドを取得します。

パラメータ

(なし。)

使用上の注意

(なし。)

次のURLは、デフォルトのバックエンドを取得します。

http://localhost:7001/opg_unified/dal/backends/default/

結果は次のようになります。

    {
        defaultBackend: {
            host: "localhost",
            backendName: "nosql_connection",
            isDefault: true,
            store: "kvstore",
            port: "5000",
            backendType: "OracleNoSQLBackendConnection"
        },
        queryTime: 0.219886,
        upTime: "0[d]:02[h]:33[m]:40[s]"    
    }

/backends/{backendName}

説明: 指定されたバックエンドに関するすべての構成情報を取得します。

パラメータ

  • beckendName:

    バックエンドの名前。

使用上の注意

(なし。)

次のURLは、nosql_connectionバックエンドの構成を取得します。

http://localhost:7001/opg_unified/dal/backends/nosql_connection/

結果は次のようになります。

    {
        backend: {
            host: "localhost",
            backendName: "nosql_connection",
            isDefault: true,
            store: "kvstore",
            port: "5000",
            backendType: "OracleNoSQLBackendConnection"
        },
        queryTime: 0.219886,
        upTime: "0[d]:02[h]:33[m]:40[s]"    
    }

/graphs/{graphname}

説明: 指定されたグラフのタイプおよびサポートされる機能に関する情報を取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。

使用上の注意

(なし。)

次のURLは、connectionsグラフに関する情報を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/

結果は次のようになります。

    {
        name: "connections",
        graph: "oraclepropertygraph with name connections",
        features: 
        {
            isWrapper: false,
            supportsVertexProperties: true,
            supportsMapProperty: true,
            supportsUniformListProperty: true,
            supportsIndices: true,
            ignoresSuppliedIds: false,
            supportsFloatProperty: true,
            supportsPrimitiveArrayProperty: true,
            supportsEdgeIndex: true,
            supportsKeyIndices: true,
            supportsDoubleProperty: true,
            isRDFModel: false,
            isPersistent: true,
            supportsVertexIteration: true,
            supportsEdgeProperties: true,
            supportsSelfLoops: false,
            supportsDuplicateEdges: true,
            supportsSerializableObjectProperty: true,
            supportsEdgeIteration: true,
            supportsVertexIndex: true,
            supportsIntegerProperty: true,
            supportsBooleanProperty: true,
            supportsMixedListProperty: true,
            supportsEdgeRetrieval: true,
            supportsTransactions: true,
            supportsThreadedTransactions: true,
            supportsStringProperty: true,
            supportsVertexKeyIndex: true,
            supportsEdgeKeyIndex: true,
            supportsLongProperty: true
        },
        readOnly: false,
        type: "oracle.pg.nosql.OraclePropertyGraph",
        queryTime: 1010.203456,
        upTime: "0[d]:19[h]:28[m]:37[s]"
    }

/graphs/{graphname}/edges

説明: 指定されたグラフのエッジに関する情報を取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • opg.showTypes (問合せパラメータ):

    各キー値ペアのデータ型がレスポンスに含まれる必要があるかどうかを指定するブール値。
  • opg.offset.start (問合せパラメータ):

    リクエストの処理時にスキップするエッジの数を表す整数。
  • opg.offset.limit (問合せパラメータ):

    グラフから取得するエッジの最大数。
  • opg.ids=[<id1>, <id2>, <id3>, ...] (問合せパラメータ):

    結果を選択するエッジIDのリスト。

使用上の注意

(なし。)

次のGETリクエストは、connectionsグラフのすべてのエッジに関する情報を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/edges

結果は次のようになります。

    {
        results:      [
            {
                weight: 1,
                _id: 1001,
                _type: "edge",
                _outV: 1,
                _inV: 3,
                _label: "collaborates"
            },
            {
                weight: 1,
                _id: 1002,
                _type: "edge",
                _outV: 1,
                _inV: 4,
                _label: "admires"
            },
            ���
        ],
        totalSize: 164,
        queryTime: 49.491961
    }

次のGETリクエストは、connectionsグラフ内のID値が1001および1002であるエッジのみを要求するように、前のリクエストを変更します。

http://localhost:7001/opg_unified/dal/graphs/connections/edges?opg.ids=[1001,1002]

結果は次のようになります。

    {
        results:      [
            {
                weight: 1,
                _id: 1001,
                _type: "edge",
                _outV: 1,
                _inV: 3,
                _label: "collaborates"
            },
            {
                weight: 1,
                _id: 1002,
                _type: "edge",
                _outV: 1,
                _inV: 4,
                _label: "admires"
            }
        ],
        totalSize: 2,
        queryTime: 49.491961
    }

次のGETリクエストは、connectionsグラフの最初の5つのエッジをスキップした後に1つのエッジをフェッチします。

http://localhost:7001/opg_unified/dal/graphs/connections/edges?opg.offset.start=5&opg.offset.limit=1

結果は次のようになります。

    {
        results:      [
            {
                weight: 1,
                _id: 1005,
                _type: "edge",
                _outV: 1,
                _inV: 7,
                _label: "collaborates"
            }
        ],
        totalSize: 1,
        queryTime: 49.491961
    }

/graphs/{graphname}/edges/{id}

説明: グラフの指定されたIDのエッジに関する情報を取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • id:

    読み取るエッジのエッジID。
  • opg.showTypes (問合せパラメータ):

    各キー値ペアのデータ型がレスポンスに含まれる必要があるかどうかを指定するブール値。

使用上の注意

(なし。)

次のGETリクエストは、connectionsグラフのエッジID 1001に関する情報を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/edges/1001

結果は次のようになります。

   {
      results: 
      {
        weight: 
        {
           type: "double",
           value: 1
        },
        _id: 1001,
        _type: "edge",
        _outV: 1,
        _inV: 3,
        _label: "collaborates"
      },
      queryTime: 43.720456
   }

次のGETリクエストは、connectionsグラフに存在しないエッジ1に対する失敗したリクエストの出力を表示します。

http://localhost:7001/opg_unified/dal/graphs/connections/edges/1

結果は次のようになります。

{
message: "Edge with name [1] cannot be found."
}

次のGETリクエストは、connectionsグラフの最初の5つのエッジをスキップした後に1つのエッジをフェッチします。

http://localhost:7001/opg_unified/dal/graphs/connections/edges?opg.offset.start=5&opg.offset.limit=1

結果は次のようになります。

    {
        results:      [
            {
                weight: 1,
                _id: 1005,
                _type: "edge",
                _outV: 1,
                _inV: 7,
                _label: "collaborates"
            }
        ],
        totalSize: 1,
        queryTime: 49.491961
    }

/graphs/{graphname}/vertices

説明: 指定されたグラフの頂点に関する情報を取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • opg.showTypes (問合せパラメータ):

    各キー値ペアのデータ型がレスポンスに含まれる必要があるかどうかを指定するブール値。
  • opg.offset.start (問合せパラメータ):

    リクエストの処理時にスキップする頂点の数を表す整数。
  • opg.offset.limit (問合せパラメータ):

    グラフから取得する頂点の最大数。
  • opg.ids=[<id1>, <id2>, <id3>, ...] (問合せパラメータ):

    結果を選択する頂点IDのリスト。

使用上の注意

(なし。)

次のGETリクエストは、connectionsグラフのすべての頂点に関する情報を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/vertices

結果は次のようになります。

    {
        results: [
            {
                country: "Portugal",
                occupation: "Professional footballer",
                name: "Cristiano Ronaldo",
                _id: 63,
                _type: "vertex"
            },
            {
                country: "North Korea",
                occupation: "Supreme leader of North Korea",
                role: "political authority",
                name: "Kim Jong Un",
                political party: "Workers' Party of Korea",
                religion: "atheism",
                _id: 32,
                _type: "vertex"
            },
            ���
        ],
        totalSize: 78,
        queryTime: 22.345108
    }

次のGETリクエストは、connectionsグラフ内のID値が4および63である頂点のみを要求するように、前のリクエストを変更します。

http://localhost:7001/opg_unified/dal/graphs/connections/vertices?opg.ids=[4,63] 

結果は次のようになります。

    {
        results: [
            {
                country: "United States",
                role: " american economist",
                name: "Janet Yellen",
                political party: "Democratic",
                _id: 4,
                _type: "vertex"
            },
            {
                country: "Portugal",
                occupation: "Professional footballer",
                name: "Cristiano Ronaldo",
                _id: 63,
                _type: "vertex"
            },
        ],
        totalSize: 2,
        queryTime: 22.345108
    }

次のGETリクエストは、connectionsグラフの最初の5つの頂点をスキップした後に1つの頂点をフェッチします。

http://localhost:7001/opg_unified/dal/graphs/connections/vertices?opg.offset.start=5&opg.offset.limit=1

結果は次のようになります。

    {
        results: [
            {
                country: "United States",
                occupation: "founder",
                role: "philantropist",
                name: "Tom Steyer",
                company: "Farallon Capital Management",
                political party: "Democratic",
                _id: 20,
                _type: "vertex"
            }
        ],
        totalSize: 1,
        queryTime: 65.366488
    }

/graphs/{graphname}/vertices/{id}

説明: グラフの指定されたIDの頂点に関する情報を取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • id:

    読み取る頂点の頂点ID。
  • opg.showTypes (問合せパラメータ):

    各キー値ペアのデータ型がレスポンスに含まれる必要があるかどうかを指定するブール値。

使用上の注意

(なし。)

次のGETリクエストは、connectionsグラフの頂点ID 1に関する情報を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/vertices/1

結果は次のようになります。

   {
      results: 
      {
         country: "United States",
         occupation: "44th president of United States of America",
         role: "political authority",
         name: "Barack Obama",
         political party: "Democratic",
         religion: "Christianity",
         _id: 1,
         _type: "vertex"
      },
      queryTime: 13.95932
   }

次のGETリクエストは、頂点1のすべてのプロパティのデータ型を含むように前のリクエストを変更しました。

http://localhost:7001/opg_unified/dal/graphs/connections/vertices/1?opg.showTypes=true

結果は次のようになります。

{
   results: 
   {
      country: 
      {
         type: "string",
         value: "United States"
      },
      occupation: 
      {
         type: "string",
         value: "44th president of United States of America"
      },
      role: 
      {
         type: "string",
         value: "political authority"
      },
      name: 
      {
         type: "string",
         value: "Barack Obama"
      },
      political party: 
      {
         type: "string",
         value: "Democratic"
      },
      religion: 
      {
         type: "string",
         value: "Christianity"
      },
      _id: 1,
      _type: "vertex"
   },
   queryTime: 13.147989
}

次のGETリクエストは、connectionsグラフに存在しない頂点1000に対する失敗したリクエストの出力を表示します。

http://localhost:7001/opg_unified/dal/graphs/connections/vertices/1000

結果は次のようになります。

{
message: "Vertex with name [1000] cannot be found."
}

/graphs/{graphName}/vertices/{id}/{direction}

説明: 指定されたID値を持つ頂点の{in,out,both}の隣接する頂点を取得します。

パラメータ

  • direction:

    入力頂点の場合はin、出力頂点の場合はout、入力頂点と出力頂点の場合はbothとすることができます。

使用上の注意

(なし。)

次のURLは、ID 5を持つ頂点の出力頂点を取得します。

http://localhost:7001/opg_unified/dal/graphs/connections/vertices/5/out/

結果は次のようになります。

    {
        results:      [
            {
                name: "Omar Kobine Layama",
                _id: 56,
                _type: "vertex"
            },
            {
                name: "Dieudonne Nzapalainga",
                _id: 57,
                _type: "vertex"
            },
            {
                name: "Nicolas Guerekoyame Gbangou",
                _id: 58,
                _type: "vertex"
            },
            {
                country: "Rome",
                name: "The Vatican",
                type: "state",
                religion: "Catholicism",
                _id: 59,
                _type: "vertex"
            }
        ],
        totalSize: 4,
        queryTime: 56.044806
    } 

/graphs/{graphname}/config

説明: 指定されたグラフの構成の表現(JSON形式)を取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。

使用上の注意

(なし。)

次のURLは、connectionsグラフのグラフ構成を取得します。

http://localhost:7001/opg_unified/graphs/connections/config

結果は次のようになります。

    {
        edge_props:   [
            {
                name: "weight",
                type: "string"
            }
        ],
        db_engine: "NOSQL",
        hosts:      [
            "localhost:5000"
        ],
        vertex_props:      [
            {
                name: "name",
                type: "string"
            },
            {
                name: "role",
                type: "string"
            },
            ���
            {
                name: "country",
                type: "string"
            }
        ],
        format: "pg",
        name: "connections",
        store_name: "kvstore",
        attributes: { },
        max_num_connections: 2,
        error_handling: { },
        loading:         {
            load_edge_label: true
        },
        edge_label: true
    }

/graphs/{graphname}/exportData

説明: Oracleプロパティ・グラフ・フラット・ファイル形式(.opvおよび.opeファイル)のグラフを含む.zipファイルをダウンロードします。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • dop (問合せパラメータ)

    操作の並列度。

使用上の注意

(なし。)

次のURLは、4つまでの並列実行スレッドを使用して、connectionsグラフをエクスポートします。

http://localhost:7001/opg_unified/graphs/connections/exportData?dop=4

これは、次のようなコンテンツのOPV (頂点)ファイルおよびOPE (エッジ)ファイルを含むzipファイルをダウンロードします。

OPVファイル:

1,name,1,Barack%20Obama,,
1,role,1,political%20authority,,
1,occupation,1,44th%20president%20of%20United%20States%20of%20America,,
1,country,1,United%20States,,
���

OPEファイル:

1000,1,2,collaborates,weight,3,,1.0,
1001,1,3,collaborates,weight,3,,1.0,
1002,1,4,admires,weight,3,,1.0,
1003,1,5,admires,weight,3,,1.0,
���

/edges/{graphname}/properties

説明: 指定されたグラフのエッジによって使用されるプロパティ・キーのセットを取得します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。

使用上の注意

(なし。)

次のURLは、connectionsグラフのエッジ・プロパティ・キーを取得します。

http://localhost:7001/opg_unified/edges/connections/properties

結果は次のようになります。

    {
        complete: 1,
        results:      [
            "weight"
        ],
        totalSize: 1,
        queryTime: 360.491961
    }

/vertices/{graphname}/textquery

説明 特定のキー値ペアの基準と一致するグラフの頂点を取得します。既存の索引に対して全文検索を実行します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • key (問合せパラメータ)

    一致する頂点が持つ必要があるプロパティ・キー。
  • value (問合せパラメータ)

    一致する頂点が持つ必要があるプロパティ値。
  • useWildCards (問合せパラメータ)

    完全一致検索を実行するか(false)、またはワイルドカードを使用するか(true)を指定するブール文字列。

使用上の注意

返される結果は、パラメータの値のみでなくパラメータの存在によっても異なります。

  • 問合せパラメータを指定しない場合、/graphs/{graphname}/verticesとまったく同じように動作します。key問合せパラメータのみを指定した場合、値に関係なく、そのプロパティ・キーを持つエッジのみを返します。

  • keyおよびvalue問合せパラメータを指定し、useWildCards問合せパラメータがtrueではない場合は、値にワイルドカード文字(*)が含まれていても、キー値ペアとの完全一致がある頂点のみを返します。

  • keyおよびvalue問合せパラメータを指定し、useWildCards問合せパラメータがtrueである場合は、索引を使用してテキスト検索を実行し、一致する頂点を返します。

ワイルドカード検索が要求され、要求した索引が指定したキーに存在しない場合、エラーが返されます。

次のURLは、connectionsグラフ内の、valueが文字列Poで開始するnameキーを持つ頂点を取得します。

http://localhost:7001/opg_unified/vertices/connections/textquery?key=name&value=Po*&useWildCards=true

返されるJSONは次のようになります。

    {
        results:      [
            {
                country: "Italy",
                occupation: "pope",
                role: "Catholic religion authority",
                name: "Pope Francis",
                religion: "Catholicism",
                _id: 5,
                _type: "vertex"
            },
            {
                country: "China",
                occupation: "business man",
                name: "Pony Ma",
                _id: 71,
                _type: "vertex"
            }
        ],
        totalSize: 2,      
        queryTime: 49.491961    
    }

/edges/{graphname}/textquery

説明: 特定のキー値ペアの基準と一致するグラフのエッジを取得します。既存の索引に対して全文検索を実行します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • key (問合せパラメータ)

    一致するエッジが持つ必要があるプロパティ・キー。
  • value (問合せパラメータ)

    一致するエッジが持つ必要がある値。
  • useWildCards (問合せパラメータ)

    完全一致検索を実行するか(false)、またはワイルドカードを使用するか(true)を指定するブール文字列。

使用上の注意

返される結果は、パラメータの値のみでなくパラメータの存在によっても異なります。

  • 問合せパラメータを指定しない場合、/graphs/{graphname}/edgesとまったく同じように動作します。key問合せパラメータのみを指定した場合、値に関係なく、そのプロパティ・キーを持つエッジのみを返します。

  • keyおよびvalue問合せパラメータを指定し、useWildCards問合せパラメータがtrueではない場合は、値にワイルドカード文字(*)が含まれていても、キー値ペアとの完全一致があるエッジを返します。

  • keyおよびvalue問合せパラメータを指定し、useWildCards問合せパラメータがtrueである場合は、索引を使用してテキスト検索を実行し、一致するエッジを返します。

次のURLは、connectionsグラフ内の、値が文字列frienで開始するtypeキーを持つエッジを取得します。

http://localhost:7001/opg_unified/edges/connections/textquery?key=type&value=frien*&useWildCards=true

返されるJSONは次のようになります。

    {
        results:      [
            {
                weight: 1,
                type: "friends",
                _id: 10000,
                _type: "edge",
                _outV: 1,
                _inV: 3,
                _label: "collaborates"
            }
        ],
        totalSize: 1,
        queryTime: 49.491961
    }
5.11.3.2 POST操作(プロパティ・グラフ)

このトピックでは、プロパティ・グラフREST APIのPOST操作について説明します。

注意:

プロパティ・グラフの索引の詳細は、プロパティ・グラフ・データの自動索引の使用およびプロパティ・グラフ・データの手動索引の使用の次の項目を参照してください。

/graphs/{graphname}/indices/{indexName}?class=<class>

説明: 指定されたグラフの指定された手動索引を作成します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • indexName:

    作成する手動索引の名前。
  • class:

    索引のクラス。vertexまたはedgeのいずれかにすることができます。

使用上の注意

このPOST操作は、OraclePropertyGraph.createIndex(name,class)メソッドの呼出しを実行します。

次のPOST操作は、connectionsプロパティ・グラフにクラスvertexmyIdx索引を作成します。

http:// localhost:7001/opg_unified/dal/graphs/connections/indices/myIdx?class=vertex

結果は次のようになります。

{
  "queryTime": 551.798547,
  "results": 
  {
    "name": "myIdx",
    "class": "vertex"
  }}

/graphs/{graphname}/keyindices/{class}/{keyName}

説明: 指定されたグラフに自動キー索引を作成します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • class:

    索引のクラス。vertexまたはedgeのいずれかにすることができます。
  • keyName:

    キー索引の名前。

使用上の注意

このPOST操作は、OraclePropertyGraph.createKeyIndex(key,class)メソッドの呼出しを実行します。

次のPOST操作は、connectionsプロパティ・グラフにクラスvertexmyVKeyIdx自動索引を作成します。

http:// localhost:7001/opg_unified/dal/graphs/connections/keyindices/vertex/myVKeyIdx

結果は次のようになります。

{
  "queryTime": 234.970874
}

/graphs/connections/edges

���edges?_outV=<id>&_label=value&_inV=<id> 
���edges/<edgeId>?_outV=<id>&_label=value&_inV=<id> 
���edges/<edgeId>?<key>=value 

説明: 2つの頂点の間に新しいエッジを作成します。

パラメータ

  • _outV:

    出力頂点。
  • _inV:

    入力頂点。
  • _label:

    エッジの出力ラベル。
  • edgeID:

    作成するエッジのID。
  • key:

    作成するキー値。

使用上の注意

(なし。)

次のPOST操作は、頂点29から頂点26にラベルfriendのエッジを作成します。

http://localhost:8080/graphs/connections/edges_outV=29&_label=friend&_inV=26

結果は次のようになります。

{"results": {"_id": 1810534020425227300,"_type": "edge","_outV": 29,"_inV": 26,"_label": "friend"},"queryTime": 36.635908}

/csv/edges

説明: エッジ・ファイルをCSV形式からOPE形式に変換します。

パラメータ

  • fileName:

    エッジ・ファイルの名前(CSV形式)。
  • cboxEdgeIDColName:

    エッジIDとして使用する必要があるキー。
  • cboxEdgeSVIDColName:

    開始頂点IDとして使用する必要があるキー。
  • cboxEdgeLabelColName:

    エッジ・ラベルとして使用する必要があるキー。
  • cboxEdgeDVIDColName:

    終了頂点IDとして使用する必要があるキー。

使用上の注意

ファイル形式の詳細は、Oracleフラット・ファイル形式の定義を参照してください。

POST操作の実行およびCSVファイルのOPEファイルへの変換に使用できるHTMLフォームを次に示します。

<html>
  <body>
    <h1>CSV Example - Edges</h1>
    <form id="myForm" action="http://localhost:7001/opg_unified/dal/csv/edges" 
method="POST" enctype="multipart/form-data">
       <p>Select a file for edges : <input type="file" name="fileEdge" size="45" /></p>
       <p>Edge Id : <input type="text" name="cboxEdgeIDColName" size="25" /></p>
       <p>Start vertex Id : <input type="text" name="cboxEdgeSVIDColName" size="25" /></p>
       <p>Edge Label : <input type="text" name="cboxEdgeLabelColName" size="25" /></p>
       <p>End vertex Id : <input type="text" name="cboxEdgeDVIDColName" size="25" /></p>
       <input type="button" onclick="myFunction()" value="Upload">
    </form>
    <script>
      function myFunction() {
        frm =  document.getElementById("myForm");
        frm.submit();
      }
    </script>
  </body>
</html>

このフォームはブラウザで次のように表示されます。

post_csv_edges_output.jpgの説明が続きます
図post_csv_edges_output.jpgの説明

入力エッジ・ファイル(edges.csv)の内容は次のとおりです。

EDGE_ID,START_ID:long,weight:float,END_ID:long,label:string
1,1,1.0,2,knows

出力エッジ・ファイル(vertices.ope)の内容は次のとおりです。

1,1,2,knows,weight,3,,1.0,

/csv/vertices

説明: 頂点ファイルをCSV形式からOPV形式に変換します。

パラメータ

  • fileVertex:

    頂点ファイルの名前(CSV形式)。
  • cboxVertexIDColName:

    頂点IDとして使用する必要があるキー。

使用上の注意

ファイル形式の詳細は、Oracleフラット・ファイル形式の定義を参照してください。

POST操作の実行およびCSVファイルのOPVファイルへの変換に使用できるHTMLフォームを次に示します。

<html>
  <body>
    <h1>CSV Example</h1>
    <form id="myForm" action="http://localhost:7001/opg_unified/dal/csv/vertices" 
method="POST" enctype="multipart/form-data">
       <p>Select a file for vertices : <input type="file" name="fileVertex" size="45" /></p>
       <p>Vertex Id : <input type="text" name="cboxVertexIDColName" size="25" /></p>
       <input type="button" onclick="myFunction()" value="Upload">
    </form>
    <script>
      function myFunction() {
        frm =  document.getElementById("myForm");
        frm.submit();
      }
    </script>
  </body>
</html>

このフォームはブラウザで次のように表示されます。

post_csv_vertices_output.jpgの説明が続きます
図post_csv_vertices_output.jpgの説明

入力頂点ファイル(vertices.csv)の内容は次のとおりです。

id,name,country
1,Eros%20Ramazzotti,Italy
2,Monica%20Bellucci,Italy

出力頂点ファイル(vertices.opv)の内容は次のとおりです。

1,name,1,Eros%20Ramazzotti,,
1,country,1,Italy,,
2,name,1,Monica%20Bellucci,,
2,country,1,Italy}

/graphs/{graphname}/loadData

説明: OPVおよびOPEファイルをサーバーにアップロードし、頂点およびエッジをグラフにインポートします。グラフ・メタデータを返します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • vertexFile (リクエスト・ペイロード):

    頂点(.opv)ファイル。
  • edgeFile (リクエスト・ペイロード):

    エッジ(.ope)ファイル。
  • clearRepository (リクエスト・ペイロード):

    ロード操作を開始する前にグラフを消去するかどうかを示すブール値。
  • dop (リクエスト・ペイロード):

    操作の並列度。

使用上の注意

この操作では、頂点ファイルとエッジ・ファイルの両方を同じ操作でポストできます。

次の単純なHTMLフォームを使用して、.OPVおよび.OPEファイルのペアをサーバーにアップロードできます。

http://localhost:7001/opg_unified/graphs/connections/loadData
<html>
<body>
    <h1>File Upload to OPG Unified</h1>
       <p>
        Graph name : <input type="text" name="graphTxt" id="graphTxt" size="45" />
       </p>
    <form id="myForm" action="http://localhost:7001/opg_unified/graphs/" method="POST" enctype="multipart/form-data">
       <p>
        Select a file for vertices : <input type="file" name="vertexFile" size="45" />
       </p>
       <p>
        Select a file for edges : <input type="file" name="edgeFile" size="45" />
       </p>
       <p>
        Clear graph ? : <input type="text" name="clearRepository" size="25" />
       </p>

       <input type="button" onclick="myFunction()" value="Upload">
    </form>
    <script>
      function myFunction() {
        frm =  document.getElementById("myForm");
        frm.action = frm.action + graphTxt.value + '/loadData';
        frm.submit();
      }
    </script>
</body>
</html>

表示されるフォームは次のようになります。

post_loaddata_output.jpgの説明が続きます
図post_loaddata_output.jpgの説明

OPV (頂点)ファイルの内容は次のとおりです。

1,name,1,Barack%20Obama,,
1,role,1,political%20authority,,
1,occupation,1,44th%20president%20of%20United%20States%20of%20America,,
1,country,1,United%20States,,
���

OPE (エッジ)ファイルの内容は次のとおりです。

1000,1,2,collaborates,weight,3,,1.0,
1001,1,3,collaborates,weight,3,,1.0,
1002,1,4,admires,weight,3,,1.0,
1003,1,5,admires,weight,3,,1.0,
���

返されるJSON結果は次のようになります。

    {
        name: "connections",
        graph: "oraclepropertygraph with name connections",
        features: 
        {
            isWrapper: false,
            supportsVertexProperties: true,
            supportsMapProperty: true,
            supportsUniformListProperty: true,
            supportsIndices: true,
            ignoresSuppliedIds: false,
            supportsFloatProperty: true,
            supportsPrimitiveArrayProperty: true,
            supportsEdgeIndex: true,
            supportsKeyIndices: true,
            supportsDoubleProperty: true,
            isRDFModel: false,
            isPersistent: true,
            supportsVertexIteration: true,
            supportsEdgeProperties: true,
            supportsSelfLoops: false,
            supportsDuplicateEdges: true,
            supportsSerializableObjectProperty: true,
            supportsEdgeIteration: true,
            supportsVertexIndex: true,
            supportsIntegerProperty: true,
            supportsBooleanProperty: true,
            supportsMixedListProperty: true,
            supportsEdgeRetrieval: true,
            supportsTransactions: true,
            supportsThreadedTransactions: true,
            supportsStringProperty: true,
            supportsVertexKeyIndex: true,
            supportsEdgeKeyIndex: true,
            supportsLongProperty: true
        },
        readOnly: false,
        type: "oracle.pg.nosql.OraclePropertyGraph",
        queryTime: 1010.203456,
        upTime: "0[d]:19[h]:28[m]:37[s]"
    }

/backends/{newBackendName}

説明: 指定されたプロパティで新しいバックエンド・エントリを設定します。

パラメータ

  • newBackendName:

    サポートする新しいバックエンドの名前。

使用上の注意

バックエンド名がすでに存在する場合、エラーが生成されます

isDefaultbackendTypeなど、指定されたその他のパラメータは、ペイロードの一部として渡されます。

次のPOST操作は、hbase_connection2という名前の新しいバックエンドを作成します。

http://localhost:7001/opg_unified/dal/backends/hbase_connection2

ペイロードの例:

{"isDefault": false,"port": "2181","backendType":"HBaseBackendConnection","quorum": "127.0.0.1"}

結果は次のようになります。

{"backend": {"backendName": "hbase_connection2","isDefault": false,"port": "2181","backendType": "HBaseBackendConnection","quorum": "127.0.0.1"},"queryTime": 49.904438,"upTime": "0[d]:00[h]:56[m]:14[s]"}

/edges/{graphName}/ids

説明: 一連のエッジを返します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • ids (リクエスト・ペイロード):

    要求したエッジのIDのJSON配列。

使用上の注意

このAPIは、IDキーのJSON配列および整数ID値の配列を送信します。入力idsパラメータのサイズと一致する配列を返します

エッジが見つからない場合、結果の配列内の対応する値はnullになります。

グラフにエッジが存在しない場合でも常に結果の配列を返し、その場合は、null値ばかりの配列を返しますが、404 HTTPコードは返しません。

次のコマンドは、connectionsグラフ内のIDが1001および1002 (存在する場合)のエッジを取得します。

curl -v -X POST 'http://localhost:7001/opg_unified/edges/connections/ids' -H "Content-Type: application/json" -d '{"ids":[1001,1002,1]}

返されるJSONは次のようになります。

    {
        results:      [
            {
                weight: 1,
                _id: 1001,
                _type: "edge",
                _outV: 1,
                _inV: 3,
                _label: "collaborates"
            },
            {
                weight: 1,
                _id: 1002,
                _type: "edge",
                _outV: 1,
                _inV: 4,
                _label: "admires"
            },
            null
        ],
        totalSize: 3,
        queryTime: 49.491961
    }

/edges/{graphName}/properties

説明: 指定されたエッジの指定されたプロパティを返します。

パラメータ

  • graphname:

    プロパティ・グラフの名前。
  • ids (リクエスト・ペイロード):

    エッジのIDのJSON配列。
  • propertyName (リクエスト・ペイロード):

    プロパティの名前を指定するJSON文字列。

使用上の注意

このAPIは、idsキーのJSON配列および整数ID値の配列を送信します。入力idsパラメータのサイズと一致する配列を返します

エッジが見つからない場合、結果の配列内の対応する値はnullになります。

グラフにエッジが存在しない場合でも常に結果の配列を返し、その場合は、null値ばかりの配列を返しますが、404 HTTPコードは返しません。

次のコマンドは、connectionsグラフ内のIDが1001、1002および1003 (存在する場合)のエッジのweight値を取得します。

curl -v -X POST 'http://localhost:7001/opg_unified/edges/connections/properties' -H "Content-Type: application/json" -d '{"ids":[1001,1002,1003],"propertyName":"weight"}'

返されるJSONは次のようになります。

    {
        results:      [
            {
                _id: 1001,
                weight: 1
            },
            {
                _id: 1002,
                weight: 1
            },
            {
                _id: 1003,
                weight: 1
            }
        ],
        totalSize: 3,
        queryTime: 12.491961 }
5.11.3.3 PUT操作(プロパティ・グラフ)

このトピックでは、プロパティ・グラフREST APIのPUT操作について説明します。

注意:

プロパティ・グラフの索引の詳細は、プロパティ・グラフ・データの自動索引の使用およびプロパティ・グラフ・データの手動索引の使用の次の項目を参照してください。

/backends/{backendNameNew}

説明: 指定されたプロパティで新しいバックエンド・エントリを設定します。

パラメータ

  • backendNameNew:

    サポートする新しいバックエンドの名前。
  • backendType:

    サポートする新しいバックエンドのタイプ。
  • (other):

    (その他のバックエンド固有のプロパティ。)

使用上の注意

バックエンド名がすでに存在する場合、エラーが生成されます。

isDefaultbackendTypeなど、指定されたその他のパラメータは、ペイロードの一部として渡されます。

次のPUT操作は、hbase_connection2という名前の新しいバックエンドを作成します。

http://localhost:7001/opg_unified/dal/backends/hbase_connection2

ペイロードの例:

{"isDefault": false,"port": "2182","backendType":"HBaseBackendConnection","quorum": "127.0.0.1"}

結果は次のようになります。

{"backend": {"backendName": "hbase_connection2","isDefault": false,"port": "2182","backendType": "HBaseBackendConnection","quorum": "127.0.0.1"}, "queryTime": 20.929009, "upTime": "0[d]:02[h]:22[m]:19[s]"}

/graphs/connections/edges

���edges?_outV=<id>&_label=value&_inV=<id> 
���edges/<edgeId>?_outV=<id>&_label=value&_inV=<id> 
���edges/<edgeId>?<key>=value 

説明: 2つの頂点の間に新しいエッジを作成します。

パラメータ

  • _outV:

    出力頂点。
  • _inV:

    入力頂点。
  • _label:

    エッジの出力ラベル。
  • edgeID:

    作成するエッジのID。
  • key:

    作成するキー値。

使用上の注意

(なし。)

次のPUT操作は、頂点29から頂点26にラベルfriendのエッジを作成します。

http://localhost:8080/graphs/connections/edges_outV=29&_label=friend&_inV=26

結果は次のようになります。

{"results": {"_id": 1810534020425227300,"_type": "edge","_outV": 29,"_inV": 26,"_label": "friend"},"queryTime": 36.635908}

/graphs/{graphname}/indices/{indexName}}?key=<key>&value=<value>&id=<id>

説明: 指定された頂点またはエッジを、指定された手動索引のキー値ペアに追加します。

パラメータ

  • graphName:

    プロパティ・グラフの名前。
  • indexName:

    索引の名前。
  • <key>:

    キー値ペアのキー。
  • <value>:

    キー値ペアの値。
  • <id>:

    頂点またはエッジのID値。

使用上の注意

このPUT操作は、OracleIndex.put(key,value,class)メソッドの呼出しを実行します。

次の例では、キー値ペア"name"-"Beyonce"をID 2の頂点に追加します。

http://localhost:7001/opg_unified/dal/graphs/connections/indices/myIdx?key=name&value=Beyonce&id=2

PUT操作が正常に行われた場合、次のようなレスポンスが表示されます。

{
  "queryTime": 39.265613
}
5.11.3.4 DELETE操作(プロパティ・グラフ)

このトピックでは、プロパティ・グラフREST APIのDELETE操作について説明します。

注意:

プロパティ・グラフの索引の詳細は、プロパティ・グラフ・データの自動索引の使用およびプロパティ・グラフ・データの手動索引の使用の次の項目を参照してください。

/backends/{backendName}

説明: グラフ・サーバーの使用可能なバックエンドのリストから指定されたバックエンドを削除します。削除したバックエンドの情報を返します。

パラメータ

  • backendName:

    バックエンドの名前。

使用上の注意

(なし。)

次のPUT操作

結果は次のようになります。

{"backend":{"backendName":"hbase_connection","isDefault":false,"port":"2181","backendType":"HBaseBackendConnection","quorum":"127.0.0.1"},"queryTime":0.207346,"upTime":"0[d]:00[h]:18[m]:40[s]"}

/graphs/{graphName}/edges/<id>

説明: 指定されたグラフから指定されたエッジIDを持つエッジを削除します。

パラメータ

  • id:

    削除するエッジのID。

使用上の注意

このAPIは操作にかかった時間を返します。

次の例は、ID 1010のエッジを削除します。

http://localhost:7001/opg_unified/dal/graphs/connections/edges/1010

操作が正常に行われた場合、次のようなレスポンスが表示されます。

{
  "queryTime": 10.925611
}

/graphs/{graphName}/indices/{IndexName}

説明: 指定されたグラフから指定された手動索引を削除します。

パラメータ

  • graphName:

    プロパティ・グラフの名前。
  • indexName:

    削除する手動索引の名前。

使用上の注意

このDELETE操作は、OraclePropertyGraph.dropIndex(name)メソッドの呼出しを実行します。

次の例では、手動索引myIdxconnectionsグラフから削除します。

http:// localhost:7001/opg_unified/dal/graphs/connections/indices/myIdx

/graphs/{graphName}/keyindices/{class}/{keyName}

説明: 指定されたグラフから指定された自動索引を削除します。

パラメータ

  • graphName:

    プロパティ・グラフの名前。
  • indexName:

    削除する自動索引の名前。

使用上の注意

このDELETE操作は、OraclePropertyGraph.dropKeyIndex(name,class)メソッドの呼出しを実行します。

次の例では、自動索引myVKeyIdxconnectionsグラフから削除します。

http:// localhost:7001/opg_unified/dal/graphs/connections/keyindices/vertex/myVKeyIdx

5.12 サンプル・プログラムの探索

ソフトウェア・インストールには、プロパティ・グラフの作成および操作方法を習得するために使用できる、プログラムの例のディレクトリが含まれています。

5.12.1 サンプル・プログラムについて

サンプル・プログラムは、examples/dalという名前のインストール・サブディレクトリに配布されます。例はHBaseおよびOracle NoSQL Database用にレプリケートされるため、選択したバックエンド・データベースに対応するプログラムのセットを使用できます。次の表に、プログラムの要素を示します。

表5-4 プロパティ・グラフのプログラム例(一部)

プログラム名 説明

ExampleNoSQL1

ExampleHBase1

1つの頂点からなる最小プロパティ・グラフを作成し、様々なデータ型のプロパティを頂点に設定し、保存済のグラフの記述をデータベースに問い合せます。

ExampleNoSQL2

ExampleHBase2

Example1と同じ最小プロパティ・グラフを作成してから、それを削除します。

ExampleNoSQL3

ExampleHBase3

複数の頂点およびエッジを持つグラフを作成します。いくつかの頂点およびエッジを明示的に削除し、その他は他の必須オブジェクトを削除することによって暗黙的に削除します。この例は、オブジェクトの現在のリストを表示するために、データベースを繰り返し問い合せます。

5.12.2 サンプル・プログラムのコンパイルおよび実行

Javaソース・ファイルをコンパイルおよび実行するには、次のようにします。

  1. 例のディレクトリに変更します。

    cd examples/dal
    
  2. Javaコンパイラを使用します。

    javac -classpath ../../lib/'*' filename.java
    

    例: javac -classpath ../../lib/'*' ExampleNoSQL1.java

  3. コンパイルしたコードを実行します。

    java -classpath ../../lib/'*':./ filename args
    

    引数は、グラフを格納するためにOracle NoSQL DatabaseまたはApache HBaseのいずれを使用しているかによって異なります。値はOraclePropertyGraph.getInstanceに渡されます。

Apache HBaseの引数の説明

HBaseの例を使用している場合は、次の引数を指定します。

  1. quorum: "node01.example.com, node02.example.com, node03.example.com"など、HBaseの実行ノードを識別する名前のカンマ区切りリスト。

  2. client_port: "2181"など、HBaseクライアントのポート番号。

  3. graph_name: "customer_graph"など、グラフの名前。

Oracle NoSQL Databaseの引数の説明

NoSQLの例を使用している場合は、次の引数を指定します。

  1. host_name: "cluster02:5000"など、Oracle NoSQL Database登録のクラスタ名およびポート番号。

  2. store_name: "kvstore"など、キー値ストアの名前

  3. graph_name: "customer_graph"など、グラフの名前。

5.12.3 出力の例について

プログラムの例は、System.out.println を使用して、プロパティ・グラフの記述を格納先のデータベース(Oracle NoSQL DatabaseまたはApache HBaseのいずれか)から取得します。キー名、データ型および値はコロンで区切られます。たとえば、weight:flo:30.0は、キー名がweight、データ型がfloat、値が30.0であることを示しています。

表5-5に、出力で使用されるデータ型の略称を示します。

表5-5 プロパティ・グラフのデータ型の略称

略称 データ型

bol

Boolean

dat

date

dbl

double

flo

float

int

integer

ser

serializable

str

string

5.12.4 例: プロパティ・グラフの作成

ExampleNoSQL1およびExampleHBase1は、1つの頂点からなる最小プロパティ・グラフを作成します。例5-5のコード・フラグメントは、v1という名前の頂点を作成し、様々なデータ型のプロパティを設定します。次に、保存済のグラフの記述をデータベースに問い合せます。

例5-5 プロパティ・グラフの作成

// Create a property graph instance named opg
OraclePropertyGraph opg = OraclePropertyGraph.getInstance(args);
 
// Clear all vertices and edges from opg
    opg.clearRepository();

// Create vertex v1 and assign it properties as key-value pairs
    Vertex v1 = opg.addVertex(1l);
    v1.setProperty("age",  Integer.valueOf(18));
    v1.setProperty("name", "Name");
    v1.setProperty("weight", Float.valueOf(30.0f));
    v1.setProperty("height", Double.valueOf(1.70d));
    v1.setProperty("female", Boolean.TRUE);
 
// Save the graph in the database
    opg.commit();

// Display the stored vertex description
System.out.println("Fetch 1 vertex: " + opg.getVertices().iterator().next());
 
// Close the graph instance
    opg.shutdown();

OraclePropertyGraph.getInstance引数(args)は、グラフを格納するためにOracle NoSQL DatabaseまたはApache HBaseのいずれを使用しているかによって異なります。「サンプル・プログラムのコンパイルおよび実行」を参照してください。

System.out.printlnは次の出力を表示します。

Fetch 1 vertex: Vertex ID 1 {age:int:18, name:str:Name, weight:flo:30.0, height:dbl:1.7, female:bol:true}

次については、プロパティ・グラフ・サポートのJavadoc (デフォルトでは/opt/oracle/oracle-spatial-graph/property_graph/doc/pgx)を参照してください。

OraclePropertyGraph.addVertex
OraclePropertyGraph.clearRepository
OraclePropertyGraph.getInstance
OraclePropertyGraph.getVertices
OraclePropertyGraph.shutdown
Vertex.setProperty

5.12.5 例: プロパティ・グラフの削除

ExampleNoSQL2およびExampleHBase2は、「例: プロパティ・グラフの作成」で作成したようなグラフを作成し、それをデータベースから削除します。

例5-6のコード・フラグメントは、グラフを削除します。OraclePropertyGraphUtils.dropPropertyGraph引数の説明は、「サンプル・プログラムのコンパイルおよび実行」を参照してください。

例5-6 プロパティ・グラフの削除

// Drop the property graph from the database
OraclePropertyGraphUtils.dropPropertyGraph(args);

// Display confirmation that the graph was dropped
System.out.println("Graph " + graph_name + " dropped. ");

System.out.printlnは次の出力を表示します。

Graph graph_name dropped.

OraclePropertyGraphUtils.dropPropertyGraphのJavadocを参照してください。

5.12.6 例: 頂点およびエッジの追加と削除

ExampleNoSQL3およびExampleHBase3は、頂点とエッジの両方を追加および削除します。

例5-7 頂点の作成

例5-7のコード・フラグメントは、3つの頂点を作成します。これは例5-5をシンプルにしたバリエーションです。

// Create a property graph instance named opg
OraclePropertyGraph opg = OraclePropertyGraph.getInstance(args);
 
// Clear all vertices and edges from opg
    opg.clearRepository();

// Add vertices a, b, and c
    Vertex a = opg.addVertex(1l);
    a.setProperty("name", "Alice");
    a.setProperty("age", 31);
  
    Vertex b = opg.addVertex(2l);  
    b.setProperty("name", "Bob");
    b.setProperty("age", 27);
 
    Vertex c = opg.addVertex(3l);
    c.setProperty("name", "Chris");
    c.setProperty("age", 33);

例5-8 エッジの作成

例5-8のコード・フラグメントは、頂点a、bおよびcを使用してエッジを作成します。

// Add edges e1, e2, and e3
    Edge e1 = opg.addEdge(1l, a, b, "knows");
    e1.setProperty("type", "partners");
 
    Edge e2 = opg.addEdge(2l, a, c, "knows");
    e2.setProperty("type", "friends");
 
    Edge e3 = opg.addEdge(3l, b, c, "knows");
    e3.setProperty("type", "colleagues");

例5-9 エッジおよび頂点の削除

例5-9のコード・フラグメントは、エッジe3と頂点bを明示的に削除します。これにより、頂点bに接続していたエッジe1が暗黙的に削除されます。

 // Remove edge e3
    opg.removeEdge(e3);

// Remove vertex b and all related edges
    opg.removeVertex(b);

例5-10 頂点およびエッジの問合せ

この例は、データベースに問い合せて、オブジェクトがいつ追加および削除されるかを表示します。例5-10のコード・フラグメントは、使用されるメソッドを表示します。

// Print all vertices
    vertices = opg.getVertices().iterator();
    System.out.println("----- Vertices ----");
    vCount = 0;
    while (vertices.hasNext()) {
      System.out.println(vertices.next());
      vCount++;
    }
    System.out.println("Vertices found: " + vCount);
 
    // Print all edges
    edges = opg.getEdges().iterator();
    System.out.println("----- Edges ----");
    eCount = 0;
    while (edges.hasNext()) {
      System.out.println(edges.next());
      eCount++;
    }
    System.out.println("Edges found: " + eCount);

このトピックの例では、次のような出力が生成されます。

----- Vertices ----
Vertex ID 3 {name:str:Chris, age:int:33}
Vertex ID 1 {name:str:Alice, age:int:31}
Vertex ID 2 {name:str:Bob, age:int:27}
Vertices found: 3
----- Edges ----
Edge ID 2 from Vertex ID 1 {name:str:Alice, age:int:31} =[knows]=> Vertex ID 3 {name:str:Chris, age:int:33} edgeKV[{type:str:friends}]
Edge ID 3 from Vertex ID 2 {name:str:Bob, age:int:27} =[knows]=> Vertex ID 3 {name:str:Chris, age:int:33} edgeKV[{type:str:colleagues}]
Edge ID 1 from Vertex ID 1 {name:str:Alice, age:int:31} =[knows]=> Vertex ID 2 {name:str:Bob, age:int:27} edgeKV[{type:str:partners}]
Edges found: 3
 Remove edge Edge ID 3 from Vertex ID 2 {name:str:Bob, age:int:27} =[knows]=> Vertex ID 3 {name:str:Chris, age:int:33} edgeKV[{type:str:colleagues}]
----- Vertices ----
Vertex ID 1 {name:str:Alice, age:int:31}
Vertex ID 2 {name:str:Bob, age:int:27}
Vertex ID 3 {name:str:Chris, age:int:33}
Vertices found: 3
----- Edges ----
Edge ID 2 from Vertex ID 1 {name:str:Alice, age:int:31} =[knows]=> Vertex ID 3 {name:str:Chris, age:int:33} edgeKV[{type:str:friends}]
Edge ID 1 from Vertex ID 1 {name:str:Alice, age:int:31} =[knows]=> Vertex ID 2 {name:str:Bob, age:int:27} edgeKV[{type:str:partners}]
Edges found: 2
Remove vertex Vertex ID 2 {name:str:Bob, age:int:27}
----- Vertices ----
Vertex ID 1 {name:str:Alice, age:int:31}
Vertex ID 3 {name:str:Chris, age:int:33}
Vertices found: 2
----- Edges ----
Edge ID 2 from Vertex ID 1 {name:str:Alice, age:int:31} =[knows]=> Vertex ID 3 {name:str:Chris, age:int:33} edgeKV[{type:str:friends}]
Edges found: 1

5.13 Oracleフラット・ファイル形式の定義

プロパティ・グラフは、頂点用の記述ファイルとエッジ用の記述ファイルの2つのフラット・ファイルに定義できます。

5.13.1 プロパティ・グラフ記述ファイルについて

ファイルのペアにより、プロパティ・グラフが記述されます。

  • 頂点ファイル: プロパティ・グラフの頂点を記述します。このファイルには、.opvというファイル名拡張子が付きます。

  • エッジ・ファイル: プロパティ・グラフのエッジを記述します。このファイルには、.opeというファイル名拡張子が付きます。

これら2つのファイルは同じベース名を共有することをお薦めします。たとえば、simple.opvおよびsimple.opeによってプロパティ・グラフを定義します。

5.13.2 頂点ファイル

頂点ファイルの各行は、プロパティ・グラフの1つの頂点を記述する1つのレコードです。1つのレコードは1つの頂点の1つのキー値プロパティを記述できるため、複数のプロパティを持つ頂点を記述する場合は複数のレコード/行が使用されます。

レコードには、カンマで区切られた6つのフィールドが含まれています。各レコードには、値があるかどうかに関係なく、すべてのフィールドを区切るために5つのカンマが含まれている必要があります。

vertex_ID, key_name, value_type, value, value, value

表5-6に、頂点ファイルのレコードを構成するフィールドを示します。

表5-6 頂点ファイルのレコードの形式

フィールド番号 名前 説明

1

vertex_ID

頂点を一意に識別する整数

2

key_name

キー値ペアのキーの名前

頂点にプロパティが指定されていない場合は、空白(%20)を入力します。この例は、プロパティが指定されていない頂点1を示しています。

1,%20,,,,

3

value_type

キー値ペアの値のデータ型を表す整数。

  • 1 String
  • 2 整数
  • 3 浮動小数
  • 4 倍精度
  • 5 タイムスタンプ(日付)
  • 6 ブール
  • 7 長整数
  • 8 短整数
  • 9 バイト
  • 10 文字
  • 20 空間データ(地理空間座標、線、ポリゴンまたはWell-Known Text (WKT)リテラルなどがあります)
  • 101 シリアライズ可能Javaオブジェクト

4

value

数値でもタイムスタンプ(日付)でもない場合のkey_nameのエンコードされたnullでない値

5

value

数値である場合のkey_nameのエンコードされたnullでない値

6

value

タイムスタンプ(日付)である場合のkey_nameのエンコードされたnullでない値

日付の形式を識別するには、Java SimpleDateFormatクラスを使用します。この例は、2015-03-26T00:00:00.000-05:00という日付形式を示しています。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); encode(sdf.format((java.util.Date) value));

頂点の必須グループ化: 1つの頂点には複数のプロパティを指定でき、頂点ファイルには、頂点IDとその頂点の1つのプロパティの組合せごとに1つのレコード(フラット・ファイル内の単一テキスト行によって表される)が含まれます。頂点ファイルでは、各頂点のすべてのレコードがまとめてグループ化されている(つまり、他の頂点のレコードが間に入っていない)必要があります。これは任意の方法で行えますが、便利な方法は、頂点ファイルのレコードを頂点ID別に昇順(または降順)にソートすることです。(ただし、頂点ファイルのすべてのレコードを頂点ID別にソートする必要があるわけではありません。これはグループ化要件を満たすための単なる1つの方法です。)

Oracleフラット・ファイル形式で頂点ファイルを構築する場合、頂点プロパティ名および値フィールドが正しくエンコードされていることを確認することが重要です(特に「特殊文字のエンコーディング」を参照してください)。エンコードを簡略化するには、OraclePropertyGraphUtils.escape Java APIを使用できます。

OraclePropertyGraphUtils.outputVertexRecord(os, vid, key, value)ユーティリティ・メソッドを使用して、Oracleフラット・ファイル形式で頂点レコードを直接シリアル化できます。このメソッドを使用すると、特殊文字のエンコーディングについて心配する必要がなくなります。このメソッドは、vidによって識別される特定の頂点のkey/valueプロパティを表す特定の出力ストリーム内のテキストの新しい行を作成します。

例5-11 OraclePropertyGraphUtils.outputVertexRecordの使用

この例では、OraclePropertyGraphUtils.outputVertexRecordを使用して頂点1の2つの新しい行を作成します。

String opv = "./example.opv"; 
OutputStream os = new FileOutputStream(opv);
int birthYear = 1961;
long vid = 1;
OraclePropertyGraphUtils.outputVertexRecord(os, vid, "name", "Barack Obama");
OraclePropertyGraphUtils.outputVertexRecord(os, vid, "birth year", birthYear);
os.flush();
os.close();

生成された出力ファイルの最初の行は、値"Barack Obama"を持つプロパティ名を示し、2番目の行は、その誕生日である1961を示します。

% cat example.opv
1,name,Barack%20Obama,,
1,birth%20year,2,,1961,

5.13.3 エッジ・ファイル

エッジ・ファイルの各行は、プロパティ・グラフの1つのエッジを記述する1つのレコードです。1つのレコードは1つのエッジの1つのキー値プロパティを記述できるため、複数のプロパティを持つエッジを記述する場合は複数のレコードが使用されます。

レコードには、カンマで区切られた9つのフィールドが含まれています。各レコードには、値があるかどうかに関係なく、すべてのフィールドを区切るために8つのカンマが含まれている必要があります。

edge_ID, source_vertex_ID, destination_vertex_ID, edge_label, key_name, value_type, value, value, value

表5-7に、エッジ・ファイルのレコードを構成するフィールドを示します。

表5-7 エッジ・ファイルのレコードの形式

フィールド番号 名前 説明

1

edge_ID

エッジを一意に識別する整数

2

source_vertex_ID

エッジの出力始点のvertex_ID

3

destination_vertex_ID

エッジの入力終点のvertex_ID

4

edge_label

2つの頂点間の関係を記述する、エッジのエンコードされたラベル

5

key_name

キー値ペアのキーのエンコードされた名前

エッジにプロパティが指定されていない場合は、空白(%20)を入力します。この例は、プロパティが指定されていないエッジ100を示しています。

100,1,2,likes,%20,,,,

6

value_type

キー値ペアの値のデータ型を表す整数。

  • 1 String
  • 2 整数
  • 3 浮動小数
  • 4 倍精度
  • 5タイムスタンプ(日付)
  • 6 ブール
  • 7 長整数
  • 8 短整数
  • 9 バイト
  • 10 文字
  • 101 シリアライズ可能Javaオブジェクト

7

value

数値でもタイムスタンプ(日付)でもない場合のkey_nameのエンコードされたnullでない値

8

value

数値である場合のkey_nameのエンコードされたnullでない値

9

value

タイムスタンプ(日付)である場合のkey_nameのエンコードされたnullでない値

日付の形式を識別するには、Java SimpleDateFormatクラスを使用します。この例は、2015-03-26Th00:00:00.000-05:00という日付形式を示しています。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'Th'HH:mm:ss.SSSXXX"); encode(sdf.format((java.util.Date) value));

エッジの必須グループ化: 1つのエッジには複数のプロパティを指定でき、エッジ・ファイルには、エッジIDとそのエッジの1つのプロパティの組合せごとに1つのレコード(フラット・ファイル内の単一テキスト行によって表される)が含まれます。エッジ・ファイルでは、各エッジのすべてのレコードがまとめてグループ化されている(つまり、他のエッジのレコードが間に入っていない)必要があります。これは任意の方法で行えますが、便利な方法は、エッジ・ファイルのレコードをエッジID別に昇順(または降順)にソートすることです。(ただし、エッジ・ファイルのすべてのレコードをエッジID別にソートする必要があるわけではありません。これはグループ化要件を満たすための単なる1つの方法です。)

Oracleフラット・ファイル形式でエッジ・ファイルを構築する場合、エッジ・プロパティ名および値フィールドが正しくエンコードされていることを確認することが重要です(特に「特殊文字のエンコーディング」を参照してください)。エンコードを簡略化するには、OraclePropertyGraphUtils.escape Java APIを使用できます。

OraclePropertyGraphUtils.outputEdgeRecord(os, eid, svid, dvid, label, key, value)ユーティリティ・メソッドを使用して、Oracleフラット・ファイル形式でエッジ・レコードを直接シリアル化できます。このメソッドを使用すると、特殊文字のエンコーディングについて心配する必要がなくなります。このメソッドは、eidによって識別される特定のエッジのkey/valueプロパティを表す特定の出力ストリーム内のテキストの新しい行を作成します。

例5-12 OraclePropertyGraphUtils.outputEdgeRecordの使用

この例では、OraclePropertyGraphUtils.outputEdgeRecordを使用して、頂点1と頂点2の間のエッジ100の2つの新しい行をラベルfriendOfを使用して作成します。

String ope = "./example.ope"; 
OutputStream os = new FileOutputStream(ope);
int sinceYear = 2009;
long eid = 100;
long svid = 1;
long dvid = 2;
OraclePropertyGraphUtils.outputEdgeRecord(os, eid, svid, dvid, "friendOf", "since (year)", sinceYear);
OraclePropertyGraphUtils.outputEdgeRecord(os, eid, svid, dvid, "friendOf", "weight", 1);
os.flush();
os.close();

生成された出力ファイルの最初の行はプロパティ“since (year)"を値2009で表し、2番目の行と次の行はエッジの重みを1に設定しています

% cat example.ope
100,1,2,friendOf,since%20(year),2,,2009,
100,1,2,friendOf,weight,2,,1,

5.13.4 特殊文字のエンコーディング

頂点およびエッジ・ファイルのエンコーディングはUTF-8です。表5-8に、頂点またはエッジ・プロパティ(キー値ペア)またはエッジ・ラベルに表示されるときに文字列としてエンコードされる必要のある特殊文字をリストします。その他すべての文字は、エンコーディングは必要ありません。

表5-8 Oracleフラット・ファイル形式での特殊文字コード

特殊文字 文字列のエンコーディング 説明

%

%25

パーセント

\t

%09

タブ

%20

スペース

\n

%0A

改行

\r

%0D

リターン

,

%2C

カンマ

5.13.5 Oracleフラット・ファイル形式でのプロパティ・グラフの例

Oracleフラット・ファイル形式でのプロパティ・グラフの例を次に示します。この例では、2つの頂点(JohnおよびMary)と、JohnがMaryの友人であることを示す単一のエッジがあります。

%cat simple.opv
1,age,2,,10,
1,name,1,John,,
2,name,1,Mary,,
2,hobby,1,soccer,,
 
%cat simple.ope
100,1,2,friendOf,%20,,,,

5.13.6 Oracle Database表のOracle定義のプロパティ・グラフ・フラット・ファイルへの変換

グラフの頂点およびエッジを表すOracle Database表をOracle定義のフラット・ファイル形式(.opvおよび.opeファイル拡張子)に変換できます。

グラフ・データがOracle Database表に格納されている場合、Java APIメソッドを使用してこのデータをフラット・ファイルに変換し、後で表をプロパティ・グラフとしてOracle Databaseにロードできます。これにより、既存のOracle Database表からフラット・ファイルを生成するために他の手動アプローチを使用する必要がなくなります。

グラフの頂点が格納された表から.opvファイルへの変換

(グラフの頂点として表すことができる)エンティティが含まれるOracle Database表を.opv形式のプロパティ・グラフ・フラット・ファイルに変換できます。

たとえば、EmployeeTab (empID integer not null, hasName varchar(255), hasAge integer, hasSalary number)というリレーショナル表を想定します

この表に次のデータがあるとします。

101, Jean, 20, 120.0
102, Mary, 21, 50.0
103, Jack, 22, 110.0
������

各従業員をグラフ内の頂点として捉えることができます。頂点IDは、employeeID、またはハッシュなどのヒューリスティックを使用して生成されたIDの値である場合があります。列hasName、hasAgeおよびhasSalaryは属性として捉えることができます。

JavaメソッドOraclePropertyGraphUtils.convertRDBMSTable2OPVおよびそのJavadoc情報は、次のとおりです。

/**
* conn: is an connect instance to the Oracle relational database
* rdbmsTableName: name of the RDBMS table to be converted
* vidColName is the name of an column in RDBMS table to be treated as vertex ID
* lVIDOffset is the offset will be applied to the vertex ID
* ctams defines how to map columns in the RDBMS table to the attributes
* dop degree of parallelism
* dcl an instance of DataConverterListener to report the progress and control the behavior when errors happen 
*/
OraclePropertyGraphUtils.convertRDBMSTable2OPV(
       Connection conn, 
       String rdbmsTableName, 
       String vidColName, 
       long lVIDOffset, 
       ColumnToAttrMapping[] ctams, 
       int dop, 
       OutputStream opvOS, 
       DataConverterListener dcl);

次のコード・スニペットは、この表をOracle定義の頂点ファイル(.opv)に変換します。

// location of the output file
String opv = "./EmployeeTab.opv"; 
OutputStream opvOS = new FileOutputStream(opv);
// an array of ColumnToAttrMapping objects; each object defines how to map a column in the RDBMS table to an attribute of the vertex in an Oracle Property Graph.
ColumnToAttrMapping[] ctams = new ColumnToAttrMapping[3];
// map column "hasName" to attribute "name" of type String
ctams[0] = ColumnToAttrMapping.getInstance("hasName", "name", String.class);
// map column "hasAge" to attribute "age" of type Integer
ctams[1] = ColumnToAttrMapping.getInstance("hasAge", "age", Integer.class);
// map column "hasSalary" to attribute "salary" of type Double
ctams[2] = ColumnToAttrMapping.getInstance("hasSalary", "salary",Double.class);
// convert RDBMS table "EmployeeTab" into opv file "./EmployeeTab.opv", column "empID" is the vertex ID column, offset 1000l will be applied to vertex ID, use ctams to map RDBMS columns to attributes, set DOP to 8
OraclePropertyGraphUtils.convertRDBMSTable2OPV(conn, "EmployeeTab", "empID", 1000l, ctams, 8, opvOS, (DataConverterListener) null);

注意:

オフセット値1000l内の最後の文字データ小文字"l"は、その前にある値が長整数であることを示します。

変換結果は次のとおりです。

1101,name,1,Jean,,
1101,age,2,,20,
1101,salary,4,,120.0,
1102,name,1,Mary,,
1102,age,2,,21,
1102,salary,4,,50.0,
1103,name,1,Jack,,
1103,age,2,,22,
1103,salary,4,,110.0,

この場合、表EmployeeTab内の各行は、3つの属性を持つ1つの頂点に変換されます。たとえば、データ"101, Jean, 20, 120.0"は、属性name/"Jean"、age/20、salary/120.0を持つID 1101の頂点に変換されます。オフセット1000lが適用されるため、元のempID 101と頂点ID 1101の間にはオフセットがあります。オフセットは、グラフ要素のID値の競合を回避する上で役に立ちます。

グラフのエッジが格納された表から.opeファイルへの変換

(グラフのエッジとして表すことができる)エンティティ関係が含まれるOracle Database表を.ope形式のプロパティ・グラフ・フラット・ファイルに変換できます。

たとえば、EmpRelationTab (relationID integer not null, source integer not null, destination integer not null, relationType varchar(255), startDate date)というリレーショナル表があると想定します

この表に次のデータがあるとします。

90001, 101, 102, manage, 10-May-2015
90002, 101, 103, manage, 11-Jan-2015
90003, 102, 103, colleague, 11-Jan-2015
������

各リレーション(行)は、グラフ内のエッジとして捉えることができます。特に、エッジIDは、relationID、またはハッシュなどのヒューリスティックを使用して生成されたIDと同じである場合があります。列relationTypeはエッジ・ラベルを定義するために使用でき、列startDateはエッジ属性として扱うことができます。

JavaメソッドOraclePropertyGraphUtils.convertRDBMSTable2OPEおよびそのJavadoc情報は、次のとおりです。

/**
* conn: is an connect instance to the Oracle relational database
* rdbmsTableName: name of the RDBMS table to be converted
* eidColName is the name of an column in RDBMS table to be treated as edge ID
* lEIDOffset is the offset will be applied to the edge ID
* svidColName is the name of an column in RDBMS table to be treated as source vertex ID of the edge
* dvidColName is the name of an column in RDBMS table to be treated as destination vertex ID of the edge
* lVIDOffset is the offset will be applied to the vertex ID
* bHasEdgeLabelCol a Boolean flag represents if the given RDBMS table has a column for edge labels; if true, use value of column elColName as the edge label; otherwise, use the constant string elColName as the edge label
* elColName is the name of an column in RDBMS table to be treated as edge labels
* ctams defines how to map columns in the RDBMS table to the attributes
* dop degree of parallelism
* dcl an instance of DataConverterListener to report the progress and control the behavior when errors happen 
*/
OraclePropertyGraphUtils.convertRDBMSTable2OPE(
        Connection conn, 
        String rdbmsTableName, 
        String eidColName, 
        long lEIDOffset, 
        String svidColName, 
        String dvidColName, 
        long lVIDOffset, 
        boolean bHasEdgeLabelCol, 
        String elColName, 
        ColumnToAttrMapping[] ctams, 
        int dop, 
        OutputStream opeOS, 
        DataConverterListener dcl);

次のコード・スニペットは、この表をOracle定義のエッジ・ファイル(.ope)に変換します。

// location of the output file
String ope = "./EmpRelationTab.ope"; 
OutputStream opeOS = new FileOutputStream(ope);
// an array of ColumnToAttrMapping objects; each object defines how to map a column in the RDBMS table to an attribute of the edge in an Oracle Property Graph.
ColumnToAttrMapping[] ctams = new ColumnToAttrMapping[1];
// map column "startDate" to attribute "since" of type Date
ctams[0] = ColumnToAttrMapping.getInstance(���startDate", ���since",Date.class);
// convert RDBMS table ���EmpRelationTab" into ope file ���./EmpRelationTab.opv", column ���relationID" is the edge ID column, offset 10000l will be applied to edge ID, the source and destination vertices of the edge are defined by columns ���source" and ���destination", offset 1000l will be applied to vertex ID, the RDBMS table has an column ���relationType" to be treated as edge labels, use ctams to map RDBMS columns to edge attributes, set DOP to 8
OraclePropertyGraphUtils.convertRDBMSTable2OPE(conn, ���EmpRelationTab", ���relationID", 10000l, ���source", ���destination", 1000l, true, ���relationType", ctams, 8, opeOS, (DataConverterListener) null);

注意:

オフセット値10000l内の最後の文字データ小文字"l"は、その前にある値が長整数であることを示します。

変換結果は次のとおりです。

100001,1101,1102,manage,since,5,,,2015-05-10T00:00:00.000-07:00
100002,1101,1103,manage,since,5,,,2015-01-11T00:00:00.000-07:00
100003,1102,1103,colleague,since,5,,,2015-01-11T00:00:00.000-07:00

この場合、表EmpRelationTab内の各行は、属性sinceを持つ個別エッジに変換されます。たとえば、データ“90001, 101, 102, manage, 10-May-2015"を持つ行は、頂点1101と頂点1102をリンクするID 100001を持つエッジに変換されます。このエッジは、属性since/“2015-05-10T00:00:00.000-07:00"を持ちます。オフセット10000lが適用されるため、元のrelationID “90001"とエッジID “100001"の間にはオフセットがあります。同様に、オフセット1000lがソース頂点IDおよび宛先頂点IDに適用されます。

5.13.7 頂点およびエッジのCSVファイルのOracle定義のプロパティ・グラフ・フラット・ファイルへの変換

一部のアプリケーションでは、CSV (カンマ区切りの値)形式を使用してグラフの頂点およびエッジをエンコードします。この形式では、CSVファイルの各レコードが、単一の頂点またはエッジおよびそのプロパティを表します。グラフの頂点を表すCSVファイルをOracle定義のフラット・ファイル形式定義(頂点を表す.opv、エッジを表す.ope)に変換できます。

変換するCSVファイルには、列が表す属性の列名および型を指定するヘッダー行が含まれる場合があります。ヘッダーに属性名のみが含まれる場合、コンバータでは、値のデータ型が文字列であると見なされます。

CSVをOPVまたはOPEに変換するJava APIは、InputStreamを受け取り、ここから頂点またはエッジを(CSVから)読み込み、これらを.opvまたは.ope形式でOutputStreamに書き込みます。コンバータのAPIを使用して変換プロセスをカスタマイズすることもできます。

次のサブトピックでは、頂点およびエッジの変換の手順を示します。最初の2つの手順は非常に似ていますが、頂点およびエッジに固有の差異があります。

5.13.7.1 頂点: CSVファイルのOracle定義のフラット・ファイル形式(.opv)への変換

CSVファイルにヘッダーが含まれない場合、CSVファイルに表示される順序と同じ順序ですべての属性名(値のデータ型にマップされたもの)が表されたColumnToAttrMapping配列を指定する必要があります。また、頂点のIDなどの特別な列などを含む、CSVファイル内の列全体をこの配列内に記述する必要があります。同じCSVファイルの最初の行内の列にヘッダーを指定するには、このパラメータをnullに設定する必要があります。

頂点を表すCSVファイルを変換するには、convertCSV2OPV APIの1つを使用できます。これらのAPIのうち最も単純なものには、次が必要です。

  • CSVファイルから頂点を読み取るInputStream

  • 頂点IDを表す列の名前(この列はCSVファイル内に表示される必要があります)

  • VIDに追加する整数のオフセット(オフセットはグラフ要素のID値の競合を回避する上で役に立ちます)

  • ColumnToAttrMapping配列(ファイル内にヘッダーが指定されている場合、nullである必要があります)

  • 並列度(DOP)

  • 変換前のオフセット(スキップする頂点レコードの数)を表す整数

  • 頂点フラット・ファイル(.opv)の書込み先のOutputStream

  • 変換の進捗状況を追跡し、エラーが発生したときに何をすべきか決定するために使用できるオプションのDataConverterListener

追加パラメータを使用して、CSVファイルの異なる形式を指定できます。

  • レコード内のトークンを区切るために使用されるデリミタ文字。デフォルトはカンマ文字',’です。

  • 文字列値に特殊文字(カンマなど)が含めることができるように文字列値に引用符を付けるために使用する引用符。文字列自体の値に引用符を使用する場合、引用符を複製するか引用符の前にバックスラッシュ文字'\'を配置してエスケープする必要があります。例をいくつか示します。

    • "画面に、""Hello, world""と表示され…"

    • "しかし、ベーダーは、\"いや、私がお前の父親だ\"と答えた。"

  • 日付値を解析するために使用する日付形式。CSV変換の場合、このパラメータはnullにすることができますが、CSVに特定の日付形式が使用されている場合は指定することをお薦めします。特定の日付形式を指定すると、日付値を解析しようとするときにこの形式が最初のオプションとして使用されるため、パフォーマンスが向上します。日付形式の例をいくつか示します。

    • "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"

    • "MM/dd/yyyy HH:mm:ss"

    • "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'"

    • "dddd, dd MMMM yyyy hh:mm:ss"

    • "yyyy-MM-dd"

    • "MM/dd/yyyy"

  • CSVファイルに文字列値とともに改行文字が含まれるかどうかを示すフラグ。このパラメータがtrueに設定されている場合、改行または引用符が値として含まれるファイル内のすべての文字列に引用符を付ける必要があります。

    • "ドンキホーテの1行目は、""名前は思い出せないが、ラ・マンチャのある村に、""です。"

次のコード・フラグメントは、ColumnToAttrMapping配列を作成し、APIを使用してCSVファイルを.opvファイルに変換する方法を示します。

    String inputCSV             = "/path/mygraph-vertices.csv";
    String outputOPV            = "/path/mygraph.opv"; 
    ColumnToAttrMapping[] ctams = new ColumnToAttrMapping[4];
    ctams[0]                    = ColumnToAttrMapping.getInstance("VID",   Long.class);
    ctams[1]                    = ColumnToAttrMapping.getInstance("name",  String.class);
    ctams[2]                    = ColumnToAttrMapping.getInstance("score", Double.class);
    ctams[3]                    = ColumnToAttrMapping.getInstance("age",   Integer.class);
    String vidColumn            = "VID";

    isCSV = new FileInputStream(inputCSV);
    osOPV = new FileOutputStream(new File(outputOPV));
      
    // Convert Vertices
    OraclePropertyGraphUtilsBase.convertCSV2OPV(isCSV, vidColumn, 0, ctams, 1, 0, osOPV, null);
    isOPV.close();
    osOPV.close();

この例では、変換対象のCSVファイルには、ヘッダーを含めず、4つの列(頂点ID、名前、スコアおよび年齢)を含める必要があります。CVSの例を次に示します。

1,John,4.2,30
2,Mary,4.3,32
3,"Skywalker, Anakin",5.0,46
4,"Darth Vader",5.0,46
5,"Skywalker, Luke",5.0,53

生成される.opvファイルは、次のとおりです。

1,name,1,John,,
1,score,4,,4.2,
1,age,2,,30,
2,name,1,Mary,,
2,score,4,,4.3,
2,age,2,,32,
3,name,1,Skywalker%2C%20Anakin,,
3,score,4,,5.0,
3,age,2,,46,
4,name,1,Darth%20Vader,,
4,score,4,,5.0,
4,age,2,,46,
5,name,1,Skywalker%2C%20Luke,,
5,score,4,,5.0,
5,age,2,,53,

頂点データが含まれるCSVファイルを変換するもう1つの方法は、次の入力引数の1つとしてCSV2OPVConfigオブジェクトを使用するconvertCSV2OPV APIを使用する方法です。

  • CSVファイルから頂点を読み取るInputStream

  • 構成を指定するCSV2OPVConfigオブジェクト

  • 頂点フラット・ファイル(.opv)の書込み先のOutputStream

CSV2OPVConfigクラスには、目的のチューニングに応じて設定できる各種メンバーがあります。これは、各種構成パラメータをすべて使用してconvertCSV2OPV APIを呼び出すことと等価です。

次のコード・フラグメントは、CSV2OPVConfigオブジェクトを作成し、APIを使用してCSVファイルを.opvファイルに変換する方法を示します。

    String inputCSV             = "/path/mygraph-vertices.csv";
    String outputOPV            = "/path/mygraph.opv"; 

    ColumnToAttrMapping[] ctams = new ColumnToAttrMapping[4];
    ctams[0]                    = ColumnToAttrMapping.getInstance("VID",   Long.class);
    ctams[1]                    = ColumnToAttrMapping.getInstance("name",  String.class);
    ctams[2]                    = ColumnToAttrMapping.getInstance("score", Double.class);
    ctams[3]                    = ColumnToAttrMapping.getInstance("age",   Integer.class);

    InputStream isCSV = new FileInputStream(inputCSV);
    OutputStream osOPV = new FileOutputStream(new File(outputOPV));
    CSV2OPVConfig config = (CSV2OPVConfig) new CSV2OPVConfig()
    .setVidColumnName("VID")
    .setCtams(ctams)
    .setAllowExtraFields(false)
    .setDelimiterChar(',')
    .setQuotationChar('"');
    
    // Convert vertices
    OraclePropertyGraphCSVConverter.convertCSV2OPV(isCSV, config, osOPV);
    isCSV.close();
    osOPV.close();

CSV2OPVConfigColumnToAttrMapping配列が含まれる場合、ColumnToAttrMapping配列にマッピングがすでに定義されているため、入力CSVにはヘッダーを含めないようにする必要があります。また、setAllowExtraFieldsフラグがCSV2OPVConfig内でfalseに設定されているため、CSVファイル内の列の数がColumnToAttrMapping配列の長さと一致する必要があります(この例では、1つは頂点ID用、2番目は名前用、3番目はスコア用、4番目は年齢用です)。CSVの例を次に示します。

1,John,4.2,30
2,Mary,4.3,32
3,"Skywalker, Anakin",5.0,46
4,"Darth Vader",5.0,46
5,"Skywalker, Luke",5.0,53

生成される.opvファイルは、次のとおりです。

1,name,1,John,,
1,score,4,,4.2,
1,age,2,,30,
2,name,1,Mary,,
2,score,4,,4.3,
2,age,2,,32,
3,name,1,Skywalker%2C%20Anakin,,
3,score,4,,5.0,
3,age,2,,46,
4,name,1,Darth%20Vader,,
4,score,4,,5.0,
4,age,2,,46,
5,name,1,Skywalker%2C%20Luke,,
5,score,4,,5.0,
5,age,2,,53,
5.13.7.2 エッジ: CSVファイルのOracle定義のフラット・ファイル形式(.ope)への変換

CSVファイルにヘッダーが含まれない場合、CSVファイルに表示される順序と同じ順序ですべての属性名(値のデータ型にマップされたもの)が表されたColumnToAttrMapping配列を指定する必要があります。また、CSVファイルの列全体を配列内に記述する必要があり、これには、エッジのID (適用される場合)、および必須のSTART_ID、END_IDおよびTYPEなどが含まれます。同じCSVファイルの最初の行内の列にヘッダーを指定するには、このパラメータをnullに設定する必要があります。

頂点を表すCSVファイルを変換するには、convertCSV2OPE APIの1つを使用できます。これらのAPIのうち最も単純なものには、次が必要です。

  • CSVファイルから頂点を読み取るInputStream

  • エッジIDを表す列の名前(これは、存在しない場合、CSVファイル内でオプションです。その場合、行番号がIDとして使用されます)

  • EIDに追加する整数のオフセット(オフセットはグラフ要素のID値の競合を回避する上で役に立ちます)

  • ソース頂点IDを表す列の名前(この列はCSVファイル内に表示される必要があります)

  • 宛先頂点IDを表す列の名前(この列はCSVファイル内に表示される必要があります)

  • VIDへのオフセット(lOffsetVID)。このオフセットは、元のSVIDおよびDVID値の上に追加されます。(このAPIのバリエーションには、2つの引数(lOffsetSVIDおよびlOffsetDVID)が使用されます。1つはSVIDのオフセット用、もう1つはDVIDのオフセット用です。)

  • エッジ・ラベル列がCSVファイル内に存在するかどうかを示すブール・フラグ。

  • エッジ・ラベルを表す列の名前(この列がCSVファイル内に存在しない場合、このパラメータがすべてのエッジ・ラベルの定数として使用されます)

  • ColumnToAttrMapping配列(ファイル内にヘッダーが指定されている場合、nullである必要があります)

  • 並列度(DOP)

  • 変換前のオフセット(スキップするエッジ・レコードの数)を表す整数

  • エッジ・フラット・ファイル(.ope)の書込み先のOutputStream

  • 変換の進捗状況を追跡し、エラーが発生したときに何をすべきか決定するために使用できるオプションのDataConverterListener

追加パラメータを使用して、CSVファイルの異なる形式を指定できます。

  • レコード内のトークンを区切るために使用されるデリミタ文字。デフォルトはカンマ文字',’です。

  • 文字列値に特殊文字(カンマなど)が含めることができるように文字列値に引用符を付けるために使用する引用符。文字列自体の値に引用符を使用する場合、引用符を複製するか引用符の前にバックスラッシュ文字'\'を配置してエスケープする必要があります。例をいくつか示します。

    • "画面に、""Hello, world""と表示され…"

    • "しかし、ベーダーは、\"いや、私がお前の父親だ\"と答えた。"

  • 日付値を解析するために使用する日付形式。CSV変換の場合、このパラメータはnullにすることができますが、CSVに特定の日付形式が使用されている場合は指定することをお薦めします。特定の日付形式を指定すると、日付値を解析しようとするときにこの形式が最初のオプションとして使用されるため、パフォーマンスが向上します。日付形式の例をいくつか示します。

    • "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"

    • "MM/dd/yyyy HH:mm:ss"

    • "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'"

    • "dddd, dd MMMM yyyy hh:mm:ss"

    • "yyyy-MM-dd"

    • "MM/dd/yyyy"

  • CSVファイルに文字列値とともに改行文字が含まれるかどうかを示すフラグ。このパラメータがtrueに設定されている場合、改行または引用符が値として含まれるファイル内のすべての文字列に引用符を付ける必要があります。

    • "ドンキホーテの1行目は、""名前は思い出せないが、ラ・マンチャのある村に、""です。"

次のコード・フラグメントは、APIを使用して、nullのColumnToAttrMapping配列を使用してCSVファイルを.opeファイルに変換する方法を示します。

    String inputOPE    = "/path/mygraph-edges.csv";
    String outputOPE   = "/path/mygraph.ope"; 
    String eidColumn   = null;             // null implies that an integer sequence will be used
    String svidColumn  = "START_ID";
    String dvidColumn  = "END_ID";
    boolean hasLabel   = true;
    String labelColumn = "TYPE";

    isOPE = new FileInputStream(inputOPE);
    osOPE = new FileOutputStream(new File(outputOPE));
      
    // Convert Edges
    OraclePropertyGraphUtilsBase.convertCSV2OPE(isOPE, eidColumn, 0, svidColumn, dvidColumn, hasLabel, labelColumn, null, 1, 0, osOPE, null);

変換対象の前の例を使用する入力CSVには、列名およびその型を指定するヘッダーを含める必要があります。CSVファイルの例を次に示します。

START_ID:long,weight:float,END_ID:long,:TYPE
1,1.0,2,loves
1,1.0,5,admires
2,0.9,1,loves
1,0.5,3,likes
2,0.0,4,likes
4,1.0,5,is the dad of
3,1.0,4,turns to
5,1.0,3,saves from the dark side

生成される.opeファイルは、次のとおりです。

1,1,2,loves,weight,3,,1.0,
2,1,5,admires,weight,3,,1.0,
3,2,1,loves,weight,3,,0.9,
4,1,3,likes,weight,3,,0.5,
5,2,4,likes,weight,3,,0.0,
6,4,5,is%20the%20dad%20of,weight,3,,1.0,
7,3,4,turns%20to,weight,3,,1.0,
8,5,3,saves%20from%20the%20dark%20side,weight,3,,1.0,

エッジ・データが含まれるCSVファイルを変換するもう1つの方法は、次の入力引数の1つとしてCSV2OPEConfigオブジェクトを使用するconvertCSV2OPE APIを使用する方法です。

  • CSVファイルからエッジを読み取るInputStream

  • 構成を指定するCSV2OPVConfigオブジェクト

  • エッジ・フラット・ファイル(.opv)の書込み先のOutputStream

CSV2OPEConfigクラスには、目的のチューニングに応じて設定できる各種メンバーがあります。これは、各種構成パラメータをすべて使用してconvertCSV2OPE APIを呼び出すことと等価です。

次のコード・フラグメントは、CSV2OPEConfigオブジェクトを作成し、APIを使用してCSVファイルを.opeファイルに変換する方法を示します。

    String inputOPE    = "/path/mygraph-edges.csv";
    String outputOPE   = "/path/mygraph.ope"; 
    String eidColumn   = null;             // null implies that an integer sequence will be used
    String svidColumn  = "START_ID";
    String dvidColumn  = "END_ID";
    boolean hasLabel   = true;
    String labelColumn = "TYPE";

    InputStream isCSV = new FileInputStream(inputOPE);
    OutputStream osOPE = new FileOutputStream(new File(outputOPE));
     CSV2OPEConfig config = (CSV2OPEConfig) new CSV2OPEConfig()
    .setEidColumnName(eidColumn)
    .setSvidColumnName(svidColumn)
    .setDvidColumnName(dvidColumn)
    .setHasEdgeLabelColumn(hasLabel)
    .setElColumnName(labelColumn)
    .setCtams(null)
    .setDelimiterChar(',')
    .setQuotationChar('"');

    // Convert Edges
    OraclePropertyGraphCSVConverter.convertCSV2OPE(isCSV, config, osOPE);
    isCSV.close();
    osOPE.close();

CSV2OPEConfigColumnToAttrMapping配列が含まれないか、この配列がnullに設定されている場合、入力CSVには、列名およびデータ型を指定ヘッダーを含める必要があります。CSVファイルの例を次に示します。

START_ID:long,weight:float,END_ID:long,:TYPE
1,1.0,2,loves
1,1.0,5,admires
2,0.9,1,loves
1,0.5,3,likes
2,0.0,4,likes
4,1.0,5,is the dad of
3,1.0,4,turns to
5,1.0,3,saves from the dark side

生成される.opeファイルは、次のとおりです。

1,1,2,loves,weight,3,,1.0,
2,1,5,admires,weight,3,,1.0,
3,2,1,loves,weight,3,,0.9,
4,1,3,likes,weight,3,,0.5,
5,2,4,likes,weight,3,,0.0,
6,4,5,is%20the%20dad%20of,weight,3,,1.0,
7,3,4,turns%20to,weight,3,,1.0,
8,5,3,saves%20from%20the%20dark%20side,weight,3,,1.0,
5.13.7.3 頂点およびエッジ: 頂点とエッジの両方のデータが含まれる単一のCSVファイルのグラフ・フラット・ファイルのペアへの変換

プロパティ・グラフのサポートでは、頂点とエッジの両方のデータが含まれる単一のCSVファイルをグラフ・フラット・ファイルのペアに変換するオプションも用意されています。convertCSV2OPG APIを使用すると、この変更を行うことができ、その入力パラメータは、次のとおりです。

  • CSVファイルから頂点およびエッジを読み取るInputStream

  • 構成を指定するCSV2OPGConfigオブジェクト

  • 頂点フラット・ファイル(.opv)の書込み先のOutputStream

  • エッジ・フラット・ファイル(.ope)の書込み先のOutputStream

次のコード・フラグメントは、CSV2OPGConfigオブジェクトを作成し、APIを使用して単一のCSVファイルを.opvおよび.opeファイルに変換する方法を示します。

    String inputCSV    = "/path/mygraph.csv";
    String outputOPV   = "/path/mygraph.opv"; 
    String outputOPE   = "/path/mygraph.ope"; 

    String eidColumn   = null;             // null implies that an integer sequence will be used
    String svidColumn  = "START_ID";
    String dvidColumn  = "END_ID";
    boolean hasLabel   = true;
    String labelColumn = "TYPE";

    String[] vertexNames = new String [2];
    vertexNames[0] = svidColumn;
    vertexNames[1] = dvidColumn;

    InputStream isCSV = new FileInputStream(inputOPE);
    OutputStream osOPV = new FileOutputStream(new File(outputOPV));
    OutputStream osOPE = new FileOutputStream(new File(outputOPE));

     CSV2OPGConfig config = (CSV2OPGConfig) new CSV2OPGConfig()
    .setVidColumnNames(vertexNames)
    .setKeepOriginalID(true)
    .setOriginalIDName("myId")
    .setEidColumnName(eidColumn)
    .setSvidColumnName(svidColumn)
    .setDvidColumnName(dvidColumn)
    .setHasEdgeLabelColumn(hasLabel)
    .setElColumnName(labelColumn)
    .setCtams(null)
    .setDelimiterChar(',')
    .setQuotationChar('"');

    // Convert Graph
    OraclePropertyGraphCSVConverter.convertCSV2OPG(isCSV, config, osOPV, osOPE);
    isCSV.close();
    osOPV.close();
    osOPE.close();

CSV2OPEConfigColumnToAttrMapping配列が含まれないか、この配列がnullに設定されている場合、入力CSVには、列名およびデータ型を指定ヘッダーを含める必要があります。CSVファイルの例を次に示します。

START_ID:long,weight:float,END_ID:long,:TYPE
John,1.0,Mary,loves
John,1.0,"Skywalker, Luke",admires
Mary,0.9,John,loves
John,0.5,"Skywalker, Anakin",likes
Mary,0.0,"Darth Vader",likes
"Darth Vader",1.0,"Skywalker, Luke",is the dad of
"Skywalker, Anakin",1.0,"Darth Vader",turns to
"Skywalker, Luke",1.0,"Skywalker, Anakin",saves from the dark side

生成される.opvファイルは、次のとおりです。

-4984830045544402721,myId,1,John,,
6010046165116255926,myId,1,Mary,,
-5861570303285508288,myId,1,Skywalker%2C%20Anakin,,
-6450119557041804291,myId,1,Darth%20Vader,,
3941046021651468440,myId,1,Skywalker%2C%20Luke,,

生成される.opeファイルは、次のとおりです。

1,-4984830045544402721,6010046165116255926,loves,weight,3,,1.0,
2,-4984830045544402721,3941046021651468440,admires,weight,3,,1.0,
3,6010046165116255926,-4984830045544402721,loves,weight,3,,0.9,
4,-4984830045544402721,-5861570303285508288,likes,weight,3,,0.5,
5,6010046165116255926,-6450119557041804291,likes,weight,3,,0.0,
6,-6450119557041804291,3941046021651468440,is%20the%20dad%20of,weight,3,,1.0,
7,-5861570303285508288,-6450119557041804291,turns%20to,weight,3,,1.0,
8, 3941046021651468440,-5861570303285508288,saves%20from%20the%20dark%20side,weight,3,,1.0,

5.14 Pythonユーザー・インタフェースの例

The Oracle Big Data Spatial and Graphのプロパティ・グラフ・サポートには、Pythonユーザー・インタフェースの例が含まれています。これは、様々なプロパティ・グラフ操作を実行するPythonスクリプトおよびモジュールの例のセットを起動できます。

Pythonユーザー・インタフェースの例のインストール手順は、インストール・ホーム(デフォルトでは/opt/oracle/oracle-spatial-graph)の下にある/property_graph/examples/pyopg/READMEファイルにあります。

/property_graph/examples/pyopg/にあるPythonスクリプトの例は、Oracle Spatial and Graphプロパティ・グラフとともに使用でき、ニーズに応じてその例(またはそのコピー)を変更および拡張できます。

例を実行するためにユーザー・インタフェースを起動するには、pyopg.shスクリプトを使用します。

例には次のものが含まれています。

  • 例1: Oracle NoSQL Databaseに接続して、頂点およびエッジの数の単純なチェックを実行します。これを実行するには、次のようにします。

    cd /opt/oracle/oracle-spatial-graph/property_graph/examples/pyopg
    ./pyopg.sh
     
    connectONDB("mygraph", "kvstore", "localhost:5000")
    print "vertices", countV()
    print "edges", countE()
    

    前の例で、mygraphはOracle NoSQL Databaseに格納されているグラフの名前で、kvstoreおよびlocalhost:5000はOracle NoSQL Databaseにアクセスするための接続情報です。これらは環境に応じてカスタマイズする必要があります。

  • 例2: Apache HBaseに接続して、頂点およびエッジの数の単純なチェックを実行します。これを実行するには、次のようにします。

    cd /opt/oracle/oracle-spatial-graph/property_graph/examples/pyopg
    ./pyopg.sh
     
    connectHBase("mygraph", "localhost", "2181")
    print "vertices", countV()
    print "edges", countE()
    

    前の例で、mygraphはApache HBaseに格納されているグラフの名前で、localhostおよび2181はApache HBaseにアクセスするための接続情報です。これらは環境に応じてカスタマイズする必要があります。

  • 例3: Oracle NoSQL Databaseに接続していくつかの分析機能を実行します。これを実行するには、次のようにします。

    cd /opt/oracle/oracle-spatial-graph/property_graph/examples/pyopg
    ./pyopg.sh
     
    connectONDB("mygraph", "kvstore", "localhost:5000")
    print "vertices", countV()
    print "edges", countE()
     
    import pprint
     
    analyzer = analyst()
    print "# triangles in the graph", analyzer.countTriangles()
     
    graph_communities = [{"commid":i.getName(),"size":i.size()} for i in analyzer.communities().iterator()]
     
    import pandas as pd
    import numpy as np
     
    community_frame = pd.DataFrame(graph_communities)
    community_frame[:5]
     
    import matplotlib as mpl
    import matplotlib.pyplot as plt
     
    fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(16,12));
    community_frame["size"].plot(kind="bar", title="Communities and Sizes")
    ax.set_xticklabels(community_frame.index);
    plt.show()
    

    前の例は、Oracle NoSQL Databaseに接続し、頂点およびエッジに関する基本情報を出力し、インメモリー・アナリストを取得し、トライアングル数を計算し、コミュニティ検出を実行して、最後にコミュニティとそのサイズを棒グラフに表します。

  • 例4: Apache HBaseに接続していくつかの分析機能を実行します。これを実行するには、次のようにします。

    cd /opt/oracle/oracle-spatial-graph/property_graph/examples/pyopg
    ./pyopg.sh
     
    connectHBase("mygraph", "localhost", "2181")
    print "vertices", countV()
    print "edges", countE()
     
    import pprint
     
    analyzer = analyst()
    print "# triangles in the graph", analyzer.countTriangles()
     
    graph_communities = [{"commid":i.getName(),"size":i.size()} for i in analyzer.communities().iterator()]
    import pandas as pd
    import numpy as np
    community_frame = pd.DataFrame(graph_communities)
    community_frame[:5]
     
    import matplotlib as mpl
    import matplotlib.pyplot as plt
     
    fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(16,12));
    community_frame["size"].plot(kind="bar", title="Communities and Sizes")
    ax.set_xticklabels(community_frame.index);
    plt.show()
    

    前の例は、Apache HBaseに接続し、頂点およびエッジに関する基本情報を出力し、インメモリー・アナリストを取得し、トライアングル数を計算し、コミュニティ検出を実行して、最後にコミュニティとそのサイズを棒グラフに表します。

Pythonインタフェースの例の詳細は、インストール・ホームの下にある次のディレクトリを参照してください。

property_graph/examples/pyopg/doc/

5.15 iPython Notebookユーザー・インタフェースの例

主なプロパティ・グラフ機能に対する次のタイプのiPython Notebookシェル・インタフェースのサポートが提供されています。

iPython Notebookは、プロパティ・グラフに基づいてワークフローまたはデモを構築するのに便利なツールです。このトピックでは、iPython Notebookベースのプロパティ・グラフ・ワークフローに視覚化を追加する方法について説明します。

iPython Notebookのインストール手順は、インストール・ホーム(デフォルトでは/opt/oracle/oracle-spatial-graph)の下にある/property_graph/examples/pyopg/READMEファイルにあります。

iPython Notebookをインストールしたら、コード・スニペットをiPythonノートブックにコピーおよび貼付けできます。

開始するには次の手順に従います。

  1. 必要なライブラリをいくつか選択してインポートします。次に例を示します。

    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import sys
    default_stdout = sys.stdout
    default_stderr = sys.stderr
    reload(sys)
    sys.setdefaultencoding("utf-8")
    sys.stdout = default_stdout
    sys.stderr = default_stderr
    from pyopg.core import *
    pgx_config = JPackage('oracle.pgx.config')
    pgx_types = JPackage('oracle.pgx.common.types')
    pgx_control = JPackage('oracle.pgx.api')
    hbase = JPackage('oracle.pg.hbase')
    
  2. グラフ構成を作成します。次に例を示します。

    graph_builder = pgx_config.GraphConfigBuilder.forPropertyGraphHbase() \
    .setName("my_graph").setZkQuorum("hostname1").setZkClientPort(2181) \
    .setZkSessionTimeout(120000).setInitialEdgeNumRegions(3) \
    .setInitialVertexNumRegions(3).setSplitsPerRegion(1)
    graph_builder.addEdgeProperty("weight", pgx_types.PropertyType.DOUBLE, "1000000")
    
  3. グラフをインメモリー・アナリストに読み込みます。次に例を示します。

    opg = hbase.OraclePropertyGraph.getInstance(graph_builder.build())
    pgx_param = JClass("java.util.HashMap")()
    instance = JClass("oracle.pgx.api.Pgx").getInstance()
    if not instance.isEngineRunning():instance.startEngine(pgx_param)
    session = instance.createSession("my_recommender_session1")
    analyst = session.createAnalyst()
    pgxGraph = session.readGraphWithProperties(opg.getConfig(), True)
    pgxGraph.getNumEdges()
    
  4. (オプション)いくつかの頂点を読み出します。次に例を示します。

    for element in range(1,10,1):
        vertex = opg.getVertex(element)
        print 'Vertex ID: ' + str(element) + ' - Name: ' + vertex.getProperty("name")
    #Vertex ID: 1 - Name: Barack Obama
    #Vertex ID: 2 - Name: Beyonce
    #...
    
  5. 視覚化するエッジ(および頂点)からJSONオブジェクト(ノード、リンク)を作成します。次に例を示します。

    # Get Edges
    edges = opg.getEdges().iterator();
    edge = edges.next()
    # Dictiony for Nodes and Links
    nodes = []
    links = []
    names = []
    sources = []
    targets = []
    values = []
    # Get Nodes
    for count in range(1,20,1):
        # Vertex Values
        outVertexName = edge.getOutVertex().getProperty("name")
        outVertexRole = edge.getOutVertex().getProperty("country")
        inVertexName = edge.getInVertex().getProperty("name")
        inVertexRole = edge.getInVertex().getProperty("country")
        # Add out Vertex
        if {"name": outVertexName, "group": outVertexRole} not in nodes:
            nodes.append({"name": outVertexName, "group": outVertexRole})
            names.append(outVertexName)
        # Add in Vertex
        if {"name": inVertexName, "group": inVertexRole} not in nodes:
            nodes.append({"name": inVertexName, "group": inVertexRole})
            names.append(inVertexName)
        # Edge Information
        sources.append(outVertexName)
        targets.append(inVertexName)
        values.append(edge.getLabel())
        # Next Edge
        edge = edges.next()
    # Get Links
    for count in range(0,19,1):
        # Vertex Values
        outVertexName = sources[count]
        inVertexName = targets[count]
        # Edge Values
        source = names.index(outVertexName)
        target = names.index(inVertexName)
        value = values[count]
        links.append({"source": source, "target": target, "value": value})
    
    from IPython.display import Javascript
    import json
    # Transform the graph into a JSON graph
    data = {"nodes":nodes, "links":links}
    jsonGraph = json.dumps(data, indent=4)
    # Send to Javascript
    Javascript("""window.jsonGraph={};""".format(jsonGraph))
    
  6. グラフ描画用の<div>...</div>を設定します。次に例を示します。

    %%html
    <div id="d3-example"></div>
    <style>
    .node {stroke: #fff; stroke-width: 1.5px;}
    .link {stroke: #999; stroke-opacity: 5.6;}
    </style>
    
  7. D3力指向レイアウトでグラフ処理を実行します。次に例を示します。

    %%javascript
    // We load the d3.js library from the Web.
    require.config({paths: {d3: "http://d3js.org/d3.v3.min"}});
    require(["d3"], function(d3) {
        // The code in this block is executed when the
        // d3.js library has been loaded.
        // First, we specify the size of the canvas containing
        // the visualization (size of the <div> element).
        var width = 800,  height = 600;
        // We create a color scale.
        var color = d3.scale.category20();
        // We create a force-directed dynamic graph layout.
        var force = d3.layout.force().charge(-300).linkDistance(100).size([width, height]);
        // In the <div> element, we create a <svg> graphic
        // that will contain our interactive visualization.
        var svg = d3.select("#d3-example").select("svg")
        if (svg.empty()) {
            svg = d3.select("#d3-example").append("svg").attr("width", width).attr("height", height);
        }
        // We load the JSON graph we generated from iPython input
        var graph = window.jsonGraph;
        plotGraph(graph);
        // Graph Plot function
        function plotGraph(graph) {
            // We load the nodes and links in the force-directed graph.
            force.nodes(graph.nodes).links(graph.links).start();
            // We create a <line> SVG element for each link in the graph.
            var link = 
    svg.selectAll(".link").data(graph.links).enter().append("line").attr("class",
     "link").attr("stroke-width", 7);
            // Link Value
            link.append("title").text(function(d) { 
                return d.value; 
            });
            // We create a <circle> SVG element for each node
            // in the graph, and we specify a few attributes.
            var node = 
    svg.selectAll(".node").data(graph.nodes).enter().append("circle").attr("class",
     "node").attr("r", 16)  //radius
            .style("fill", function(d) {
                // The node color depends on the club.
                return color(d.group); 
            }).call(force.drag); 
            // The name of each node is the node number.
            node.append("title").text(function(d) { 
                var info = "Name: " + d.name + "\n" + "Country: " + d.group;
                return info; 
            });
            // Text Over Nodes
            var text = svg.append("g").selectAll("text").data(force.nodes()).enter().append("text").attr("x", function(d) { 
                return -10 
            }).attr("y", 0).style("font-size","10px").text(function(d) { 
                if (d.name.length > 15) {
                    return d.name.substring(0, 15) + "...";
                }
                return d.name; 
            });
            // We bind the positions of the SVG elements
            // to the positions of the dynamic force-directed graph,
            // at each time step.
            force.on("tick", function() {
                link.attr("x1", function(d) { 
                    return d.source.x; 
                }).attr("y1", function(d) { 
                    return d.source.y; 
                }).attr("x2", function(d) { 
                    return d.target.x; 
                }).attr("y2", function(d) { 
                    return d.target.y;
                });
                node.attr("cx", function(d) {
                    return d.x;
                }).attr("cy", function(d) { 
                    return d.y; 
                });  
                text.attr("transform", function(d) {
                    return "translate(" + d.x + "," + d.y + ")";
                }); 
            });
        }
    });
    

前述のすべての手順を実行した場合、次のようなイメージがHTML領域に表示されます。

図5-3 iPython Notebookから生成されるイメージの例

図5-3の説明が続きます
「図5-3 iPython Notebookから生成されるイメージの例」の説明