プライマリ・コンテンツに移動

Oracle® Big Data Spatial and Graphユーザーズ・ガイドおよびリファレンス リリース2.3 E70114-05 |
| 目次

前 | 次 |

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

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

- プロパティ・グラフについて
  プロパティ・グラフでは、プロパティ(キー値ペア)をグラフの頂点およびエッジに簡単に関連付けることができ、大量のデータ・セット間の関係に基づく分析操作が可能になります。
- プロパティ・グラフのデータ形式について
  次のグラフ形式がサポートされています。
- プロパティ・グラフの開始
  プロパティ・グラフを開始するには、次の主要手順に従います。
- プロパティ・グラフ・データ用のJava APIの使用
  プロパティ・グラフの作成には、Java APIを使用したプロパティ・グラフとそのオブジェクトの作成が含まれます。
- プロパティ・グラフ・データのテキスト索引付けの管理
  Oracle Big Data Spatial and Graphの索引付けは、特定のキー/値またはキー/テキスト・ペア別に要素を高速に読み取ることを可能にします。これらの索引は、要素タイプ(頂点またはエッジ)、キー(および値)のセットおよび索引タイプに基づいて作成されます。
- PGQLを使用したプロパティ・グラフ・データに対する問合せ
  Oracle Big Data Spatial and Graphは、豊富なグラフ・パターン一致機能セットをサポートしています。
- プロパティ・グラフ・データを使用したApache Sparkの使用
  Apache Sparkは、大量のデータを効率的に処理することを可能にし、データを処理するためのライブラリ・セット(SQL、MLlib、Spark StreamingおよびDataFrame)が用意されています。Apache Sparkでは、HDFS、Oracle NoSQL DatabaseおよびApache HBaseなどの様々なソースからデータを読み込むことができます。
- セキュアなOracle NoSQL Databaseのサポート
  Oracle Big Data Spatial and Graphプロパティ・グラフ・サポートは、Oracle NoSQL Databaseのセキュア・インストールと非セキュア・インストールの両方で機能します。このトピックでは、セキュアなOracle NoSQL Database設定でプロパティ・グラフ機能を使用する方法についての情報を提供します。
- Apache HBaseに格納されているグラフでのセキュリティの実装
  Oracle Big Data Spatial and Graphのプロパティ・グラフを保護するために、Apache HBaseでKerberos認証を使用することが推奨されます。
- プロパティ・グラフ・データでのGroovyシェルの使用
  Oracle Big Data Spatial and Graphプロパティ・グラフ・サポートには、組込みのGroovyシェル(オリジナルのGremlin Groovyシェル・スクリプトに基づく)が含まれています。このコマンドライン・シェル・インタフェースを使用して、Java APIを参照できます。
- サンプル・プログラムの探索
  ソフトウェア・インストールには、プロパティ・グラフの作成および操作方法を習得するために使用できる、プログラムの例のディレクトリが含まれています。
- Oracleフラット・ファイル形式の定義
  プロパティ・グラフは、頂点用の記述ファイルとエッジ用の記述ファイルの2つのフラット・ファイルに定義できます。
- Pythonユーザー・インタフェースの例
  Oracle Big Data Spatial and Graphのプロパティ・グラフ・サポートには、Pythonユーザー・インタフェースの例が含まれています。これは、様々なプロパティ・グラフ操作を実行するPythonスクリプトおよびモジュールの例のセットを起動できます。

## 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 単純なプロパティ・グラフの例」の説明

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 Oracleプロパティ・グラフのアーキテクチャ」の説明

- インメモリー・アナリスト
- データ・アクセス・レイヤー
- ストレージ管理
- RESTful Webサービス

#### 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 プロパティ・グラフのデータ形式について

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

- GraphMLデータ形式
- GraphSONデータ形式
- GMLデータ形式
- Oracleフラット・ファイル形式

### 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フラット・ファイルを示しています。

関連項目:

「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プログラムを作成します。

   「プロパティ・グラフ・データ用のJava APIの使用」を参照してください。

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

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

- Java APIの概要
- グラフ・データのパラレル・ロード
  グラフ・データのパラレル・ロードを実行するために、Java APIが提供されています。
- プロパティ・グラフ・インスタンスのオープンおよびクローズ
- 頂点の作成
- エッジの作成
- 頂点およびエッジの削除
- データベースから埋込みインメモリー・アナリストへのグラフの読込み
- 頂点のラベルの指定
- インメモリー・グラフの構築
- プロパティ・グラフの削除

### 5.4.1 Java APIの概要

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

- Oracle Big Data Spatial and Graph Java API
- TinkerPop Blueprints Java API
- Apache Hadoop Java API
- Oracle NoSQL Database Java API
- Apache HBase 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;

関連項目:

『HBase 0.98.6-cdh5.3.2 API』

`http://archive.cloudera.com/cdh5/cdh/5/hbase/apidocs/index.html?overview-summary.html`

### 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();
    }

#### 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("philanthropist")) {
    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<Vertex> iter = m_obama.getVertices(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 " ";
    }
    }

前に定義した操作コールバックを使用して、次のコード・フラグメントはプロパティ・グラフをロードし、操作コールバックのインスタンスを作成し、その後に`OraclePropertyGraph`で`addAttributeToAllVertices`および`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
    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
    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));

    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からの適切なクラスを使用する必要があります。

- Oracle NoSQL Databaseの使用
- Apache HBaseの使用

#### 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);

    // 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`に指定する接続情報と同じです。

- Oracle NoSQL Databaseの使用
- Apache HBaseの使用

#### 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を使用して管理されます。この節の続きでは、データ・アクセス・レイヤーのプロパティ・グラフ機能を使用してテキスト索引を作成する方法に焦点を当てます。

- プロパティ・グラフ・データのテキスト索引の構成
- プロパティ・グラフ・データの自動索引の使用
- プロパティ・グラフ・データの手動索引の使用
- プロパティ・グラフ・テキスト索引に対する検索問合せの実行
- データ型の処理
- Zookeeperへのコレクションの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*").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でこの接頭辞/接尾辞を追加する方法について説明します。

- 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を使用したパラレル・テキスト問合せ

`LuceneIndex`で`getPartitioned`メソッドを呼び出して、サブディレクトリのセットへの接続の配列(`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を使用したパラレル・テキスト検索

`SolrIndex`で`getPartitioned`メソッドを呼び出して、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を使用すると、頂点とエッジ、および頂点とエッジのプロパティに関する制約で構成されたグラフ問合せパターンを表現できます。詳細は、次を参照してください。

- PGQLの仕様: https://docs.oracle.com/cd/E56133_01/latest/reference/pgql-specification.html

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

    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)`: エッジのデータベース表現からエッジ・ラベルを取得します。

- Apache HBase内のプロパティ・グラフ・データを使用したApache Sparkの使用
- Oracle NoSQL Databaseに格納されているプロパティ・グラフ・データとApache Sparkとの統合

### 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の場合、`dbRepr`は`Result`クラスの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の場合、`dbRepr`は`Row`クラスの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 サンプル・プログラムの探索

ソフトウェア・インストールには、プロパティ・グラフの作成および操作方法を習得するために使用できる、プログラムの例のディレクトリが含まれています。

- サンプル・プログラムについて
- サンプル・プログラムのコンパイルおよび実行
- 出力の例について
- 例: プロパティ・グラフの作成
- 例: プロパティ・グラフの削除
- 例: 頂点およびエッジの追加と削除

### 5.11.1 サンプル・プログラムについて

サンプル・プログラムは、`examples/dal`という名前のインストール・サブディレクトリに配布されます。例はHBaseおよびOracle NoSQL Database用にレプリケートされるため、選択したバックエンド・データベースに対応するプログラムのセットを使用できます。次の表に、プログラムの要素を示します。

表5-4 プロパティ・グラフのプログラム例(一部)

プログラム名 | 説明
--- | ---
ExampleNoSQL1 ExampleHBase1 | 1つの頂点からなる最小プロパティ・グラフを作成し、様々なデータ型のプロパティを頂点に設定し、保存済のグラフの記述をデータベースに問い合せます。
ExampleNoSQL2 ExampleHBase2 | Example1と同じ最小プロパティ・グラフを作成してから、それを削除します。
ExampleNoSQL3 ExampleHBase3 | 複数の頂点およびエッジを持つグラフを作成します。いくつかの頂点およびエッジを明示的に削除し、その他は他の必須オブジェクトを削除することによって暗黙的に削除します。この例は、オブジェクトの現在のリストを表示するために、データベースを繰り返し問い合せます。

### 5.11.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.11.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.11.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.11.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.11.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.12 Oracleフラット・ファイル形式の定義

プロパティ・グラフは、頂点用の記述ファイルとエッジ用の記述ファイルの2つのフラット・ファイルに定義できます。

- プロパティ・グラフ記述ファイルについて
- 頂点ファイル
- エッジ・ファイル
- 特殊文字のエンコーディング
- Oracleフラット・ファイル形式でのプロパティ・グラフの例
- Oracle Database表のOracle定義のプロパティ・グラフ・フラット・ファイルへの変換
- 頂点およびエッジのCSVファイルのOracle定義のプロパティ・グラフ・フラット・ファイルへの変換

### 5.12.1 プロパティ・グラフ記述ファイルについて

ファイルのペアにより、プロパティ・グラフが記述されます。

- 頂点ファイル: プロパティ・グラフの頂点を記述します。このファイルには、`.opv`というファイル名拡張子が付きます。

- エッジ・ファイル: プロパティ・グラフのエッジを記述します。このファイルには、`.ope`というファイル名拡張子が付きます。

これら2つのファイルは同じベース名を共有することをお薦めします。たとえば、`simple.opv`および`simple.ope`によってプロパティ・グラフを定義します。

### 5.12.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.12.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.12.4 特殊文字のエンコーディング

頂点およびエッジ・ファイルのエンコーディングはUTF-8です。表5-8に、頂点またはエッジ・プロパティ(キー値ペア)またはエッジ・ラベルに表示されるときに文字列としてエンコードされる必要のある特殊文字をリストします。その他すべての文字は、エンコーディングは必要ありません。

表5-8 Oracleフラット・ファイル形式での特殊文字コード

特殊文字 | 文字列のエンコーディング | 説明
--- | --- | ---
`%` | `%25` | パーセント
`\t` | `%09` | タブ
`` | `%20` | スペース
`\n` | `%0A` | 改行
`\r` | `%0D` | リターン
`,` | `%2C` | カンマ

### 5.12.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.12.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.12.7 頂点およびエッジのCSVファイルのOracle定義のプロパティ・グラフ・フラット・ファイルへの変換

一部のアプリケーションでは、CSV (カンマ区切りの値)形式を使用してグラフの頂点およびエッジをエンコードします。この形式では、CSVファイルの各レコードが、単一の頂点またはエッジおよびそのプロパティを表します。グラフの頂点を表すCSVファイルをOracle定義のフラット・ファイル形式定義(頂点を表す`.opv`、エッジを表す`.ope`)に変換できます。

変換するCSVファイルには、列が表す属性の列名および型を指定するヘッダー行が含まれる場合があります。ヘッダーに属性名のみが含まれる場合、コンバータでは、値のデータ型が文字列であると見なされます。

CSVをOPVまたはOPEに変換するJava APIは、`InputStream`を受け取り、ここから頂点またはエッジを(CSVから)読み込み、これらを`.opv`または`.ope`形式で`OutputStream`に書き込みます。コンバータのAPIを使用して変換プロセスをカスタマイズすることもできます。

次のサブトピックでは、頂点およびエッジの変換の手順を示します。最初の2つの手順は非常に似ていますが、頂点およびエッジに固有の差異があります。

- 頂点: CSVファイルのOracle定義のフラット・ファイル形式(.opv)への変換
- エッジ: CSVファイルのOracle定義のフラット・ファイル形式(.ope)への変換
- 頂点およびエッジ: 頂点とエッジの両方のデータが含まれる単一のCSVファイルのグラフ・フラット・ファイルのペアへの変換

#### 5.12.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();

`CSV2OPVConfig`に`ColumnToAttrMapping`配列が含まれる場合、`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.12.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();

`CSV2OPEConfig`に`ColumnToAttrMapping`配列が含まれないか、この配列が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.12.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();

`CSV2OPEConfig`に`ColumnToAttrMapping`配列が含まれないか、この配列が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.13 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/