2 Oracle Database環境でのプロパティ・グラフの使用

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

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

プロパティ・グラフを使用すると、データを異なる方法で表示できます。

グラフでデータ・エンティティの頂点を作成し、それらの間の関係をエッジとして作成することで、データをグラフとしてモデル化できます。たとえば、銀行顧客アカウントは頂点になり、それらの間の送金関係はエッジになります。

データをグラフとして表示すると、データ間の接続および関係に基づいてデータを分析できます。PageRankなどのグラフ分析アルゴリズムを実行して、Webページ間のリンクなど、データ・エンティティ間の関係に基づいてその相対的な重要性を測定できます。

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

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

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

  • 出力エッジのセット

  • 入力エッジのセット

  • プロパティの集まり

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

  • 出力頂点

  • 入力頂点

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

  • プロパティの集まり

頂点およびエッジでは、各プロパティが一意の名前で識別されます。

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

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

図2-1の説明が続きます
「図2-1 単純なプロパティ・グラフの例」の説明

プロパティ・グラフには、自己エッジ(ソース頂点と宛先頂点が同じエッジ)と、同じソース頂点と宛先頂点の間の複数のエッジを含めることができます。

また、プロパティ・グラフには、同じグラフ内に様々なタイプの頂点およびエッジを含めることもできます。たとえば、グラフには、ラベルがPersonの頂点セットとラベルがPlaceの頂点セットを、これら2つの頂点セットに関連する様々なプロパティとともに含めることができます。

プロパティ・グラフ・データ・モデルは、W3C規格ベースのResource Description Framework (RDF)グラフ・データ・モデルに似ていますが、プロパティ・グラフ・データ・モデルはRDFよりも単純であり、厳密ではありません。

プロパティ・グラフ・データ・モデルの機能および分析APIにより、プロパティ・グラフは次のようなユースケースでよい候補になります。

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

  • 傾向と顧客行動の予測

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

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

ノート:

データベース側でOracleがサポートするプロパティ・グラフ・データ・モデルでは、頂点にラベル付けできません。しかし、指定した頂点プロパティの値を、1つ以上のラベルとして扱うことができます。

関連トピック

2.1.2 Oracle Databaseのプロパティ・グラフのサポートとは

プロパティ・グラフは、Hadoopのビッグ・データに対してサポートされているのに加えて、Oracle Databaseでサポートされます。このサポートは、データベース内グラフ問合せ、グラフ問合せおよび分析用のインメモリー・グラフ・サーバーおよびグラフ・クライアント・コンポーネントで構成されます。

2.1.2.1 インメモリー・グラフ・サーバー(PGX)

インメモリー・グラフ・サーバー・レイヤーを使用すると、並列のインメモリー実行を使用してプロパティ・グラフを分析できます。50を超える分析関数が用意されています。カテゴリと、そこに含まれる具体的な関数の例を次に示します。

  • 中心性 - 次数中心性、固有ベクトル中心性、PageRank、中間中心性、近接中心性
  • コンポーネントおよびコミュニティ - 強力に接続されたコンポーネント(TarjanおよびKosaraju)。弱く接続されたコンポーネント
  • TwitterのWho-To-Follow (おすすめユーザー)、ラベル伝播。
  • パス探索 - 単一ソースのすべての宛先(ベルマン - フォード)、ダイクストラの最短パス、ホップ距離(幅優先探索)
  • コミュニティ評価 - 係数(トライアングル・カウンティング)、コンダクタンス、モジュール性、Adamic-Adarカウンタ。

インメモリー・グラフ・サーバー(PGX)の詳細は、インメモリー・グラフ・サーバー(PGX)の使用を参照してください。

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

データ・アクセス・レイヤーは、プロパティ・グラフの作成および削除、頂点およびエッジの追加および削除、キー値ペアを使用した頂点およびエッジの検索、テキスト索引の作成、およびその他の操作の実行に使用できる、Java APIのセットを提供します。

詳細は、次を参照してください。

2.1.2.3 プロパティ・グラフ・アーキテクチャのオプション

Oracle Databaseのプロパティ・グラフ機能を使用する場合は、次の2つのアーキテクチャ・オプションがあります。

どちらのオプションでも、プロパティ・グラフ問合せ言語(PGQL)を使用できます。

インメモリー・グラフ・サーバー(PGX) (3層)でのグラフ問合せおよび分析の実行

プロパティ・グラフをインメモリー・グラフ・サーバーにロードできます。このサーバーは、グラフ計算専用のアーキテクチャを備えています。このグラフでのすべての問合せおよび分析操作は、グラフ・サーバーのインメモリーで実行できます。このグラフは、リレーショナル表から直接作成することも、データベースにグラフを格納するプロパティ・グラフ・スキーマからロードすることもできます。メモリー内のグラフは変更(頂点とエッジの挿入、更新および削除、アルゴリズムの実行結果に対する新しいプロパティの作成)できます。グラフ・サーバーによって変更がリレーショナル表に書き戻されることはありません。

インメモリー・グラフ・サーバー(PGX)は通常、データベースとは別のサーバーにあり、スタンドアロンで実行することも、Oracle WebLogic ServerやApache Tomcatなどのコンテナで実行することもできます。この手法(プロパティ・グラフをインメモリー・グラフ・サーバーにロード)では、次の図に示すように3層アーキテクチャを使用します。

図2-3 2層プロパティ・グラフ・アーキテクチャ

図2-2の説明が続きます
「図2-3 2層プロパティ・グラフ・アーキテクチャ」の説明

Oracle Database (2層)へのグラフのロード

グラフをインメモリー・グラフ・サーバーにロードする必要がない場合は、別の手法を使用できます。リレーショナル表のデータからプロパティ・グラフを作成し、プロパティ・グラフ・スキーマ(VT$表およびGE$表)に格納します。その後、このグラフでPGQL問合せを実行できます。

データベースでサポートされていない分析アルゴリズムおよびPGQL問合せを実行するために、このグラフをメモリーにロードできます。グラフ内のデータから自動的に更新を定期的にフェッチしてデータの同期を維持するように、インメモリー・グラフ・サーバーを構成できます。

この手法では、次の図に示すように2層アーキテクチャを使用します。

図2-3 2層プロパティ・グラフ・アーキテクチャ

図2-3の説明が続きます
「図2-3 2層プロパティ・グラフ・アーキテクチャ」の説明

2.2 Oracle Database表のプロパティ・グラフ・ビュー

Oracle Databaseに格納されているデータに対してプロパティ・グラフ・ビューを作成できます。これらのビューでPGQLを使用して、様々なグラフ分析操作を実行できます。

PGQLのCREATE PROPERTY GRAPH文を使用すると、グラフに関するメタデータを含むビューのようなオブジェクトを作成できます。このグラフはPGQLを使用して問い合せることができます。

プロパティ・グラフ・ビューは、リレーショナル・データベース表に存在するデータに対して直接作成されます。グラフはデータベース表に格納されているため、スキーマがあります。これは、Oracle Databaseのプロパティ・グラフ・スキーマ・オブジェクトで説明されているように、データがソース表からプロパティ・グラフ・スキーマ表にコピーされる柔軟なスキーマで作成されるグラフとは異なります。

プロパティ・グラフ・ビューの主な利点の1つは、データベース表に対するすべての更新がすぐにグラフに反映されることです。

PGビューのメタデータ表

CREATE PROPERTY GRAPH文が実行されるたびに、ユーザー独自のスキーマにメタデータ表が作成されます。

次の表では、CREATE PROPERTY GRAPH文の実行時にグラフごとに作成されるメタデータ表のセットについて説明します。

表2-1で下線が付いているすべての列は、表の主キーの一部です。また、すべての列にNOT NULL制約があります。

表2-1 PGビューのメタデータ表

表名 説明
graphName_ELEM_TABLE$ グラフ要素(頂点/エッジ)表のメタデータ(要素表ごとに1行):
  • ET_NAME: 要素表の名前(別名)
  • ET_TYPE: VERTEXまたはEDGE
  • SCHEMA_NAME: 基礎となる表のスキーマの名前
  • TABLE_NAME: 基礎となる表の名前
graphName_LABEL$ 要素表のラベルのメタデータ(ラベルごとに1行、要素表ごとに1ラベル):
  • LABEL_NAME: ラベルの名前
  • ET_NAME: 要素表の名前(別名)
  • ET_TYPE: VERTEXまたはEDGE
graphName_PROPERTY$

ラベルを介して公開される列を記述するメタデータ(プロパティごとに1行)

  • PROPERTY_NAME: プロパティの名前
  • ET_NAME: 要素表の名前(別名)
  • ET_TYPE: VERTEXまたはEDGE
  • LABEL_NAME: このプロパティが属するラベルの名前
  • COLUMN_NAME: 列の名前(最初は、プロパティ名が列名と等しいケースのみが許可されます)
graphName_KEY$

頂点/エッジ・キーを記述するメタデータ(キーの列ごとに1行)

  • COLUMN_NAME: キーの列の名前
  • COLUMN_NUMBER: キー内の列の番号

    たとえば、KEY ( a, b, c )では、aの番号は1、bの番号は2、cの番号は3です。

  • KEY_TYPE: VERTEXまたはEDGE
  • ET_NAME: 要素表の名前(別名)

graphName_SRC_DST_KEY$

エッジのソース/宛先キーを記述するメタデータ(キーの列ごとに1行):

  • ET_NAME: 常にエッジ表である要素表の名前(別名)
  • VT_NAME: 頂点表の名前
  • KEY_TYPE: EDGE_SOURCEまたはEDGE_DESTINATION
  • ET_COLUMN_NAME: キー列の名前
  • ET_COLUMN_NUMBER: キー内の列の番号

    たとえば、KEY ( a, b, c )では、aの番号は1、bの番号は2、cの番号は3です。

ノート:

現在、サポートされているのはSOURCE KEY ( ... ) REFERENCES T1のみです。そのため、エッジのソース/宛先キーのみが格納されます。

例2-1 プロパティ・グラフ・ビューの作成

次のCREATE PROPERTY GRAPH文について考えます。


CREATE PROPERTY GRAPH student_network
  VERTEX TABLES(
    person
      KEY ( id )
      LABEL student
      PROPERTIES( name ),
    university
      KEY ( id )
      PROPERTIES( name )
  )
  EDGE TABLES(
    knows
      key (person1, person2)
      SOURCE KEY ( person1 ) REFERENCES person
      DESTINATION KEY ( person2 ) REFERENCES person
      NO PROPERTIES,
    person AS studentOf
      key (id, university)
      SOURCE KEY ( id ) REFERENCES person
      DESTINATION KEY ( university ) REFERENCES university
      NO PROPERTIES
  )
プロパティ・グラフ・ビューを作成するには、executeメソッドのオプション・パラメータでPG_VIEW=Tフラグを使用します。

ノート:

  • プロパティ・グラフ・ビューは、RDBMS Java APIを使用してのみ作成できます。
  • SQLclを使用している場合、プロパティ・グラフ・ビューの作成はサポートされません。ただし、作成したプロパティ・グラフ・ビューは、SQLclのPGQL SELECT文を使用して問い合せることができます。
  • Python APIまたはグラフ・ビジュアライゼーション・ツールを使用している場合、プロパティ・グラフ・ビューの作成と問合せは両方ともサポートされません。
stmt.execute("CREATE PROPERTY GRAPH student_network ...", null, "PG_VIEW=T");

これにより、次のメタデータ表が作成されます。


SQL> select * from STUDENT_NETWORK_ELEM_TABLE$;
 
ET_NAME         ET_TYPE    SCHEMA_NAME     TABLE_NAME
--------------- ---------- --------------- ---------------
PERSON          VERTEX     SCOTT           PERSON
UNIVERSITY      VERTEX     SCOTT           UNIVERSITY
KNOWS           EDGE       SCOTT           KNOWS
STUDENTOF       EDGE       SCOTT           PERSON
 
SQL> select * from STUDENT_NETWORK_LABEL$;
 
LABEL_NAME      ET_NAME         ET_TYPE
--------------- --------------- ----------
STUDENT         PERSON          VERTEX
UNIVERSITY      UNIVERSITY      VERTEX
KNOWS           KNOWS           EDGE
STUDENTOF       STUDENTOF       EDGE
 
SQL> select * from STUDENT_NETWORK_PROPERTY$;
 
PROPERTY_NAME   ET_NAME         ET_TYPE    LABEL_NAME      COLUMN_NAME
--------------- --------------- ---------- --------------- ---------------
NAME            PERSON          VERTEX     STUDENT         NAME
NAME            UNIVERSITY      VERTEX     UNIVERSITY      NAME
 
SQL> select * from STUDENT_NETWORK_KEY$;
 
COLUMN_NAME     COLUMN_NUMBER KEY_TY ET_NAME
--------------- ------------- ------ ---------------
ID                          1 VERTEX PERSON
ID                          1 VERTEX UNIVERSITY
PERSON1                     1 EDGE   KNOWS
PERSON2                     2 EDGE   KNOWS
ID                          1 EDGE   STUDENTOF
UNIVERSITY                  2 EDGE   STUDENTOF
 
SQL> select * from STUDENT_NETWORK_SRC_DST_KEY$;
 
ET_NAME     VT_NAME        KEY_TYPE         ET_COLUMN_NAME  ET_COLUMN_NUMBER
--------------- ---------- ---------------- --------------- ----------------
KNOWS       PERSON         EDGE_SOURCE      PERSON1                        1
KNOWS       PERSON         EDGE_DESTINATION PERSON2                        1
STUDENTOF   PERSON         EDGE_SOURCE      ID                             1
STUDENTOF   UNIVERSITY     EDGE_DESTINATION UNIVERSITY                     1


プロパティ・グラフ・ビューstudent_networkでPGQL問合せを実行できるようになりました。

2.3 Oracle Databaseのプロパティ・グラフ・スキーマ・オブジェクト

プロパティ・グラフPL/SQLおよびJava APIは特別なOracleデータベース・スキーマ・オブジェクトを使用します。

このトピックでは、グラフ・データの処理に対するプロパティ・グラフ・スキーマ・アプローチに関連したオブジェクトについて説明します。これは、制限のある、2表スキーマを使用したプロパティ・グラフの処理で説明されている非推奨の2表スキーマ・アプローチよりも柔軟なアプローチです。

Oracle Spatial and Graphにより、Oracle Databaseのプロパティ・グラフ・データを格納、問合せ、および操作できます。たとえば、myGraphという名前のプロパティ・グラフを作成するには、Java API (oracle.pg.rdbms.OraclePropertyGraph)またはPL/SQL API (MDSYS.OPG_APISパッケージ)のいずれかを使用できます。

PL/SQL APIの使用:

BEGIN
     opg_apis.create_pg(
           'myGraph',  
           dop => 4,             -- degree of parallelism
           num_hash_ptns => 8,   -- number of hash partitions used to store the graph
           tbs => 'USERS',       -- tablespace
           options => 'COMPRESS=T'
           );
END;
/

Java APIの使用:

  cfg = GraphConfigBuilder
            .forPropertyGraphRdbms()
            .setJdbcUrl("jdbc:oracle:thin:@127.0.0.1:1521:orcl")  
            .setUsername("<your_user_name>")
            .setPassword("<your_password>")  
            .setName("myGraph") 
            .setMaxNumConnections(8) 
            .setLoadEdgeLabel(false) 
            .build();

  OraclePropertyGraph opg = OraclePropertyGraph.getInstance(cfg);

2.3.1 プロパティ・グラフ表(詳細情報)

プロパティ・グラフがデータベースに確立された後、いくつかの表がユーザーのスキーマに自動的に作成され、接頭辞としてグラフ名が、接尾辞としてVT$またはGE$が付きます。たとえば、myGraphという名前のグラフの場合、表myGraphVT$が作成されて頂点およびそのプロパティ(K/Vペア)が格納され、表myGraphGE$が作成されてエッジおよびそのプロパティが格納されます。

追加の内部表がIT$およびGT$の接尾辞で作成され、テキスト索引メタデータおよびグラフ・スケルトン(トポロジ構造)が格納されます。

表myGraphVT$およびmyGraphGE$の定義は次のとおりです。これらはSQLベースの分析およびSQLべースのプロパティ・グラフの問合せに重要です。VT$およびGE$表の両方で、VTS、VTEおよびFEは予約済の列で、列SLはセキュリティ・ラベル用、列K、T、V、VNおよびVTはグラフ要素のプロパティ(K/Vペア)に関する情報をまとめて格納します。VT$表で、VIDは頂点IDを格納するための長整数です。GE$表で、EID、SVIDおよびDVIDは、エッジID、出力(from)頂点IDおよび入力(to)頂点IDを格納するための長整数列です。

SQL> describe myGraphVT$
 Name                       Null?    Type
 ----------------------------------------- -------- ----------------------------
 VID                       NOT NULL NUMBER
 K                                  NVARCHAR2(3100)
 T                                  NUMBER(38)
 V                                  NVARCHAR2(15000)
 VN                                 NUMBER
 VT                                 TIMESTAMP(6) WITH TIME ZONE
 SL                                 NUMBER
 VTS                                DATE
 VTE                                DATE
 FE                                 NVARCHAR2(4000)


SQL> describe myGraphGE$
 Name                       Null?    Type
 ----------------------------------------- -------- ----------------------------
 EID                        NOT NULL NUMBER
 SVID                       NOT NULL NUMBER
 DVID                       NOT NULL NUMBER
 EL                                  NVARCHAR2(3100)
 K                                   NVARCHAR2(3100)
 T                                   NUMBER(38)
 V                                   NVARCHAR2(15000)
 VN                                  NUMBER
 VT                                  TIMESTAMP(6) WITH TIME ZONE
 SL                                  NUMBER
 VTS                                 DATE
 VTE                                 DATE
 FE                                  NVARCHAR2(4000)

簡単にするために、1つのグラフ名だけを許可し、大文字と小文字は区別されません。

VT$表とGE$表の両方で、列K、T、V、VN、VTはグラフ要素のプロパティ(K/Vペア)に関するすべての情報をまとめて格納し、SLはセキュリティラベルに使用され、VTS、VTEおよびFEは予約列になります。

プロパティ・グラフのスキーマ設計で、プロパティ値は数値データ型(long、int、double、float)の場合、VN列に格納され、タイムスタンプの場合、VT列に格納され、文字列、booleanおよびその他のシリアライズ可能データ型の場合、V列に格納されます。よりよいOracleテキスト問合せサポートのために、プロパティ値のリテラル表現は、データ型が数値またはタイムスタンプであっても、V列に格納されます。すべてのサポートされるデータ型を区別するために、整数IDはT列に格納されます。(可能なT列の整数IDの値は、Vertexファイルの表のvalue_typeフィールドに対してリストされています。)

VT$およびGE$表の両方のK列にはプロパティ・キーが格納されます。各エッジにはString型のラベルが必要で、そのラベルはGE$表のEL列に格納されます。

VT$表とGE$表のT列は、その列が示すプロパティの値のデータ型を表す数値です。たとえば、1は値が文字列、2は値が整数、などを意味します。T列に指定できる値および関連するデータ型の一部は次のとおりです。

国際文字をサポートするために、NVARCHAR列がVT$およびGE$表で使用されます。デフォルトのデータベース文字セットとして、UTF8をお薦めします。また、V列のサイズは15000で、これには、32K VARCHAR (MAX_STRING_SIZE = EXTENDED)の有効化が必要です

頂点を格納するためのVT$表スキーマには、次の列があります。

  • VID: 頂点のIDを示す長い列。

  • VL: 頂点のラベルを表す文字列列。

  • K: プロパティの名前を示す文字列の列。頂点に関連付けられているプロパティがない場合、この列の値は空白にする必要があります。

  • T: プロパティのタイプを示す長い列。

  • V: プロパティの値を文字列として示す文字列の列。プロパティ・タイプが数値である場合、値の文字列書式バージョンがこの列に格納されます。同様に、プロパティがタイムスタンプ・ベースである場合、値の文字列書式バージョンが格納されます。

  • VN: 数値プロパティの値を示す数値列。この列には、プロパティ・タイプが数値である場合のみ、プロパティ値が格納されます。

  • VT: 日時プロパティの値を格納するタイムゾーン列のあるタイムスタンプ。この列には、プロパティ・タイプがタイムスタンプ・ベースである場合のみ、プロパティ値が格納されます。

  • SL: Oracle Label Securityを使用してセキュリティ・ラベル・セット用に予約された数値列(セキュリティ・ラベルの使用の詳細は、プロパティ・グラフ・データのアクセス制御(グラフレベルおよびOLS)を参照)。

  • VTS: 今後の拡張用として予約されているタイムゾーン列のタイムスタンプ。

  • VTE: 今後の拡張用として予約されているタイムゾーン列のタイムスタンプ。

  • FE: 今後の拡張用として予約されている文字列列。

次の例では、CONNECTIONSVT$という名前の表に行を挿入します。これには、(様々なデータ型を表す) 1から10のT列値が含まれます。

INSERT INTO connectionsvt$(vid,k,t,v,vn,vt) VALUES (2001, '1-STRING', 1, 'Some String', NULL, NULL); 
INSERT INTO connectionsvt$(vid,k,t,v,vn,vt) VALUES (2001, '2-INTEGER', 2, NULL, 21, NULL); 
INSERT INTO connectionsvt$(vid,k,t,v,vn,vt) VALUES (2001, '3-FLOAT', 3, NULL, 21.5, NULL); 
INSERT INTO connectionsvt$(vid,k,t,v,vn,vt) VALUES (2001, '4-DOUBLE', 4, NULL, 21.5, NULL); 
INSERT INTO connectionsvt$(vid,k,t,v,vn,vt) VALUES (2001, '5-DATE', 5, NULL, NULL, timestamp'2018-07-20 15:32:53.991000'); 
INSERT INTO connectionsvt$(vid,k,t,v,vn,vt) VALUES (2001, '6-BOOLEAN', 6, 'Y', NULL, NULL); 
INSERT INTO connectionsvt$(vid,k,t,v,vn,vt) VALUES (2001, '7-LONG', 7, NULL, 42, NULL); 
INSERT INTO connectionsvt$(vid,k,t,v,vn,vt) VALUES (2001, '8-SHORT', 8, NULL, 10, NULL); 
INSERT INTO connectionsvt$(vid,k,t,v,vn,vt) VALUES (2001, '9-BYTE', 9, NULL, 10, NULL); 
INSERT INTO connectionsvt$(vid,k,t,v,vn,vt) VALUES (2001, '10-CHAR', 10, 'A', NULL, NULL); 
...
UPDATE connectionsVT$ SET V = coalesce(v,to_nchar(vn),to_nchar(vt)) WHERE vid=2001; 
COMMIT;

エッジを格納するためのGE$表スキーマには、次の列があります。

  • EID: エッジのIDを示す長い列。

  • SVID: 出力(元の)頂点のIDを示す長い列。

  • DVID: 入力(宛先)頂点のIDを示す長い列。

  • EL: エッジのラベルを表す文字列列。

  • K: プロパティの名前を示す文字列の列。頂点に関連付けられているプロパティがない場合、この列の値は空白にする必要があります。

  • T: プロパティのタイプを示す長い列。

  • V: プロパティの値を文字列として示す文字列の列。プロパティ・タイプが数値である場合、値の文字列書式バージョンがこの列に格納されます。同様に、プロパティがタイムスタンプ・ベースである場合、値の文字列書式バージョンが格納されます。

  • VN: 数値プロパティの値を示す数値列。この列には、プロパティ・タイプが数値である場合のみ、プロパティ値が格納されます。

  • VT: 日時プロパティの値を格納するタイムゾーン列のあるタイムスタンプ。この列には、プロパティ・タイプがタイムスタンプ・ベースである場合のみ、プロパティ値が格納されます。

  • SL: Oracle Label Securityを使用してセキュリティ・ラベル・セット用に予約された数値列(セキュリティ・ラベルの使用の詳細は、プロパティ・グラフ・データのアクセス制御(グラフレベルおよびOLS)を参照)。

  • VTS: 今後の拡張用として予約されているタイムゾーン列のタイムスタンプ。

  • VTE: 今後の拡張用として予約されているタイムゾーン列のタイムスタンプ。

  • FE: 今後の拡張用として予約されている文字列列。

VT$およびGE$表に加えて、Oracle Spatial and Graphはその他の内部表も保持します。

GT$接尾辞を使用して定義された内部グラフ・スケルトン表は、グラフのトポロジ構造を格納するために使用され、次の列を含んでいます。

  • EID: エッジのIDを示す長い列。

  • EL: エッジのラベルを表す文字列列。

  • SVID: 出力(元の)頂点のIDを示す長い列。

  • DVID: 入力(宛先)頂点のIDを示す長い列。

  • ELH: エッジ・ラベルのハッシュ値を指定する未加工の列。

  • ELS: 合計文字数を基準にしてエッジ・ラベル・サイズを指定する整数列。

IT$接尾辞を使用して作成された内部テキスト索引メタデータ表は、Oracle Text検索エンジンを使用して作成されたテキスト索引に関するメタデータ情報の格納に使用されます。作成されたテキスト索引に基づいて自動的に入力されます。IT$表には、テキスト索引に関する一般情報を示す次の列があります。

  • EIN: テキスト索引の名前を示す文字列列。

  • ET: テキスト索引の構築に使用されたエンティティを示す数値列(頂点(1)またはエッジ(2)テキスト索引である場合)。

  • IT: テキスト索引のタイプを示す数値列(自動(1)または手動(2)テキスト索引である場合)。

  • SE: エンティティ・プロパティの索引付けに使用される検索エンジンを示す数値列(2はOracle Textを示します)。

  • K: テキスト索引付けに使用されるプロパティ名を示す文字列列。

Oracle Textベースの索引では、次の列を使用してテキスト索引の構成を記述します(Oracle Textベースの索引の作成の詳細は、Oracle Textを使用したテキスト索引の構成を参照してください)。

  • PO: テキスト索引構成設定の優先所有者を示す列。デフォルトでは、パッケージ所有者はMDSYSに設定されます。

  • DS: テキスト索引の構築に使用されるデータ・ストアを指定する文字列列。

  • FIL: テキスト索引の構築に使用されるフィルタを指定する文字列列。

  • STR: テキスト索引の構築に使用されるストレージ・プロパティを指定する文字列列。

  • WL: テキスト索引の作成時に使用されるワード・リストを指定する文字列列。

  • SL: テキスト索引の構築に使用されるストップ・リストを指定する文字列列。

  • LXR: テキストの索引付け中にOracle Textが使用するレクサーを指定する文字列列。

  • OPTS: 追加の構成オプションを指定する文字列列。

Oracleの内部専用として、SS$接尾辞を使用して定義された内部表が作成されます。

2.3.2 頂点(VT$)およびエッジ(GE$)表のデフォルトの索引

問合せのパフォーマンスのために、プロパティ・グラフの表にいくつかの索引がデフォルトで作成されます。索引名は、グラフ名を接頭辞に使うなど、表名と同じ表記規則に従います。たとえば、プロパティ・グラフmyGraphの場合、次の(パーティション化された)ローカル索引が作成されます。

  • 一意の索引myGraphXQV$myGraphVT$(VID, K)

  • 一意の索引myGraphXQE$myGraphGE$(EID, K)

  • 索引myGraphXSE$myGraphGE$(SVID, DVID, EID, VN)

  • 索引myGraphXDE$myGraphGE$(DVID, SVID, EID, VN)

2.3.3 プロパティ・グラフ・スキーマの柔軟性

プロパティ・グラフ・スキーマの設計では、あらゆる種類のカタログや集中管理されたリポジトリは使用しません。各プロパティ・グラフは個別に格納され、ユーザーが選択したスキーマにより管理されます。ユーザーのスキーマは1つ以上のプロパティ・グラフを含むことができます。

この設計によりユーザーに大幅な柔軟性がもたらされます。次に例を示します。

  • ユーザーは必要に応じて追加の索引を作成できます。

  • 異なるプロパティ・グラフは基本表に対し異なる索引のセットまたは圧縮オプションを持つことができます。

  • 異なるプロパティ・グラフは異なる数のハッシュ・パーティションを持つことができます。

  • プロパティ・グラフのXSE$またはXDE$索引を削除することはできますが、整合性のために、一意の制約は保持する必要があります。

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

次のステップに従い、プロパティ・グラフを開始します。

  1. プロパティ・グラフを初めて使用する際、ソフトウェアがインストールされ、稼働可能であることを確認します。
  2. 次の1つ以上のオプションを使用してグラフとやり取りします。
    • JavaアプリケーションでJava APIを使用します。Java APIは、プロトタイプおよびデモ目的でJShellコマンドライン・インタフェースで実行することもできます。
    • 次の場所で、PGQL問合せを実行します。
      • Javaアプリケーション、または
      • グラフ・ビジュアライゼーション・インタフェース、または
      • SQLclクライアント
    • PGQL問合せを実行し、Apache ZeppelinインタプリタでJava APIを実行します

2.4.1 データベース・ユーザーに必要な権限

グラフ表(プロパティ・グラフ・スキーマ・オブジェクトまたはグラフとしてメモリーに直接ロードされるリレーショナル表のいずれか)を含むデータベース・スキーマには、一定の権限が必要です。

ALTER SESSION
CREATE PROCEDURE
CREATE SEQUENCE
CREATE SESSION
CREATE TABLE
CREATE TRIGGER
CREATE TYPE
CREATE VIEW

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

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

2.5.1 Java APIの概要

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

2.5.1.1 Oracle Graphプロパティ・グラフJava API

Oracle Graphプロパティ・グラフのサポートにより、Oracle Database用のデータベース固有のAPIが提供されます。

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

import oracle.pg.common.*;
import oracle.pg.text.*;
import oracle.pg.rdbms.*;
import oracle.pgx.config.*;
import oracle.pgx.common.types.*;
2.5.1.2 Oracle Databaseプロパティ・グラフJava API

Oracle Databaseプロパティ・グラフJava APIにより、Oracle Databaseに格納されたプロパティ・グラフを作成および移入できます。

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

import oracle.pg.rdbms.*; 
import java.sql.*;

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

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

Oracle Spatial and Graphはグラフ・データのOracle Databaseへのロードをサポートします。グラフ・データは次の方法を使用してプロパティ・グラフにロードされます。

  • 頂点およびエッジは、graph.addVertex(Object id)/graph.addEdge(Object id) APIを使用して、増分を追加できます。

  • グラフ・データは、OraclePropertyGraphDataLoader APIを使用して、Oracleフラット・ファイル形式のファイルからパラレルにロードできます。

  • GraphML、GMLまたはGraphSONのプロパティ・グラフは、GMLReaderGraphMLReaderおよびGraphSONReaderをそれぞれ使用してロードできます。

このトピックでは、Oracle定義のフラット・ファイル形式でのプロパティ・グラフのパラレル・ロードに焦点を当てています。

パラレル・データ・ロードは、頂点(またはエッジ)入力ストリームが複数のチャンクに分割され、Oracle Databaseにパラレルにロードされる場合の、データのロードへの最適化されたソリューションを提供します。この操作には、2つの主なオーバーラップ・フェーズが含まれます。

  • 分割。頂点およびエッジ入力ストリームが複数のチャンクに分割され、一時入力ストリームに保存されます。チャックの数は指定した並列度によって決定されます

  • グラフのロード。各チャンクに対し、頂点(またはエッジ)に関する情報を処理し、データをプロパティ・グラフ表にロードするために、ローダー・スレッドが作成されます。

OraclePropertyGraphDataLoaderはいくつかの異なるオプションを使用してパラレル・データ・ロードをサポートします。

2.5.2.1 JDBCベースのデータのロード

JDBCベースのデータのロードでは、Java Database Connectivity (JDBC) APIを使用して、グラフ・データをOracle Databaseにロードします。このオプションでは、指定した入力ストリームの頂点(またはエッジ)は、スプリッタ・スレッドにより複数のチャンクの間に広がります。各チャンクは、JDBCバッチを使用して、チャンク内のすべての要素を一時作業表に挿入する、異なるローダー・スレッドにより処理されます。使用されるスプリッタおよびローダー・スレッドの数は、ユーザーが指定した並列度(DOP)によって決定されます。

すべてのグラフ・データが一時作業表にロードされた後、一時作業表に格納されたすべてのデータはプロパティ・グラフVT$およびGE$表にロードされます。

次の例は、並列度48で、JDBCベースのパラレル・データ・ロードを使用し、グラフ・データをOracle定義のフラット・ファイル形式の頂点およびエッジ・ファイルからロードします。

    String szOPVFile = "../../data/connections.opv"; 
    String szOPEFile = "../../data/connections.ope"; 
    OraclePropertyGraph opg = OraclePropertyGraph.getInstance( args, szGraphName); 
    opgdl = OraclePropertyGraphDataLoader.getInstance(); 
    opgdl.loadData(opg, szOPVFile, szOPEFile, 48 /* DOP */, 1000 /* batch size */, true /* rebuild index flag */, "pddl=t,pdml=t" /* options */); 
);

データのロード操作のパフォーマンスを最適化するために、JDBCベースのデータのロードを呼び出すときに、フラグやヒントのセットを指定できます。これらのヒントとしては次のものがあります。

  • DOP: データのロード時に使用する並列度。このパラメータは、データをプロパティ・グラフVT$およびGE$表にロードするときに使用するローダー・スレッドの数と同様に、ファイルの分割時に生成するチャンクの数を決定します。

  • バッチ・サイズ:バッチ・モードでOracleのupdate文で使用するバッチ・サイズを指定する整数。JDBCベースのデータのロードに使用されるデフォルトのバッチ・サイズは1000です。

  • 索引の再作成: このフラグがtrueに設定されている場合、データ・ローダーは、データがロードされるプロパティ・グラフで定義されたすべての索引および制約を無効にします。すべてのデータがプロパティ・グラフにロードされた後、すべての索引および制約は再作成されます。

  • ロード・オプション: データのロード操作を最適化するための1つのオプション(またはカンマで区切った複数のオプション)。これらのオプションとしては次のものがあります。

    • NO_DUP=T: 入力データに無効な重複がないことを前提にしています。有効なプロパティ・グラフでは、各頂点(エッジ)は指定したプロパティ・キーに対し最大で1つの値を持つことができます。無効なプロパティ・グラフでは、各頂点(エッジ)は特定のキーに対し2つ以上の値を持つことがあります。例として、頂点vには2つのキー/値ペア、name/"John"およびname/"Johnny"があり、同じキーを共有しています。

    • PDML=T: データ・ローダーで使用されるデータベース・セッションでのDML操作のパラレル実行を有効にします。このヒントは、長時間実行するバッチ・ジョブのパフォーマンスを向上するのに使用されます。

    • PDDL=T: データ・ローダーで使用されるデータベース・セッションでのDDL操作のパラレル実行を有効にします。このヒントは、長時間実行するバッチ・ジョブのパフォーマンスを向上するのに使用されます。

    • KEEP_WORK_TABS=T: データのロードが完了した後の作業表のクリーニングおよび削除をスキップします。これはデバッグでの使用専用です。

    • KEEP_TMP_FILES=T: データのロードが完了した後の一時スプリッタ・ファイルの削除をスキップします。これはデバッグ専用です。

  • スプリッタ・フラグ: 分割フェーズで使用されるファイルまたはストリームのタイプを定義し、グラフのロード・フェーズで使用されるデータ・チャンクを生成する整数値です。一時ファイルは通常のファイル(0)、名前付きパイプ(1)、またはパイプされたストリーム(2)として作成できます。デフォルトでは、JDBCベースのデータのロードでは、次のものが使用されます

    中間データ・チャンクを処理するためのパイプされたストリーム。パイプされたストリームはJDBCベースのローダー専用です。これは完全にインメモリーで効率的であり、オペレーティング・システムにファイルを作成する必要がありません。

    名前付きパイプはローカルのオペレーティング・システムで空のファイルのように見えるのに対し、通常のファイルはローカルのオペレーティング・システムの領域を消費します。すべてのオペレーティング・システムが名前付きパイプをサポートするわけではないことに注意してください。

  • 分割ファイルの接頭辞: 分割フェーズがグラフのロード用のデータ・チャンクを生成しているときに、作成される一時ファイルまたはパイプに使用される接頭辞です。デフォルトで、接頭辞“OPG_Chunk”は通常のファイルに使用され、“OPG_Pipe”は名前付きパイプに使用されます。

  • 表領域: すべての一時作業表が作成される表領域の名前です。

サブトピック:

  • 複数のファイルを伴うJDBCベースのデータのロード

  • パーティションを伴うJDBCベースのデータのロード

  • ファインチューニングを使用したJDBCベースのパラレル・データ・ロード

複数のファイルを伴うJDBCベースのデータのロード

JDBCベースのデータのロードは、複数ファイルからの頂点およびエッジ、またはデータベースへの入力ストリームのロードもサポートします。次のコード・フラグメントは、パラレル・データ・ロードAPIを使用し、複数の頂点およびエッジ・ファイルをロードします。この例では、2つの文字列配列szOPVFilesおよびszOPEFilesが入力ファイルの保持に使用されます。

    String[] szOPVFiles = new String[] {"../../data/connections-p1.opv", 
                                        "../../data/connections-p2.opv"}; 
    String[] szOPEFiles = new String[] {"../../data/connections-p1.ope",                          
                                        "../../data/connections-p2.ope"}; 
    OraclePropertyGraph opg = OraclePropertyGraph.getInstance( args, szGraphName); 
    opgdl = OraclePropertyGraphDataLoader.getInstance(); 
    opgdl.loadData(opg, szOPVFiles, szOPEFiles, 48 /* DOP */,
                   1000 /* batch size */, 
                   true /* rebuild index flag */, 
                   "pddl=t,pdml=t" /* options */); 

パーティションを伴うJDBCベースのデータのロード

数千から数十万の要素からのグラフ・データの処理中に、JDBCベースのデータのロードAPIにより、論理パーティション化を使用して、Oracleフラット・ファイル形式のグラフ・データをOracle Databaseにロードできます。

各パーティションは、グラフ・データ・ファイルの頂点(またはエッジ)のサブセットを表します。ファイルのサイズはほぼ、パーティションの数で分割されたファイル内の異なる要素IDの数です。各パーティションは[0, Number of partitions – 1]の範囲の、整数IDで識別されます。

パーティションでパラレル・データ・ロードを使用するには、使用する論理パーティションの合計数と、パーティション・オフセット(開始ID)を、loadData APIで使用される基本パラメータに加えて、指定する必要があります。グラフ・データ・ファイルまたは入力ストリームをデータベースに完全にロードするには、定義したパーティションの数だけ、データ・ロード操作を実行する必要があります。たとえば、2つのパーティションを使用してファイルからグラフ・データをロードするには、オフセット0および1を使用した2つのデータ・ロードAPIコールが必要です。データ・ローダーへの各コールは複数のスレッド、または1つのシステムまたは複数のシステムでの別個のJavaクライアントを使用して処理できます。

この方法は、1つの頂点ファイル(または入力ストリーム)および1つのエッジ・ファイル(または入力ストリーム)で使用されることを意図したものであることに注意してください。さらに、このオプションでは頂点およびエッジでの索引および制約を無効にすることが必要です。これらの索引および制約は、すべてのパーティションがロードされた後で再作成される必要があります。

次の例は、2つのパーティションを使用してグラフ・データをロードします。各パーティションは1つのJavaプロセスDataLoaderWorkerによってロードされます。複数のワーカーを調整するために、DataLoaderCoordinatorという名前のコーディネータ・プロセスが使用されます。この例では、次の操作を行います

  1. すべての索引および制約を無効にし、

  2. 一時作業表loaderProgressを作成します。これはデータのロード・プロセス(つまり、何人のワーカーが作業を終了したか)を記録するものです。作業表が作成されると、すべてのDataLoaderWorkerプロセスがデータのロードを開始します。

  3. 1ずつプロセスを増分します。

  4. すべてのDataLoaderWorkerプロセスが実行されるまで、プロセスのポーリングを継続します(DataLoaderCoordinatorプロセスを使用して)。

  5. すべての索引および制約を再作成します。

ノート: DataLoaderWorkerでは、フラグSKIP_INDEXtrueに、フラグrebuildIndxfalseに設定される必要があります。

// start DataLoaderCoordinator, set dop = 8 and number of partitions = 2
java DataLoaderCoordinator  jdbcUrl  user password pg 8 2
// start the first DataLoaderWorker, set dop = 8, number of partitions = 2, partition offset = 0
java DataLoaderWorker jdbcUrl user password pg  8 2 0
// start the first DataLoaderWorker, set dop = 8, number of partitions = 2, partition offset = 1
java DataLoaderWorker jdbcUrl user password pg  8 2 1

DataLoaderCoordinatorが最初にすべての索引および制約を無効にします。次に、loaderProgressという名前の表を作成し、列progress = 0の1行を挿入します。

public class DataLoaderCoordinator {
        public static void main(String[] szArgs) {
          String jdbcUrl = szArgs[0];
          String user = szArgs[1];
          String password = szArgs[2];
          String graphName = szArgs[3];
          int dop = Integer.parseInt(szArgs[4]);
          int numLoaders = Integer.parseInt(szArgs[5]);

          Oracle oracle = null;
          OraclePropertyGraph opg = null;
          try {
            oracle = new Oracle(jdbcUrl, user, password);
            OraclePropertyGraphUtils.dropPropertyGraph(oracle, graphName);
            opg = OraclePropertyGraph.getInstance(oracle, graphName);

            List<String> vIndices = opg.disableVertexTableIndices();
            List<String> vConstraints = opg.disableVertexTableConstraints();
            List<String> eIndices = opg.disableEdgeTableIndices();
            List<String> eConstraints = opg.disableEdgeTableConstraints();

            String szStmt = null;
            try {
              szStmt = "drop table loaderProgress";
              opg.getOracle().executeUpdate(szStmt);
            }
            catch (SQLException ex) {
              if (ex.getErrorCode() == 942) {
                // table does not exist. ignore
              }
              else {
                throw new OraclePropertyGraphException(ex);
              }
            }

            szStmt = "create table loaderProgress (progress integer)";
            opg.getOracle().executeUpdate(szStmt);
            szStmt = "insert into loaderProgress (progress) values (0)";
            opg.getOracle().executeUpdate(szStmt);
            opg.getOracle().getConnection().commit();
            while (true) {
              if (checkLoaderProgress(oracle) == numLoaders) {
                break;
              } else {
                Thread.sleep(1000);
              }
            }

            opg.rebuildVertexTableIndices(vIndices, dop, null);
            opg.rebuildVertexTableConstraints(vConstraints, dop, null);
            opg.rebuildEdgeTableIndices(eIndices, dop, null);
            opg.rebuildEdgeTableConstraints(eConstraints, dop, null);
          }
          catch (IOException ex) {
            throw new OraclePropertyGraphException(ex);
          }
          catch (SQLException ex) {
            throw new OraclePropertyGraphException(ex);
          }
          catch (InterruptedException ex) {
            throw new OraclePropertyGraphException(ex);
          }
          catch (Exception ex) {
            throw new OraclePropertyGraphException(ex);
          }
          finally {
            try {
              if (opg != null) {
                opg.shutdown();
              }
              if (oracle != null) {
                oracle.dispose();
              }
            }
            catch (Throwable t) {
              System.out.println(t);
            }
          }

        }

        private static int checkLoaderProgress(Oracle oracle) {
          int result = 0;
          ResultSet rs = null;

          try {
            String szStmt = "select progress from loaderProgress";
            rs = oracle.executeQuery(szStmt);
            if (rs.next()) {
              result =  rs.getInt(1);
            }

          }
          catch (Exception ex) {
            throw new OraclePropertyGraphException(ex);
          }
          finally {
            try {
              if (rs != null) {
                rs.close();
              }
	    }
            catch (Throwable t) {
              System.out.println(t);
            }
          }
          return result;
        }
}
     
public class DataLoaderWorker {

        public static void main(String[] szArgs) {
          String jdbcUrl = szArgs[0];
          String user = szArgs[1];
          String password = szArgs[2];
          String graphName = szArgs[3];
          int dop = Integer.parseInt(szArgs[4]);
          int numLoaders = Integer.parseInt(szArgs[5]);
          int offset = Integer.parseInt(szArgs[6]);

          Oracle oracle = null;
          OraclePropertyGraph opg = null;

          try {
            oracle = new Oracle(jdbcUrl, user, password);
            opg = OraclePropertyGraph.getInstance(oracle, graphName, 8, dop, null/*tbs*/, ",SKIP_INDEX=T,");
            OraclePropertyGraphDataLoader opgdal = OraclePropertyGraphDataLoader.getInstance();

            while (true) {
              if (checkLoaderProgress(oracle) == 1) {
                break;
              } else {
                Thread.sleep(1000);
              }
            }

            String opvFile = "../../../data/connections.opv";
            String opeFile = "../../../data/connections.ope";
            opgdal.loadData(opg, opvFile, opeFile, dop, numLoaders, offset, 1000, false, null, "pddl=t,pdml=t");

            updateLoaderProgress(oracle);
          }
          catch (SQLException ex) {
            throw new OraclePropertyGraphException(ex);
          }
          catch (InterruptedException ex) {
            throw new OraclePropertyGraphException(ex);
          }
          finally {
            try {
              if (opg != null) {
                opg.shutdown();
              }
              if (oracle != null) {
                oracle.dispose();
              }
            }
            catch (Throwable t) {
              System.out.println(t);
            }
          }
        }

        private static int checkLoaderProgress(Oracle oracle) {
          int result = 0;
          ResultSet rs = null;

          try {
            String szStmt = "select count(*) from loaderProgress";
            rs = oracle.executeQuery(szStmt);
            if (rs.next()) {
              result = rs.getInt(1);
            }
          }
          catch (SQLException ex) {
            if (ex.getErrorCode() == 942) {
              // table does not exist. ignore
            } else {
              throw new OraclePropertyGraphException(ex);
            }
          }
          finally {
            try {
              if (rs != null) {
                rs.close();
              }
            }
            catch (Throwable t) {
              System.out.println(t);
            }
          }
          return result;
        }

        private static void updateLoaderProgress(Oracle oracle) {
          ResultSet rs = null;

          try {
            String szStmt = "update loaderProgress set progress = progress + 1";
            oracle.executeUpdate(szStmt);
            oracle.getConnection().commit();
          }
          catch (Exception ex) {
            throw new OraclePropertyGraphException(ex);
          }
          finally {
            try {
              if (rs != null) {
                rs.close();
              }
            }
            catch (Throwable t) {
              System.out.println(t);
            }
          }
        }
}

ファインチューニングを使用したJDBCベースのパラレル・データ・ロード

JDBCベースのデータ・ロードは、要素をプロパティ・グラフ・インスタンスへロードするときに使用されるIDオフセットと同様に、ロードされる行からのデータのサブセットのファインチューニングをサポートします。ファイルから読み取る行の最大数と、頂点およびエッジの両方のオフセット行番号(開始位置)を指定して、ファイルからロードするデータのサブセットを指定できます。この方法では、行の最大数が読み取られるまで、データはオフセット行番号からロードされます。最大行数が-1の場合、ロード・プロセスはファイルの終わりまでデータをスキャンします。

複数のグラフ・データ・ファイルにはいくつかのID衝突または重複が含まれることがあるので、JDBCベースのデータ・ロードでは、頂点およびエッジのIDオフセットを定義できます。この方法では、ロードされた各頂点のIDは、元の頂点IDおよび指定した頂点IDのオフセットの合計になります。同様に、ロードされた各エッジのIDは、元のエッジIDおよび指定したエッジIDのオフセットの合計から生成されます。頂点およびエッジ・ファイルは相関関係がある必要があります。ロードされたエッジに対する入出力頂点IDは指定した頂点IDオフセットに対して変更されるからです。この操作は、1つの論理パーティションを使用したデータのロードでのみサポートされます。

次のコード・フラグメントは、指定したグラフ・データ・ファイルから最初の100個の頂点およびエッジ行をロードします。この例では、IDオフセット0が使用され、これはID調整が行われないことを示します。

    String szOPVFile = "../../data/connections.opv"; 
    String szOPEFile = "../../data/connections.ope"; 
    // Run the data loading using fine tuning 
    long lVertexOffsetlines = 0; 
    long lEdgeOffsetlines = 0; 
    long lVertexMaxlines = 100; 
    long lEdgeMaxlines = 100;
    long lVIDOffset = 0;
    long lEIDOffset = 0;
    OraclePropertyGraph opg = OraclePropertyGraph.getInstance( args, szGraphName); 
    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 /* maximum number of lines to start loading from 
                       partition, default -1 (all lines in partition) */, 
      lVIDOffset /* vertex ID offset: the vertex ID will be original 
                    vertex ID + offset, default 0 */, 
      lEIDOffset /* edge ID offset: the edge ID will be original edge ID 
                    + offset, default 0 */, 
      4 /* DOP */, 
      1 /* Total number of partitions, default 1 */, 
      0 /* Partition to load: from 0 to totalPartitions - 1, default 0 */, 
      OraclePropertyGraphDataLoader.PIPEDSTREAM /* splitter flag */, 
      "chunkPrefix" /* prefix: the prefix used to generate split chunks 
                       for regular files or named pipes */, 
      1000 /* batch size: batch size of Oracle update in batching mode. 
              Default value is 1000 */, 
      true /* rebuild index */, 
      null /* table space name*/,
      "pddl=t,pdml=t" /* options: enable parallel DDL and DML */);
2.5.2.2 外部表ベースのデータのロード

外部表ベースのデータのロードでは、グラフ・データをOracle Databaseにロードするのに、外部表を使用します。外部表のロードにより、データベース内の通常のリレーショナル表にあるかのように、ユーザーは外部ソースのデータにアクセスできます。この場合、指定した入力ストリームの頂点(またはエッジ)は、スプリッタ・スレッドにより複数のチャンクの間に広がります。各チャンクは、チャンク内のすべての要素をOracle Databaseに渡す役割を持つ、異なるローダー・スレッドにより処理されます。使用されるスプリッタおよびローダー・スレッドの数は、ユーザーが指定した並列度(DOP)によって決定されます。

外部表がデータ・ロード・ロジックにより自動的に作成された後、ローダーは外部表から読み取り、すべてのデータをプロパティ・グラフ・スキーマ表(VT$およびGE$)表にロードします。

外部表ベースのデータのロードには、外部表により読み出されるファイルが格納されるディレクトリ・オブジェクトが必要です。このディレクトリは、SQL*Plus環境で次のスクリプトを実行して作成できます。

create or replace directory tmp_dir as '/tmppath/';
grant read, write on directory tmp_dir to public;

次のコード・フラグメントは、並列度が48で、外部表ベースのパラレル・データ・ロードを使用し、グラフ・データをOracleフラット・ファイル形式の頂点およびエッジ・ファイルからロードします。

    String szOPVFile = "../../data/connections.opv"; 
    String szOPEFile = "../../data/connections.ope"; 
    String szExtDir = "tmp_dir";
    OraclePropertyGraph opg = OraclePropertyGraph.getInstance( args, szGraphName); 
    opgdl = OraclePropertyGraphDataLoader.getInstance(); 
    opgdl.loadDataWithExtTab(opg, szOPVFile, szOPEFile, 48 /*DOP*/, 
                             true /*named pipe flag: setting the flag to true will use 
                                   named pipe based splitting; otherwise, regular file 
                                   based splitting would be used*/, 
                             szExtDir /* database directory object */, 
                             true /*rebuild index */, 
                             "pddl=t,pdml=t,NO_DUP=T" /*options */);

データのロード操作のパフォーマンスを最適化するために、外部表ベースのデータのロードを呼び出すときに、フラグやヒントのセットを指定できます。これらのヒントとしては次のものがあります。

  • DOP: データのロード時に使用する並列度。このパラメータは、データをプロパティ・グラフVT$およびGE$表にロードするときに使用するローダー・スレッドの数と同様に、ファイルの分割時に生成するチャンクの数を決定します。

  • 索引の再作成: このフラグがtrueに設定されている場合、データ・ローダーは、データがロードされるプロパティ・グラフで定義されたすべての索引および制約を無効にします。すべてのデータがプロパティ・グラフにロードされた後、すべての索引および制約は再作成されます。

  • ロード・オプション: データのロード操作を最適化するための1つのオプション(またはカンマで区切った複数のオプション)。これらのオプションとしては次のものがあります。

    • NO_DUP=T: 重複キー/値ペアに対する検証が実行されないため、データをプロパティ・グラフ表にロードするのにより速い方法を選択します。

    • PDML=T: データ・ローダーで使用されるデータベース・セッションでのDML操作のパラレル実行を有効にします。このヒントは、長時間実行するバッチ・ジョブのパフォーマンスを向上するのに使用されます。

    • PDDL=T: データ・ローダーで使用されるデータベース・セッションでのDDL操作のパラレル実行を有効にします。このヒントは、長時間実行するバッチ・ジョブのパフォーマンスを向上するのに使用されます。

    • KEEP_WORK_TABS=T: データのロードが完了した後の作業表のクリーニングおよび削除をスキップします。これはデバッグでの使用専用です。

    • KEEP_TMP_FILES=T: データのロードが完了した後の一時スプリッタ・ファイルの削除をスキップします。これはデバッグでの使用専用です。

  • スプリッタ・フラグ: 分割フェーズで使用されるファイルまたはストリームのタイプを定義し、グラフのロード・フェーズで使用されるデータ・チャンクを生成する整数値です。一時ファイルは通常のファイル(0)または名前付きパイプ(1)として作成できます。

    デフォルトで、外部表ベースのデータのロードでは、通常のファイルを使用して、データ・チャンク用の一時ファイルを処理します。名前付きパイプはそれをサポートするオペレーティング・システムでのみ使用できます。一般的に、通常のファイルをDBFSと一緒に使用するのはよい方法です。

  • 分割ファイルの接頭辞: 分割フェーズがグラフのロード用のデータ・チャンクを生成しているときに、作成される一時ファイルまたはパイプに使用される接頭辞です。デフォルトで、接頭辞“Chunk”は通常のファイルに使用され、“Pipe”は名前付きパイプに使用されます。

  • 表領域: すべての一時作業表が作成される表領域の名前です。

JDBCベースのデータのロードと同様に、外部表ベースのデータのロードは、1つのファイル、複数のファイル、パーティション、およびファインチューニングを使用して、パラレル・データ・ロードをサポートします。

サブトピック:

  • 複数のファイルを使用した外部表ベースのデータのロード

  • パーティションを使用した外部表ベースのデータのロード

  • ファインチューニングを使用した外部表ベースのパラレル・データ・ロード

複数のファイルを使用した外部表ベースのデータのロード

外部表ベースのデータのロードは、複数ファイルからの頂点およびエッジ、またはデータベースへの入力ストリームのロードもサポートします。次のコード・フラグメントは、パラレル・データ・ロードAPIを使用し、複数の頂点およびエッジ・ファイルをロードします。この例では、2つの文字列配列szOPVFilesおよびszOPEFilesが入力ファイルの保持に使用されます。

    String szOPVFile = "../../data/connections.opv"; 
    String szOPEFile = "../../data/connections.ope"; 
    String szExtDir = "tmp_dir";
    OraclePropertyGraph opg = OraclePropertyGraph.getInstance( args, szGraphName); 
    opgdl = OraclePropertyGraphDataLoader.getInstance(); 
    opgdl.loadDataWithExtTab(opg, szOPVFile, szOPEFile, 48 /* DOP */, 
                             true /* named pipe flag */, 
                             szExtDir /* database directory object */, 
                             true /* rebuild index flag */, 
                             "pddl=t,pdml=t" /* options */);

パーティションを使用した外部表ベースのデータのロード

非常に大きいプロパティ・グラフの処理中に、外部表ベースのデータのロードAPIにより、論理パーティション化を使用して、Oracleフラット・ファイル形式のグラフ・データをOracle Databaseにロードできます。各パーティションは、グラフ・データ・ファイルの頂点(またはエッジ)のサブセットを表します。ファイルのサイズはほぼ、パーティションの数で分割されたファイル内の異なる要素IDの数です。各パーティションは[0, Number of partitions – 1]の範囲の、整数IDで識別されます。

パーティションでパラレル・データ・ロードを使用するには、使用するパーティションの合計数と、パーティション・オフセットを、loadDataWithExtTab APIで使用される基本パラメータに加えて、指定する必要があります。グラフ・データ・ファイルまたは入力ストリームをデータベースに完全にロードするには、定義したパーティションの数だけ、データ・ロード操作を実行する必要があります。たとえば、2つのパーティションを使用してファイルからグラフ・データをロードするには、オフセット0および1を使用した2つのデータ・ロードAPIコールが必要です。データ・ローダーへの各コールは複数のスレッド、または1つのシステムまたは複数のシステムでの別個のJavaクライアントを使用して処理できます。

この方法は、1つの頂点ファイル(または入力ストリーム)および1つのエッジ・ファイル(または入力ストリーム)で使用されることを意図したものであることに注意してください。さらに、このオプションでは頂点およびエッジでの索引および制約を無効にすることが必要です。これらの索引および制約は、すべてのパーティションがロードされた後で再作成される必要があります。

パーティションを使用したJDBCベースのデータのロードの例は、パーティションを使用した外部表ベースのロードとして動作するように、容易に移行できます。必要な変更は、API loadData()loadDataWithExtTab()で置き換え、データベース・ディレクトリ・オブジェクトなどの追加の入力パラメータを指定するだけです。

ファインチューニングを使用した外部表ベースのパラレル・データ・ロード

外部表ベースのデータのロードも、要素をプロパティ・グラフ・インスタンスへロードするときに使用されるIDオフセットと同様に、ロードされる行からのデータのサブセットのファインチューニングをサポートします。ファイルから読み取る行の最大数と、頂点およびエッジの両方のオフセット行番号を指定して、ファイルからロードするデータのサブセットを指定できます。この方法では、行の最大数が読み取られるまで、データはオフセット行番号からロードされます。最大行数が-1の場合、ロード・プロセスはファイルの終わりまでデータをスキャンします。

グラフ・データ・ファイルにはいくつかのID衝突が含まれることがあるので、外部表ベースのデータのロードでは、頂点およびエッジのIDオフセットを定義できます。この方法では、ロードされた各頂点のIDは、元の頂点IDおよび指定した頂点IDのオフセットの合計から取得されます。同様に、ロードされた各エッジのIDは、元のエッジIDおよび指定したエッジIDのオフセットの合計から生成されます。頂点およびエッジ・ファイルは相関関係がある必要があります。ロードされたエッジに対する入出力頂点IDは指定した頂点IDオフセットに対して変更されるからです。この操作は、1つのパーティションを使用したデータのロードでのみサポートされます。

次のコード・フラグメントは、指定したグラフ・データ・ファイルから最初の100個の頂点およびエッジをロードします。この例では、IDオフセットは指定しません。

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

    // Run the data loading using fine tuning 
    long lVertexOffsetlines = 0; 
    long lEdgeOffsetlines = 0; 
    long lVertexMaxlines = 100; 
    long lEdgeMaxlines = 100;
    long lVIDOffset = 0;
    long lEIDOffset = 0;
    String szExtDir = "tmp_dir";

    OraclePropertyGraph opg = OraclePropertyGraph.getInstance( args, szGraphName); 
    OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
    
    opgdl.loadDataWithExtTab(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 /* maximum number of lines to start loading 
                                              from partition, default -1 (all lines in 
                                              partition) */, 
                             lVIDOffset /* vertex ID offset: the vertex ID will be 
                                          original vertex ID + offset, default 0 */, 
                             lEIDOffset /* edge ID offset: the edge ID will be 
                                          original edge ID + offset, default 0 */, 
                             4 /* DOP */, 
                             1 /* Total number of partitions, default 1 */, 
                             0 /* Partition to load (from 0 to totalPartitions - 1, 
                                  default 0) */, 
                             OraclePropertyGraphDataLoader.NAMEDPIPE 
                             /* splitter flag */, 
                             "chunkPrefix" /* prefix */, 
                             szExtDir /* database directory object */, 
                             true /* rebuild index flag */, 
                             "pddl=t,pdml=t" /* options */);
2.5.2.3 SQL*Loaderベースのデータのロード

SQL*Loaderベースのデータのロードでは、グラフ・データをOracle Databaseにロードするのに、Oracle SQL*Loaderを使用します。SQL*Loaderにより、外部ファイルからOracle Databaseの表にデータがロードされます。この場合、指定した入力ストリームの頂点(またはエッジ)は、スプリッタ・スレッドにより複数のチャンクの間に広がります。各チャンクは、SQL*Loaderを使用して、チャンク内のすべての要素を一時作業表に挿入する、異なるローダー・スレッドにより処理されます。使用されるスプリッタおよびローダー・スレッドの数は、ユーザーが指定した並列度(DOP)によって決定されます。

すべてのグラフ・データが一時作業表にロードされた後、グラフ・ローダーは一時作業表に格納されたすべてのデータをプロパティ・グラフVT$およびGE$表にロードします。

次のコード・フラグメントは、並列度48でSQLベースのパラレル・データ・ロードを使用し、Oracleフラット・ファイル形式の頂点およびエッジ・ファイルからグラフ・データをロードします。APIを使用するには、SQL*Loaderへのパスを指定する必要があります。

    String szUser = "username";
    String szPassword = "password";
    String szDbId = "db18c"; /*service name of the database*/
    String szOPVFile = "../../data/connections.opv"; 
    String szOPEFile = "../../data/connections.ope"; 
    String szSQLLoaderPath = "<YOUR_ORACLE_HOME>/bin/sqlldr";
    OraclePropertyGraph opg = OraclePropertyGraph.getInstance( args, szGraphName); 

    opgdl = OraclePropertyGraphDataLoader.getInstance(); 
    opgdl.loadDataWithSqlLdr(opg, szUser, szPassword, szDbId, 
                             szOPVFile, szOPEFile, 
                             48 /* DOP */, 
                             true /*named pipe flag */, 
                             szSQLLoaderPath /* SQL*Loader path: the path to 
                                                bin/sqlldr*/, 
                             true /*rebuild index */, 
                             "pddl=t,pdml=t" /* options */);

JDBCベースのデータのロードと同様に、SQL*Loaderベースのデータのロードは、1つのファイル、複数のファイル、パーティション、およびファインチューニングを使用して、パラレル・データ・ロードをサポートします。

サブトピック:

  • 複数のファイルを使用したSQL*Loaderベースのデータのロード

  • パーティションを使用したSQL*Loaderベースのデータのロード

  • ファインチューニングを使用したSQL*Loaderベースのパラレル・データ・ロード

複数のファイルを使用したSQL*Loaderベースのデータのロード

SQL*Loaderベースのデータのロードは、複数ファイルからの頂点およびエッジ、またはデータベースへの入力ストリームのロードをサポートします。次のコード・フラグメントは、パラレル・データ・ロードAPIを使用し、複数の頂点およびエッジ・ファイルをロードします。この例では、2つの文字列配列szOPVFilesおよびszOPEFilesが入力ファイルの保持に使用されます。

    String szUser = "username";
    String szPassword = "password";
    String szDbId = "db18c"; /*service name of the database*/
    String[] szOPVFiles = new String[] {"../../data/connections-p1.opv", 
                                        "../../data/connections-p2.opv"}; 
    String[] szOPEFiles = new String[] {"../../data/connections-p1.ope", 
                                        "../../data/connections-p2.ope"}; 
    String szSQLLoaderPath = "../../../dbhome_1/bin/sqlldr";
    OraclePropertyGraph opg = OraclePropertyGraph.getInstance( args, szGraphName); 

    opgdl = OraclePropertyGraphDataLoader.getInstance(); 
    opgdl. loadDataWithSqlLdr (opg, szUser, szPassword, szDbId, 
                               szOPVFiles, szOPEFiles, 
                               48 /* DOP */, 
                               true /* named pipe flag */, 
                               szSQLLoaderPath /* SQL*Loader path */, 
                               true /* rebuild index flag */, 
                               "pddl=t,pdml=t" /* options */);

パーティションを使用したSQL*Loaderベースのデータのロード

大きいプロパティ・グラフの処理中に、SQL*LoaderベースのデータのロードAPIにより、論理パーティション化を使用して、Oracleフラット・ファイル形式のグラフ・データをOracle Databaseにロードできます。各パーティションは、グラフ・データ・ファイルの頂点(またはエッジ)のサブセットを表します。ファイルのサイズはほぼ、パーティションの数で分割されたファイル内の異なる要素IDの数です。各パーティションは[0, Number of partitions – 1]の範囲の、整数IDで識別されます。

パーティションでパラレル・データ・ロードを使用するには、使用するパーティションの合計数と、パーティション・オフセットを、loadDataWithSqlLdr APIで使用される基本パラメータに加えて、指定する必要があります。グラフ・データ・ファイルまたは入力ストリームをデータベースに完全にロードするには、定義したパーティションの数だけ、データ・ロード操作を実行する必要があります。たとえば、2つのパーティションを使用してファイルからグラフ・データをロードするには、オフセット0および1を使用した2つのデータ・ロードAPIコールが必要です。データ・ローダーへの各コールは複数のスレッド、または1つのシステムまたは複数のシステムでの別個のJavaクライアントを使用して処理できます。

この方法は、1つの頂点ファイル(または入力ストリーム)および1つのエッジ・ファイル(または入力ストリーム)で使用されることを意図したものであることに注意してください。さらに、このオプションでは頂点およびエッジでの索引および制約を無効にすることが必要です。これらの索引および制約は、すべてのパーティションがロードされた後で再作成される必要があります。

パーティションを使用したJDBCベースのデータのロードの例は、パーティションを使用したSQL*Loaderベースのロードとして動作するように、容易に移行できます。必要な変更は、API loadData()loadDataWithSqlLdr()で置き換え、SQL*Loaderの場所などの追加の入力パラメータを指定するだけです。

ファインチューニングを使用したSQL*Loaderベースのパラレル・データ・ロード

SQL Loaderベースのデータ・ロードは、要素をプロパティ・グラフ・インスタンスへロードするときに使用されるIDオフセットと同様に、ロードされる行からのデータのサブセットの微調整をサポートします。ファイルから読み取る行の最大数と、頂点およびエッジの両方のオフセット行番号を指定して、ファイルからロードするデータのサブセットを指定できます。この方法では、行の最大数が読み取られるまで、データはオフセット行番号からロードされます。最大行数が-1の場合、ロード・プロセスはファイルの終わりまでデータをスキャンします。

グラフ・データ・ファイルにはいくつかのID衝突が含まれることがあるので、SQL Loaderベースのデータのロードでは、頂点およびエッジのIDオフセットを定義できます。この方法では、ロードされた各頂点のIDは、元の頂点IDおよび指定した頂点IDのオフセットの合計から取得されます。同様に、ロードされた各エッジのIDは、元のエッジIDおよび指定したエッジIDのオフセットの合計から生成されます。頂点およびエッジ・ファイルは相関関係がある必要があります。ロードされたエッジに対する入出力頂点IDは指定した頂点IDオフセットに対して変更されるからです。この操作は、1つのパーティションを使用したデータのロードでのみサポートされます。

次のコード・フラグメントは、指定したグラフ・データ・ファイルから最初の100個の頂点およびエッジをロードします。この例では、IDオフセットは指定しません。

    String szUser = "username";
    String szPassword = "password";
    String szDbId = "db18c"; /* service name of the database */
    String szOPVFile = "../../data/connections.opv"; 
    String szOPEFile = "../../data/connections.ope"; 
    String szSQLLoaderPath = "../../../dbhome_1/bin/sqlldr";
    
    // Run the data loading using fine tuning 
    long lVertexOffsetlines = 0; 
    long lEdgeOffsetlines = 0; 
    long lVertexMaxlines = 100; 
    long lEdgeMaxlines = 100;
    long lVIDOffset = 0;
    long lEIDOffset = 0;
    OraclePropertyGraph opg = OraclePropertyGraph.getInstance( args, szGraphName); 
    OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
    
    opgdl.loadDataWithSqlLdr(opg, szUser, szPassword, szDbId, 
                             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 /* maximum number of lines to start loading 
                                              from partition, default -1 (all lines in 
                                              partition) */, 
                             lVIDOffset /* vertex ID offset: the vertex ID will be 
                                           original vertex ID + offset, default 0 */, 
                             lEIDOffset /* edge ID offset: the edge ID will be 
                                           original edge ID + offset, default 0 */, 
                             48 /* DOP */, 
                             1 /* Total number of partitions, default 1 */, 
                             0 /* Partition to load (from 0 to totalPartitions - 1, 
                                  default 0) */, 
                             OraclePropertyGraphDataLoader.NAMEDPIPE 
                             /* splitter flag */, 
                             "chunkPrefix" /* prefix */, 
                             szSQLLoaderPath /* SQL*Loader path: the path to 
                                                bin/sqlldr*/, 
                             true /* rebuild index */,
                             "pddl=t,pdml=t" /* options */);

2.5.3 グラフ・データのパラレル取得

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

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

次のコードは、プロパティ・グラフをロードし、接続の配列をオープンし、オープンした接続を使用してパラレル問合せを実行してすべての頂点およびエッジを取得します。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
Oracle[] oracleConns = new Oracle[dop];
Connection[]   conns = new Connection[dop];
for (int i = 0; i < dop; i++) { 
  oracleConns[i] = opg.getOracle().clone();
  conns[i] = oracleConns[i].getConnection();
}

long lCountV = 0;
// Iterate over all the vertices’ partitionIDs to count all the vertices
for (int partitionID = 0; partitionID < opg.getVertexPartitionsNumber(); 
     partitionID += dop) { 
  Iterable<Vertex>[] iterables 
        = opg.getVerticesPartitioned(conns /* Connection array */, 
                                     true /* skip store to cache */, 
                                     partitionID /* starting partition */); 
  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’ partitionIDs to count all the edges
for (int partitionID = 0; partitionID < opg.getEdgeTablePartitionIDs(); 
     partitionID += dop) { 
  Iterable<Edge>[] iterables 
          = opg.getEdgesPartitioned(conns /* Connection array */, 
                                    true /* skip store to cache */, 
                                    partitionID /* starting partitionID */); 
  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 < conns.length; idx++) { 
   conns[idx].close();
}

2.5.4 サブグラフ抽出のための要素フィルタ・コールバックの使用

Oracle 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);
}

}

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

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: Robert Smith
Vertex v = opg.getVertices("name", "Robert Smith").iterator().next();

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

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

System.out.println("\n\n--------Collaborators of Robert Smith from " +
 " the US and non-politician\n\n");
long countV = 0;
while (iter.hasNext()) {
Edge edge = iter.next(); // get the edge
// check if smith 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: Robert Smith
Vertex v = opg.getVertices("name", "Robert Smith").iterator().next();

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

opg.setEdgeFilterCallback(cefc);

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

System.out.println("\n\n--------Collaborators of Robert Smith from " +
 " the US and non-politician\n\n");
long countV = 0;
while (iter.hasNext()) {
Edge edge = iter.next(); // get the edge
// check if smith 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++;
}

2.5.5 プロパティ・グラフ・データの読取りでの最適化フラグの使用

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

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

最適化フラグ 説明
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);

2.5.6 プロパティ・グラフのサブグラフの属性の追加および削除

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

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

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

private static class CollaboratorsVertexOpCallback 
implements VertexOpCallback
{
private OracleVertexBase m_smith;
private List<Vertex> m_smithCollaborators;

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

Iterable<Vertex> iter = m_smith.getVertices(Direction.BOTH, 
"collaborates");
m_smithCollaborators = 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 Robert 
 * Smith
*/
@Override
public boolean needOp(OracleVertexBase v)
{
return m_smithCollaborators != null && 
 m_smithCollaborators.contains(v);
}

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

/**
 * 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 " ";
}
}

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

private static class FeudsEdgeOpCallback 
implements EdgeOpCallback
{
private OracleVertexBase m_smith;
private List<Edge> m_smithFeuds;

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

Iterable<Vertex> iter = m_smith.getVertices(Direction.BOTH, 
"feuds");
m_smithFeuds = 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 Robert Smith's 
 * feuds
*/
@Override
public boolean needOp(OracleEdgeBase e)
{
return m_smithFeuds != null && m_smithFeuds.contains(e);
}

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

/**
 * 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_smith.equals(v)) {
v = (OracleVertexBase) e.getVertex(Direction.OUT);
}
String role = v.getProperty("role");
role = role.toLowerCase();

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

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

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

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

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

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

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

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

// Look up for all collaborators of Smith
Iterable<Vertex> collaborators = opg.getVertices("smithCollaborator", "political");
System.out.println("Political collaborators of Robert Smith " + getVerticesAsString(collaborators));

collaborators = opg.getVertices("smithCollaborator", "business");
System.out.println("Business collaborators of Robert Smith " + 
getVerticesAsString(collaborators));

// Add an attribute to all people having a feud with Robert Smith 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 Smith
Iterable<Edge> feuds = opg.getEdges("smithFeud", "political");
System.out.println("\n\nPolitical feuds of Robert Smith " + getEdgesAsString(feuds));

feuds = opg.getEdges("smithFeud", "business");
System.out.println("Business feuds of Robert Smith " + 
getEdgesAsString(feuds));

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

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

opg.removeAttributeFromAllVertices(pvoc);

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

opg.removeAttributeFromAllEdges(beoc);

/**
 * Implementation of a EdgeOpCallback to remove the "smithCollaborators" 
 * property from all people collaborating with Robert Smith 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   
   * smithCollaborator is Philanthropy
   */
  @Override
  public boolean needOp(OracleVertexBase v)
  {
    String type = v.getProperty("smithCollaborator");
    return type != null && type.equals("philanthropy");
  }

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

  /**
   * 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 "smithFeud" property
 * from all connections in a feud with Robert Smith 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 smithFeud is       
   * business
   */
  @Override
  public boolean needOp(OracleEdgeBase e)
  {
    String type = e.getProperty("smithFeud");
    return type != null && type.equals("business");
  }

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

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

2.5.7 プロパティ・グラフ・メタデータの取得

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

次のコード・フラグメントは、Oracle databaseに格納されている既存のプロパティ・グラフのメタデータおよび統計を取得します。

// 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.getVertexPartitionsNumber()));
System.err.println("Edge table number of splits: " + 
 (opg.getEdgePartitionsNumber()));
}

2.5.8 新しいデータの既存のプロパティ・グラフへのマージ

グラフ・データのOracle Databaseの空のプロパティ・グラフへのロードに加えて、新しいグラフ・データを既存の(空のまたは空でない)グラフにマージできます。データのロードと同様に、データのマージも、入力頂点およびエッジを複数のチャンクに分割し、それらをデータベースの既存のグラフにパラレルにマージします。

マージを実行中のフローは、新しいグラフ・データと既存のグラフ・データの間に重複があるかどうかによって異なります。ここでの重複とは、グラフ要素の同じキーが、新しいグラフ・データと既存のグラフ・データとで異なる値を持つ可能性があるという意味です。たとえば、ID 1の頂点のキーweightは、新しいグラフ・データでは値0.8を、既存のグラフ・データでは値0.5を持つ可能性があります。この場合、新しい値または既存の値をキーに使用する必要があるかを指定する必要があります。

次のオプションがグラフ・データのマージに使用できます。JDBベース、外部表ベース、SQL loaderベースのマージ。

  • JDBCベースのグラフ・データのマージ

  • 外部表ベースのデータのマージ

  • SQL*Loaderベースのデータのマージ

JDBCベースのグラフ・データのマージ

JDBCベースのデータのマージでは、Java Database Connectivity (JDBC) APIを使用して、新しいグラフ・データをOracle Databaseにロードしてから、新しいグラフ・データを既存のグラフにマージします。

次の例は、DOP(並列度)が48、バッチ・サイズが1000で、データのマージ・オプションを指定した、JDBCベースのデータ・マージを使用し、Oracle定義のフラット・ファイル形式の頂点およびエッジ・ファイルszOPVFileおよびszOPEFileからの新しいグラフ・データを、opgという名前の既存のグラフにマージします。

String szOPVFile = "../../data/connectionsNew.opv"; 
String szOPEFile = "../../data/connectionsNew.ope"; 
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance(); 
opgdl.mergeData(opg, szOPVFile, szOPEFile, 
     48 /*DOP*/, 
     1000 /*Batch Size*/, 
     true /*Rebuild index*/,  
     "pdml=t, pddl=t, no_dup=t, use_new_val_for_dup_key=t" /*Merge options*/);

データのマージ操作のパフォーマンスを最適化するために、JDBCベースのデータのマージを呼び出すときに、フラグやヒントのセットをマージ・オプション・パラメータに指定できます。これらのヒントとしては次のものがあります。

  • DOP: データのマージ時に使用する並列度。このパラメータは、データをプロパティ・グラフVT$およびGE$表にマージするときに使用するローダー・スレッドの数と同様に、ファイルの分割時に生成するチャンクの数を決定します。

  • バッチ・サイズ:バッチ・モードでOracleのJDBC文で使用するバッチ・サイズを指定する整数。

  • 索引の再作成: trueに設定されている場合、データ・ローダーは、データがロードされるプロパティ・グラフで定義されたすべての索引および制約を無効にします。すべてのデータがプロパティ・グラフにマージされた後、すべての元の索引および制約は再作成され、有効化されます。

  • マージ・オプション: データのマージ操作を最適化するための1つのオプション(またはカンマで区切った複数のオプション)。これらのオプションとしては次のものがあります。

    • PDML=T: データ・ローダーで使用されるデータベース・セッションでのDML操作のパラレル実行を有効にします。このヒントは、長時間実行するバッチ・ジョブのパフォーマンスを向上するのに使用されます。

    • PDDL=T: データ・ローダーで使用されるデータベース・セッションでのDDL操作のパラレル実行を有効にします。このヒントは、長時間実行するバッチ・ジョブのパフォーマンスを向上するのに使用されます。

    • NO_DUP=T: 新しい入力グラフ・データに無効な重複がないことを前提にしています。有効なプロパティ・グラフでは、各頂点(またはエッジ)は指定したプロパティ・キーに対し最大で1つの値を持つことができます。無効なプロパティ・グラフでは、各頂点(またはエッジ)は特定のキーに対し2つ以上の値を持つことがあります。例として、頂点vには2つのキー/値ペア、name/"John"およびname/"Johnny"があり、同じキーを共有しています。

    • OVERLAP=F: 新しいグラフ・データと既存のグラフ・データの間に重複がないことを前提とします。つまり、新しいグラフ・データと既存のグラフ・データに複数の異なる値を持つキーはありません。

    • USE_NEW_VAL_FOR_DUP_KEY=T: 新しいグラフ・データと既存のグラフ・データの間に重複がある場合、新しいグラフ・データの値を使用します。そうでなければ、既存のグラフ・データの値を使用します。

外部表ベースのデータのマージ

外部表ベースのデータのマージでは、外部表を使用して、新しいグラフ・データをOracle Databaseにロードしてから、新しいグラフ・データを既存のグラフにマージします。

外部表ベースのデータのマージには、外部表により読み出されるファイルが格納されるディレクトリ・オブジェクトが必要です。このディレクトリは、次のSQL*Plus文を使用して作成できます。

create or replace directory tmp_dir as '/tmppath/';
grant read, write on directory tmp_dir to public;

次の例は、DOP(並列度)が48で、マージ・オプションを指定した、外部表ベースのデータ・マージを使用し、Oracleフラット・ファイル形式の頂点およびエッジ・ファイルszOPVFileおよびszOPEFileからの新しいグラフ・データを、既存のグラフopgにマージします。

String szOPVFile = "../../data/connectionsNew.opv"; 
String szOPEFile = "../../data/connectionsNew.ope"; 
String szExtDir = "tmp_dir";
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance(); 
opgdl.mergeDataWithExtTab(opg, szOPVFile, szOPEFile, 
     48 /*DOP*/, 
     true /*Use Named Pipe for splitting*/, 
     szExtDir /*database directory object*/, 
     true /*Rebuild index*/,  
     "pdml=t, pddl=t, no_dup=t, use_new_val_for_dup_key=t" /*Merge options*/);

SQL*Loaderベースのデータのマージ

SQLローダー・ベースのデータのマージでは、Oracle SQL*Loaderを使用して、新しいグラフ・データをOracle Databaseにロードしてから、新しいグラフ・データを既存のグラフにマージします。

次の例は、DOP(並列度)が48で、マージ・オプションを指定した、SQLローダー・ベースのデータ・マージを使用し、Oracleフラット・ファイル形式の頂点およびエッジ・ファイルszOPVFileおよびszOPEFileからの新しいグラフ・データを、既存のグラフopgにマージします。APIを使用するには、SQL*Loaderへのパスを指定する必要があります。

String szUser = "username";
String szPassword = "password";
String szDbId = "db18c"; /*service name of the database*/ 
String szOPVFile = "../../data/connectionsNew.opv"; 0
String szOPEFile = "../../data/connectionsNew.ope"; 
String szSQLLoaderPath = "<YOUR_ORACLE_HOME>/bin/sqlldr";    
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance(); 
opgdl.mergeDataWithSqlLdr(opg, szUser, szPassword, szDbId, szOPVFile, szOPEFile, 
     48 /*DOP*/, 
     true /*Use Named Pipe for splitting*/, 
     szSQLLoaderPath /* SQL*Loader path: the path to bin/sqlldr */, 
     true /*Rebuild index*/,  
     "pdml=t, pddl=t, no_dup=t, use_new_val_for_dup_key=t" /*Merge options*/);

2.5.9 プロパティ・グラフ・インスタンスのオープンとクローズ

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

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

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

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

Oracle Databaseの場合、OraclePropertyGraph.getInstanceメソッドはOracleインスタンスを使用してデータベース接続を管理します。OraclePropertyGraphには、グラフ名、ハッシュ・パーティションの数、並列度、表領域、ストレージのオプション(圧縮など)を設定できる、コンストラクタのセットがあります。次に例を示します。

import oracle.pg.rdbms.*;
Oracle oracle = new Oracle(jdbcURL, username, password);

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

インメモリー・アナリスト機能がアプリケーションに必要な場合、GraphConfigBuilderを使用してOracle Database用のグラフを作成し、引数としてグラフ名を指定してOraclePropertyGraphをインスタンス化する必要があります。たとえば、次のコード・スニペットでは、グラフconfigを作成し、OraclePropertyGraphインスタンスを取得し、データをそのグラフにロードし、インメモリー・アナリストを取得します。

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

...
 
PgNosqlGraphConfig cfg = GraphConfigBuilder. forPropertyGraphRdbms ()
       .setJdbcUrl("jdbc:oracle:thin:@<hostname>:1521:<sid>")
       .setUsername("<username>").setPassword("<password>")
       .setName(szGraphName)
       .setMaxNumConnections(8)
       .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, 2 /* dop */, 1000, true, "PDML=T,PDDL=T,NO_DUP=T,"); 
 
  ...
  PgxSession session = Pgx.createSession("session-id-1");
  PgxGraph g = session.readGraphWithProperties(cfg);

  Analyst analyst = session.createAnalyst();
  ...

2.5.10 頂点の作成

頂点を作成するには、次のOracleプロパティ・グラフ・メソッドを使用します。

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

2.5.11 エッジの作成

エッジを作成するには、次のOracleプロパティ・グラフ・メソッドを使用します。

  • 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");

2.5.12 頂点とエッジの削除

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

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

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

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

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

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

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

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

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

グラフをOracle Databaseから、同じクライアントのJavaアプリケーション(1つのJVM)に組み込まれた、インメモリー・アナリストへ読み取ることができます。次の例では、正しいjava.io.tmpdirの設定が必要です。

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

PgRdbmsGraphConfig cfg = GraphConfigBuilder.forPropertyGraphRdbms().setJdbcUrl("jdbc:oracle:thin:@<your_db_host>:<db_port>:<db_sid>")
     .setUsername("<username>")
     .setPassword("<password>")
     .setName("<graph_name>")
     .setMaxNumConnections(8)
     .setLoadEdgeLabel(false)
     .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);

2.5.14 頂点のラベルの指定

データベースおよびデータ・アクセス・レイヤーは頂点にラベルを提供しません。しかし、指定した頂点プロパティの値を、1つ以上のラベルとして扱うことができます。このような変換は、インメモリー・アナリストにのみ関連します。

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

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

2.5.15 インメモリー・グラフの作成

キーストアへのデータベース・パスワードの格納に加えて、インメモリー・グラフをプログラムで作成できます。グラフのサイズが小さい場合、またはグラフのコンテンツが非常に動的な場合に、これにより開発を簡略化することができます。キーのJavaクラスはGraphBuilderです。これはaddVertexおよびaddEdge APIを使用して追加された頂点およびエッジのセットを累積できます。すべての変更が行われると、インメモリー・グラフ・インスタンス(PgxGraph)はGraphBuilderにより作成できます。

次の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();

長整数を頂点およびエッジの識別子として使用するには、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")

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

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

// Drop the graph
Oracle oracle = new Oracle(jdbcUrl, username, password);
OraclePropertyGraphUtils.dropPropertyGraph(oracle, graphName);

PL/SQL APIを使用してプロパティ・グラフを削除することもできます。次に例を示します。

EXECUTE opg_apis.drop_pg('my_graph_name');

2.5.17 PGQL問合せの実行

PgqlStatementインタフェースとPgqlPreparedStatementインタフェースを使用して、Oracle Databaseに対して直接PGQL問合せを実行できます。詳細は、「Oracle Databaseに対して直接PGQL問合せを実行」を参照してください。

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

Oracle Spatial and Graphプロパティ・グラフの索引付けのサポートにより、特定のキー/値またはキー/テキスト・ペア別に要素を高速に取得することを可能にします。このような索引は、要素タイプ(頂点またはエッジ)、キーのセット(および値)、および索引タイプに基づき作成されます。

Oracle Spatial and Graphでは、Oracle Databaseの機能であるOracle Text索引付けテクノロジの使用をサポートしています。

2種類の索引付け構造がサポートされています。

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

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

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

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

索引構成操作により、IT$表が更新されます。これについては、プロパティ・グラフ表(詳細情報)を参照してください。

2.6.1.1 Oracle Textを使用したテキスト索引の構成

Oracle Spatial and GraphはOracle Textを使用した自動テキスト索引をサポートします。Oracle Textでは、頂点(またはエッジ)表のV列に格納されているテキスト値の索引付け、検索および分析のために標準SQLが使用されます。Oracle Textはプロパティ・グラフの頂点(またはエッジ)のすべての既存のK/Vペアを索引付けするので、このオプションは自動テキスト索引とともにのみ使用でき、索引の作成時にはワイルドカード("*")索引キー・パラメータを使用する必要があります。

プロパティ・グラフ機能はUnicodeをより適切にサポートするためにNVARCHARタイプの列を使用するので、データベースの文字セットとしてUTF8 (AL32UTF8)を使用することを強くお薦めします。

頂点表(またはエッジ表)にOracle Text索引を作成するには、ALTER SESSION権限が必要です。次の例では、権限を付与します。

SQL> grant alter session to <YOUR_USER_SCHEMA_HERE>;

カスタマイズが必要な場合、次の例のように、CTX_DDLにEXECUTEを付与します。

SQL> grant execute on ctx_ddl to <YOUR_USER_SCHEMA_HERE>;

Oracle Textを使用したテキスト索引はOracleTextIndexParametersオブジェクトを使用します。Oracle Textを使用した索引の構成パラメータには次のものがあります。

  • プリファレンス所有者: プリファレンスの所有者。

  • データ・ストア: テキスト値の格納方法を指定するデータストア・プリファレンス。データストア・プリファレンスは次のようにctx_ddl.create_preference APIを使用して作成できます。

    SQL> -- The following requires access privilege to CTX_DDL
    SQL> exec ctx_ddl.create_preference('SCOTT.OPG_DATASTORE', 'DIRECT_DATASTORE');
    

    値がNULLに設定されている場合、索引はCTXSYS.DEFAULT_DATASOREを使用して作成されます。このプリファレンスは、DIRECT_DATASTORE型を使用します。

  • フィルタ: 索引付けのためのテキストのフィルタ処理方法を決定するフィルタ・プリファレンスです。フィルタ・プリファレンスは次のようにctx_ddl.create_preferenceを使用して作成できます。

    SQL> -- The following requires access privilege to CTX_DDL
    SQL> exec ctx_ddl.create_preference('SCOTT.OPG_FILTER', 'AUTO_FILTER');
    

    値がNULLに設定されている場合、索引はCTXSYS.NULL_FILTERを使用して作成されます。このプリファレンスは、NULL_FILTER型を使用します。

  • 記憶域: テキスト索引に関連付けられた表に対して表領域および作成パラメータを指定する記憶域プリファレンス。記憶域プリファレンスは次のようにctx_ddl.create_preferenceを使用して作成できます。

    SQL> -- The following requires access privilege to CTX_DDL
    SQL> exec ctx_ddl.create_preference('SCOTT.OPG_STORAGE', 'BASIC_STORAGE');
    

    値がNULLに設定されている場合、索引はCTXSYS.DEFAULT_STORAGEを使用して作成されます。このプリファレンスは、BASIC_STORAGE型を使用します。

  • ワード・リスト: 有効な問合せオプションを指定するワード・リスト・プリファレンス。これらの問合せオプションには、ステミング、ファジー・マッチ、サブストリング、接頭辞索引付けが含まれます。データ・ストア・プリファレンスは次のようにctx_ddl.create_preferenceを使用して作成できます。

    SQL> -- The following example enables stemming and fuzzy matching for English.
    SQL> exec ctx_ddl.create_preference('SCOTT.OPG_WORDLIST', 'BASIC_WORDLIST');
    

    値がNULLに設定されている場合、索引はCTXSYS.DEFAULT_WORDLISTを使用して作成されます。このプリファレンスは、使用するデータベース言語に対して言語ステマーを使用します。

  • ストップ・リスト: 索引付けが想定されないワードのリストを指定するストップ・リスト・プリファレンス。ストップ・リスト・プリファレンスは、ctx_ddl.create_stoplistを使用して作成できます。

    値がNULLに設定されている場合、索引はCTXSYS.DEFAULT_STOPLISTを使用して作成されます。このプリファレンスは、使用するデータベース言語のストップリストを使用します。

  • レクサー: 索引付けするテキストの言語を指定するレクサー・プリファレンス。レクサー・プリファレンスは次のようにctx_ddl.create_preferenceを使用して作成できます。

    SQL> -- The following requires access privilege to CTX_DDL
    SQL> exec ctx_ddl.create_preference('SCOTT.OPG_AUTO_LEXER', 'AUTO_LEXER');
    

    値がNULLに設定されている場合、索引はCTXSYS.DEFAULT_LEXERを使用して作成されます。このプリファレンスは、インストール時に使用された言語に基づき、追加のオプションとともに、BASIC_LEXER型を使用します。

次のコード・フラグメントは、Oracle TextをデフォルトのオプションとOPG_AUTO_LEXERと使用して、テキスト索引の構成を作成します。

String prefOwner = "scott";
String datastore = (String) null;
String filter = (String) null;
String storage = (String) null;
String wordlist = (String) null;
String stoplist = (String) null;
String lexer = "OPG_AUTO_LEXER";
String options = (String) null;

OracleIndexParameters params 
                  = OracleTextIndexParameters.buildOracleText(prefOwner,               
                                                              datastore, 
                                                              filter, 
                                                              storage, 
                                                              wordlist, 
                                                              stoplist, 
                                                              lexer, 
                                                              dop, 
                                                              options);

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

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

プロパティ・グラフで自動索引を指定するときに、次のメソッドを使用して、自動索引を作成、削除および操作します。

  • 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のすべての要素の自動索引で現在使用されている索引付けされたキーのセットを取得します。

デフォルトでは、索引はメソッド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:Robert Smithを持つすべての一致する頂点を検索します。この操作は、テキスト索引の検索を実行します。

さらに、getVertices APIコールでパラメータuseWildCardsを指定することにより、ワイルドカード検索がサポートされます。ワイルドカード検索は、指定したプロパティ・キーに対して自動索引が有効な場合にのみサポートされます。

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

このコード例によって生成される出力は、次のようになります。

----- Vertices with name Robert Smith-----
Vertex ID 1 {name:str:Robert Smith, role:str:political authority, occupation:str:CEO of Example Corporation, country:str:United States, political party:str:Bipartisan, religion:str:Unknown}
Vertices found: 1
 
----- Vertices with name *Smith* -----
Vertex ID 1 {name:str:Robert Smith, role:str:political authority, occupation:str:CEO of Example Corporation, country:str:United States, political party:str:Bipartisan, religion:str:Unknown}
Vertices found: 1

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

手動索引は、プロパティ・グラフの頂点およびエッジで複数の索引の定義をサポートします。手動索引では、要素を手動で索引へ書込み、取得、および削除する必要があります。

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

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

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

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

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

2.6.4 プロパティ・グラフのテキスト索引を介した検索問合せの実行

Oracle Spatial and Graphは、自動および手動テキスト索引を介してテキスト検索問合せを実行するユーティリティのセットを提供します。これらのユーティリティは、特定のキー値ペアに基づく問合せから、1つまたは複数のキーを介した(ワイルドカード、ファジー検索、範囲問合せなどの拡張問合せオプションを使用した)テキスト検索の実行まで、様々です。

2.6.4.1 Oracle Textを使用したテキスト索引を介した検索問合せの実行

Oracle Textでのテキスト検索問合せは、スコアの範囲および順序、スコアIDを含む"contains"句を使用したSELECT SQL問合せに変換されます。Oracleのプロパティ・グラフには、OracleTextQueryObjectという名前のユーティリティが含まれ、これを使用して、Oracle Text索引を介したテキスト検索問合せを実行できます。

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

String prefOwner = "scott";
String datastore = (String) null;
String filter = (String) null;
String storage = (String) null;
String wordlist = (String) null;
String stoplist = (String) null;
String lexer = "OPG_AUTO_LEXER";
String options = (String) null;

OracleIndexParameters params 
                  = OracleTextIndexParameters.buildOracleText(prefOwner,               
                                                              datastore, 
                                                              filter, 
                                                              storage, 
                                                              wordlist, 
                                                              stoplist, 
                                                              lexer, 
                                                              dop, 
                                                              options);

opg.setDefaultIndexParameters(indexParams);
    

// Create auto indexing on all existing properties, use wildcard for all
opg.createKeyIndex(("*", Vertex.class); 

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

// Create the text query object for Oracle Text
OracleTextQueryObject otqo 
               = OracleTextQueryObject.getInstance("Smith" /* query body */, 
                                                   1 /* score */, 
                                                   ScoreRange.POSITIVE /* Score range */,   
                                                   Direction.ASC /* order by direction*/);
 
Iterator<Vertex> vertices = index.get("name", otqo).iterator();
System.out.println("----- Vertices with query: " + otqo.toString() + " -----");
countV = 0;
while (vertices.hasNext()) {
  System.out.println(vertices.next());
  countV++;
}
System.out.println("Vertices found: "+ countV);

問合せを実行するデータ型のクラスを指定して、一致するキー値ペアのデータ型をフィルタ処理できます。次のコード・フラグメントでは、テキスト索引を介して問合せを実行し、語句Smithを含む文字列値を持つすべてのプロパティを取得します。

// Create the text query object for Oracle Text
OracleTextQueryObject otqo 
               = OracleTextQueryObject.getInstance("Smith" /* query body */, 
                                                   1 /* score */, 
                                                   ScoreRange.POSITIVE 
                                                   /* Score range */,   
                                                   Direction.ASC 
                                                   /* order by direction*/,
                                                   "name",
                                                   String.class);
 
Iterator<Vertex> vertices = index.get("name", otqo).iterator();
System.out.println("----- Vertices with query: " + otqo.toString() + " -----");
countV = 0;
while (vertices.hasNext()) {
  System.out.println(vertices.next());
  countV++;
}
System.out.println("Vertices found: "+ countV);

2.6.5 データ型の処理

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

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

Boolean演算子を使用する処理の場合、以降の各キー値ペアは、データ型の接頭辞/接尾辞を追加する必要があるので、問合せは適切な一致を検出できます。

2.6.5.1 Oracle Textでのデータ型の処理

Oracle Textを使用するテキスト索引は、プロパティ・グラフ表のKおよびVテキスト列に対して作成されます。使用可能なすべてのデータ型でテキスト索引付け機能を提供するために、V列に数値、空間および日時のキー/値ペアの文字列表現が移入されます。

V列への移入時に使用される日時および数値形式を指定するには、メソッドsetNumberToCharSqlFormatStringおよびsetTimeToCharSqlFormatStringを使用できます。次のコード・スニペットは、プロパティ・グラフ・インスタンスの日時および数値形式の設定方法を示します。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(args,       
                                                          szGraphName);
opg.setNumberToCharSqlFormatString("TM9");
opg.setTimeToCharSqlFormatString("SYYYY-MM-DD\"T\"HH24:MI:SS.FF9TZH:TZM");

数値または日時値に対してテキスト検索問合せを実行するときは、プロパティ・グラフに関連付けられた形式を使用したテキスト式を使用する必要があります。OraclePropertyGraphにはユーティリティAPI opg.parseValueToCharSQLFormatStringが含まれ、これにより数値または日時オブジェクトをV列ストレージで使用される形式へ解析できます。次のコード・スニペットは、日付値を使用してこの関数を呼び出し、取得したテキストからテキスト問合せオブジェクトを作成します。

Date d = new java.util.Date(100l);
String szDate = opg.parseValueToCharSQLFormatString(d);

// Create the text query object for Oracle Text
OracleTextQueryObject otqo 
               = OracleTextQueryObject.getInstance(szDate /* query body */, 
                                                   1 /* score */, 
                                                   ScoreRange.POSITIVE /* Score range */,   
                                                   Direction.ASC /* order by direction);

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

Oracleのプロパティ・グラフ・サポートは、Oracle Textとの統合による手動および自動テキスト索引を管理します。

作成時に、検索エンジンおよびその他のテキスト索引で使用される構成設定を指定する、OracleIndexParametersオブジェクトを作成する必要があります。プロパティ・グラフのテキスト索引が作成された後、これらの構成設定を変更することはできません。

自動索引の場合、すべての頂点索引キーは1つのテキスト索引により管理され、すべてのエッジ索引キーは、最初の頂点またはエッジ・キーが索引付けされたときに指定した構成を使用して、別のテキスト索引により管理されます。

構成設定を変更する必要がある場合、まず現在の索引を無効化し、新しいOracleIndexParametersオブジェクトを使用して再度作成します。

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

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

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

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

OracleTextAutoIndexのメソッドgetPartitionedを呼び出し、Oracle Textへの接続の配列(Connectionオブジェクト)、検索するキー/値ペア、および開始パーティションIDを使用することで、Oracle Textを使用したパラレル・テキスト問合せを使用できます。

次のコード・フラグメントは、Oracle Textを使用して、自動テキスト索引を生成し、パラレル・テキスト問合せを実行します。OracleTextAutoIndexクラスでのgetPartitionedメソッドへの呼出し数は、VT$ (またはGE$表)のパーティションの合計数と使用される接続の数によって制御されます。

OraclePropertyGraph opg = OraclePropertyGraph.getInstance(…);
String prefOwner = "scott";
String datastore = (String) null;
String filter = (String) null;
String storage = (String) null;
String wordlist = (String) null;
String stoplist = (String) null;
String lexer = "OPG_AUTO_LEXER";
String options = (String) null;

OracleIndexParameters params 
                  = OracleTextIndexParameters.buildOracleText(prefOwner,               
                                                              datastore, 
                                                              filter, 
                                                              storage, 
                                                              wordlist, 
                                                              stoplist, 
                                                              lexer, 
                                                              dop, 
                                                              options);

opg.setDefaultIndexParameters(indexParams);
    

// Create auto indexing on all existing properties, use wildcard for all
opg.createKeyIndex(("*", Vertex.class); 


// Create the text query object for Oracle Text
OracleTextQueryObject otqo 
               = OracleTextQueryObject.getInstance("Smith" /* query body */, 
                                                   1 /* score */, 
                                                   ScoreRange.POSITIVE /* Score range */,   
                                                   Direction.ASC /* order by direction*/);

// Get the Connection object 
Connection[] conns = new Connection[dop];
for (int idx = 0; idx < conns.length; idx++) {
conns[idx] = opg.getOracle().clone().getConnection();
}

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

// Iterate to cover all the partitions 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 */, 
 otqo, 
 true /* wildcards */, 
 split /* start split ID */);

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

// Close the connections
for (int idx = 0; idx < conns.length; idx++) {
conns[idx].dispose();
}

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

2.7 プロパティ・グラフ・データのアクセス制御(グラフレベルおよびOLS)

Oracle Graphでは、2つのアクセス制御およびセキュリティ・モデル(グラフ・レベルのアクセス制御、Oracle Label Security (OLS)との統合によるファイングレイン・セキュリティ)をサポートします。

  • グラフレベルのアクセス制御は、所有者以外のユーザーにプロパティ・ブラフのアクセスを許可/禁止する付与/拒否によって行われます。

  • プロパティ・グラフ・データのOLSにより、重要度ラベルをプロパティ・グラフに格納された個別の頂点またはエッジに関連付けることができます。

Oracle Databaseに格納されたプロパティ・グラフ・データへのデフォルトのアクセス制御はグラフ・レベルです。グラフの所有者はグラフの読取り、挿入、削除、更新および選択の権限を他のユーザーに付与できます。

ただし、厳密なセキュリティ要件を持つアプリケーションの場合は、Oracle DatabaseのOracle Label Securityオプションを使用して、ファイングレイン・アクセス制御メカニズムを実施できます。OLSでは、各問合せに対し、特定の要素(頂点またはエッジ)へのアクセスは、そのラベルとユーザーのラベルを比較することで付与されます。(OLSの使用方法の詳細は、Oracle Label Security管理者ガイドを参照してください。)

Oracle Label Securityが有効な場合、要素(頂点またはエッジ)は、より高い重要度ラベルを持つ同じ要素がデータベースに存在すると、グラフに挿入できません。たとえば、( Vertex ID 1 {name:str:v1} "SENSITIVE" )のように非常に機密性の高いラベルを持つ頂点があるとします。( Vertex ID 1 {name:str:v1} "PUBLIC" )は、実際には低い権限(PUBLIC)のユーザーが頂点を更新するのを防ぎます。一方、高い権限のユーザーが、低いレベルのセキュリティ・ラベルで作成された頂点またはエッジを上書きする場合、高いセキュリティの新しいラベルは頂点またはエッジに関連付けられ、低い権限のユーザーはそれを参照できなくなります。

2.7.1 Oracle Label Security (OLS)のプロパティ・グラフ・データへの適用

このトピックでは、プロパティ・グラフ・データにOLSを適用する方法を説明する例を示します。

プロパティ・グラフは通常のリレーショナル表に格納されるので、この例は通常のリレーショナル表にOLSを適用するのと違いはありません。次に、OLSの構成および有効化、セキュリティ・ラベルを使用するセキュリティ・ポリシーの作成、およびそれをプロパティ・グラフに適用する方法について示します。このコード例は非常に単純化されており、推奨のプラクティスで使用しているユーザー名およびパスワードをそのまま使用しないでください。

  1. SYSDBAとして、userP、userP2、userS、userTS、userTS2およびpgAdminという名前のデータベース・ユーザーを作成します。

    CONNECT / as sysdba;
    
    CREATE USER userP IDENTIFIED BY userPpass;
    GRANT connect, resource, create table, create view, create any index TO userP;
    GRANT unlimited TABLESPACE to userP;
    
    CREATE USER userP2 IDENTIFIED BY userP2pass;
    GRANT connect, resource, create table, create view, create any index TO userP2;
    GRANT unlimited TABLESPACE to userP2;
    
    CREATE USER userS IDENTIFIED BY userSpass;
    GRANT connect, resource, create table, create view, create any index TO userS;
    GRANT unlimited TABLESPACE to userS;
    
    CREATE USER userTS IDENTIFIED BY userTSpass;
    GRANT connect, resource, create table, create view, create any index TO userTS;
    GRANT unlimited TABLESPACE to userTS;
    
    CREATE USER userTS2 IDENTIFIED BY userTS2pass;
    GRANT connect, resource, create table, create view, create any index TO userTS2;
    GRANT unlimited TABLESPACE to userTS2;
    
    CREATE USER pgAdmin IDENTIFIED BY pgAdminpass;
    GRANT connect, resource, create table, create view, create any index TO pgAdmin;
    GRANT unlimited TABLESPACE to pgAdmin;
    
  2. SYSDBAとして、Oracle Label Securityを構成および有効化します。

    ALTER USER lbacsys IDENTIFIED BY lbacsys ACCOUNT UNLOCK;
    EXEC LBACSYS.CONFIGURE_OLS;
    EXEC LBACSYS.OLS_ENFORCEMENT.ENABLE_OLS;
    
  3. SYSTEMとして、sec_adminおよびhr_secに権限を付与します。

    CONNECT system/<system-password>
    GRANT connect, create any index to sec_admin IDENTIFIED BY password;
    GRANT connect, create user, drop user, create role, drop any role TO hr_sec IDENTIFIED BY password;
    
  4. LBACSYSとして、セキュリティ・ポリシーを作成します。

    CONNECT lbacsys/<lbacsys-password>
    
    BEGIN
    SA_SYSDBA.CREATE_POLICY (
      policy_name => 'DEFENSE',
      column_name => 'SL',
      default_options => 'READ_CONTROL,LABEL_DEFAULT,HIDE');
    END;
    /
    
  5. LBACSYSとして、DEFENSE_DBAおよびexecuteをsec_adminおよびhr_sec usersに付与します。

    GRANT DEFENSE_DBA to sec_admin;
    GRANT DEFENSE_DBA to hr_sec;
    
    GRANT execute on SA_COMPONENTS to sec_admin;
    GRANT execute on SA_USER_ADMIN to hr_sec;
    
  6. SEC_ADMINとして、3つのセキュリティ・レベルを作成します(簡略化のため、コンパートメントおよびグループを省略しています)。

    CONNECT sec_admin/<sec_admin-password>;
    
    BEGIN
    SA_COMPONENTS.CREATE_LEVEL ( 
      policy_name => 'DEFENSE', 
      level_num => 1000,
      short_name => 'PUB',
      long_name => 'PUBLIC'); 
    END;
    /
    EXECUTE SA_COMPONENTS.CREATE_LEVEL('DEFENSE',2000,'CONF','CONFIDENTIAL');
    EXECUTE SA_COMPONENTS.CREATE_LEVEL('DEFENSE',3000,'SENS','SENSITIVE');
    
  7. 3つのラベルを作成します。

    EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('DEFENSE',1000,'PUB');
    EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('DEFENSE',2000,'CONF');
    EXECUTE SA_LABEL_ADMIN.CREATE_LABEL('DEFENSE',3000,'SENS');
    
  8. HR_SECとして、ラベルおよび権限を割り当てます。

    CONNECT hr_sec/<hr_sec-password>;
    
    BEGIN
    SA_USER_ADMIN.SET_USER_LABELS (
      policy_name => 'DEFENSE',
      user_name => 'UT',
      max_read_label => 'SENS',
      max_write_label => 'SENS',
      min_write_label => 'CONF',
      def_label => 'SENS',
      row_label => 'SENS');
    END;
    /
    
    EXECUTE SA_USER_ADMIN.SET_USER_LABELS('DEFENSE', 'userTS', 'SENS');
    EXECUTE SA_USER_ADMIN.SET_USER_LABELS('DEFENSE','userTS2','SENS');
    EXECUTE SA_USER_ADMIN.SET_USER_LABELS('DEFENSE', 'userS', 'CONF');
    EXECUTE SA_USER_ADMIN.SET_USER_LABELS ('DEFENSE', userP', 'PUB', 'PUB', 'PUB', 'PUB', 'PUB');
    EXECUTE SA_USER_ADMIN.SET_USER_LABELS ('DEFENSE', 'userP2', 'PUB', 'PUB', 'PUB', 'PUB', 'PUB');
    EXECUTE SA_USER_ADMIN.SET_USER_PRIVS ('DEFENSE', 'pgAdmin', 'FULL');
    
  9. SEC_ADMINとして、セキュリティ・ポリシーを指定したプロパティ・グラフに適用します。名前がOLSEXAMPLEで、グラフの所有者がuserPのプロパティ・グラフがあるとします。OLSセキュリティを適用するために、次の文を実行します。

    CONNECT sec_admin/<password>;
    
    EXECUTE SA_POLICY_ADMIN.APPLY_TABLE_POLICY ('DEFENSE', 'userP', 'OLSEXAMPLEVT$');
    EXECUTE SA_POLICY_ADMIN.APPLY_TABLE_POLICY ('DEFENSE', 'userP', 'OLSEXAMPLEGE$');
    EXECUTE SA_POLICY_ADMIN.APPLY_TABLE_POLICY ('DEFENSE', 'userP', 'OLSEXAMPLEGT$');
    EXECUTE SA_POLICY_ADMIN.APPLY_TABLE_POLICY ('DEFENSE', 'userP', 'OLSEXAMPLESS$');
    

これでOracle Label Securityは、プロパティ・グラフに格納された個別の頂点またはエッジに関連付けられた重要度ラベルを持つようになりました。

次の例は、OLSEXAMPLEという名前のプロパティ・グラフの作成方法を示し、異なるセキュリティ・ラベルを持つ別のユーザーのグラフ要素の作成、読取り、書込み時の動作を示すフロー例を示します。

// Create Oracle Property Graph
String graphName = "OLSEXAMPLE";
Oracle connPub = new Oracle("jdbc:oracle:thin:@host:port:SID",  "userP", "userPpass");
OraclePropertyGraph graphPub = OraclePropertyGraph.getInstance(connPub, graphName, 48);

// Grant access to other users
graphPub.grantAccess("userP2",  "RSIUD"); // Read, Select, Insert, Update, Delete (RSIUD)
graphPub.grantAccess("userS",   "RSIUD");
graphPub.grantAccess("userTS",  "RSIUD");
graphPub.grantAccess("userTS2", "RSIUD");
 
// Load data
OraclePropertyGraphDataLoader opgdl = OraclePropertyGraphDataLoader.getInstance();
String vfile = "../../data/connections.opv";
String efile = "../../data/connections.ope";
graphPub.clearRepository();
opgdl.loadData(graphPub, vfile, efile, 48, 1000, true, null);
System.out.println("Vertices with user userP and PUBLIC LABEL: " + graphPub.countVertices()); // 78
System.out.println("Vertices with user userP and PUBLIC LABEL: " + graphPub.countEdges());  // 164

// Second user with a higher level 
Oracle connTS = new Oracle("jdbc:oracle:thin:@host:port:SID", "userTS", "userTpassS");
OraclePropertyGraph graphTS = OraclePropertyGraph.getInstance(connTS, "USERP", graphName, 8, 48, null, null);
System.out.println("Vertices with user userTS and SENSITIVE LABEL: " + graphTS.countVertices()); // 78
System.out.println("Vertices with user userTS and SENSITIVE LABEL: " + graphTS.countEdges());  // 164

// Add vertices and edges with the second user
long lMaxVertexID = graphTS.getMaxVertexID();
long lMaxEdgeID = graphTS.getMaxEdgeID();
long size = 10;
System.out.println("\nAdd " + size + " vertices and edges with user userTS and SENSITIVE LABEL\n");
for (long idx = 1; idx <= size; idx++) {
  Vertex v = graphTS.addVertex(idx + lMaxVertexID);
  v.setProperty("name", "v_" + (idx + lMaxVertexID));
  Edge e = graphTS.addEdge(idx + lMaxEdgeID, v, graphTS.getVertex(idx), "edge_" + (idx + lMaxEdgeID));
}
graphTS.commit();

// User userP with a lower level only sees the original vertices and edges, user userTS can see more
System.out.println("Vertices with user userP and PUBLIC LABEL: " + graphPub.countVertices()); // 78
System.out.println("Vertices with user userP and PUBLIC LABEL: " + graphPub.countEdges());  // 164
System.out.println("Vertices with user userTS and SENSITIVE LABEL: " + graphTS.countVertices()); // 88
System.out.println("Vertices with user userTS and SENSITIVE LABEL: " + graphTS.countEdges());  // 174

// Third user with a higher level 
Oracle connTS2 = new Oracle("jdbc:oracle:thin:@host:port:SID", "userTS2", "userTS2pass");
OraclePropertyGraph graphTS2 = OraclePropertyGraph.getInstance(connTS2, "USERP", graphName, 8, 48, null, null);
System.out.println("Vertices with user userTS2 and SENSITIVE LABEL: " + graphTS2.countVertices()); // 88
System.out.println("Vertices with user userTS2 and SENSITIVE LABEL: " + graphTS2.countEdges());  // 174

// Fourth user with a intermediate level 
Oracle connS = new Oracle("jdbc:oracle:thin:@host:port:SID", "userS", "userSpass");
OraclePropertyGraph graphS = OraclePropertyGraph.getInstance(connS, "USERP", graphName, 8, 48, null, null);
System.out.println("Vertices with user userS and CONFIDENTIAL LABEL: " + graphS.countVertices()); // 78
System.out.println("Vertices with user userS and CONFIDENTIAL LABEL: " + graphS.countEdges());  // 164
   
// Modify vertices with the fourth user
System.out.println("\nModify " + size + " vertices with user userS and CONFIDENTIAL LABEL\n");
for (long idx = 1; idx <= size; idx++) {
  Vertex v = graphS.getVertex(idx);
  v.setProperty("security_label", "CONFIDENTIAL");
}
graphS.commit();

// User userP with a lower level that userS cannot see the new vertices
// Users userS and userTS can see them
System.out.println("Vertices with user userP with property security_label: " + OraclePropertyGraphUtils.size(graphPub.getVertices("security_label", "CONFIDENTIAL"))); // 0
System.out.println("Vertices with user userS with property security_label: " + OraclePropertyGraphUtils.size(graphS.getVertices("security_label", "CONFIDENTIAL"))); // 10
System.out.println("Vertices with user userTS with property security_label: " + OraclePropertyGraphUtils.size(graphTS.getVertices("security_label", "CONFIDENTIAL"))); // 10
System.out.println("Vertices with user userP and PUBLIC LABEL: " + graphPub.countVertices()); // 68
System.out.println("Vertices with user userTS and SENSITIVE LABEL: " + graphTS.countVertices()); // 88

前述の例によって生成される出力は次のとおりです。

Vertices with user userP and PUBLIC LABEL: 78
Vertices with user userP and PUBLIC LABEL: 164
Vertices with user userTS and SENSITIVE LABEL: 78
Vertices with user userTS and SENSITIVE LABEL: 164

Add 10 vertices and edges with user userTS and SENSITIVE LABEL

Vertices with user userP and PUBLIC LABEL: 78
Vertices with user userP and PUBLIC LABEL: 164
Vertices with user userTS and SENSITIVE LABEL: 88
Vertices with user userTS and SENSITIVE LABEL: 174
Vertices with user userTS2 and SENSITIVE LABEL: 88
Vertices with user userTS2 and SENSITIVE LABEL: 174
Vertices with user userS and CONFIDENTIAL LABEL: 78
Vertices with user userS and CONFIDENTIAL LABEL: 164

Modify 10 vertices with user userS and CONFIDENTIAL LABEL

Vertices with user userP with property security_label: 0
Vertices with user userS with property security_label: 10
Vertices with user userTS with property security_label: 10
Vertices with user userP and PUBLIC LABEL: 68
Vertices with user userTS and SENSITIVE LABEL: 88

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

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

このシェルを使用するには、まずApache Groovyを個別にダウンロードしてインストールする必要があります。

シェルを起動するには、<graph client home>/bin/ディレクトリに移動します。スクリプトopg-groovyが含まれています。

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

$ sh ./opg-groovy
 
opg-rdbms> cfg = 
cfg = GraphConfigBuilder.forPropertyGraphRdbms() \
.setJdbcUrl("jdbc:oracle:thin:@127.0.0.1:1521:orcl")\
.setUsername("scott").setPassword("<password>") \
.setName("connections") .setMaxNumConnections(2)\
.setLoadEdgeLabel(false) \
.addEdgeProperty("weight", PropertyType.DOUBLE, "1000000") \
.build();

opg-rdbms> opg = OraclePropertyGraph.getInstance(cfg);
==>oraclepropertygraph with name myGraph
 
opg-rdbms> opgdl = OraclePropertyGraphDataLoader.getInstance();
==>oracle.pg.nosql.OraclePropertyGraphDataLoader@576f1cad
 
opg-rdbms> opgdl.loadData(opg, new FileInputStream("../../data/connections.opv"), new FileInputStream("../../data/connections.ope"), 4/*dop*/, 1000/*iBatchSize*/, true /*rebuildIndex*/, null /*szOptions*/); ==>null
 
opg-rdbms> 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-rdbms>  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 ...]

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

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

opg-rdbms> 
cfg = GraphConfigBuilder.forPropertyGraphRdbms() \
.setJdbcUrl("jdbc:oracle:thin:@127.0.0.1:1521:orcl")\
.setUsername("scott").setPassword("<password>") \
.setName("connections") .setMaxNumConnections(2)\
.setLoadEdgeLabel(false) \
.addEdgeProperty("weight", PropertyType.DOUBLE, "1000000") \
.build(); 
opg-rdbms> opg = OraclePropertyGraph.getInstance(cfg);  
==>oraclepropertygraph with name myGraph
 
opg-rdbms> opgdl = OraclePropertyGraphDataLoader.getInstance();
==>oracle.pg.hbase.OraclePropertyGraphDataLoader@3451289b
 
opg-rdbms> opgdl.loadData(opg, "../../data/connections.opv", "../../data/connections.ope", 4/*dop*/, 1000/*iBatchSize*/, true /*rebuildIndex*/, null /*szOptions*/);
==>null
 
opg-rdbms> opg.getVertices();
==>Vertex ID 78 {country:str:United States, name:str:Hosain Rahman, occupation:str:CEO of Jawbone}
...
 
opg-rdbms> 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-rdbms> session = Pgx.createSession("session-id-1");
opg-rdbms> g = session.readGraphWithProperties(cfg);
opg-rdbms> analyst = session.createAnalyst();
 
opg-rdbms>  triangles = analyst.countTriangles(false).get();
==>22

Java APIの詳細は、Javadoc参照情報を参照してください。

2.9 グラフZeppelinインタプリタ・クライアントの使用

Oracle Graphは、Apache Zeppelinのインタプリタ・クライアント実装を提供します。このチュートリアルでは、グラフ・インタプリタをローカルのZeppelinインストール環境にインストールして、単純な操作を実行する方法について説明します。

インタプリタのインストール

次のステップは、Zeppelinバージョン0.9を使用してテストされました。新しいバージョンでは変更が必要な可能性があります。

  1. Apache Zeppelinのダウンロードとインストールをまだ実行していない場合は、実行してください。

    ノート:

    Apache ZeppelinにはJava 8が必要です。
  2. Apache Groovy 2.4.xのダウンロードとインストールをまだ実行していない場合は、実行してください。

  3. ライブラリをコピーします:
    • ライブラリをApache Zeppelin用Oracle Graph Clientパッケージから$ZEPPELIN_HOME/interpreter/pgxにコピーします。次に例を示します。
      unzip oracle-graph-zeppelin-interpreter-20.4.0.zip -d $ZEPPELIN_HOME/interpreter/pgx
    • $GROOVY_HOME/lib内のライブラリを $ZEPPELIN_HOME/interpreter/pgxにコピーします。次に例を示します。
      cp $GROOVY_HOME/lib/* $ZEPPELIN_HOME/interpreter/pgx
  4. Zeppelinを再起動します。

インタプリタの使用

グラフ・インタプリタにpgxという名前を付けた場合は、他のインタプリタと同様に、%pgxディレクティブを使用して段落を開始することにより、グラフ・サーバーに段落を送信できます。

インタプリタは、リモート・グラフ・サーバーと対話するクライアントのように動作します。Zeppelinインタプリタ内に埋め込まれたグラフ・サーバー・インスタンスは実行できません。次の例に示すように、グラフ・サーバーのベースURLおよび接続情報を指定する必要があります。

%pgx
import oracle.pgx.api.*
import groovy.json.*
 
baseUrl = '<base-url>'
username = '<username>'
password = '<password>'
 
conn = new URL("$baseUrl/auth/token").openConnection()
conn.setRequestProperty('Content-Type', 'application/json')
token = conn.with {
  doOutput = true
  requestMethod = 'POST'
  outputStream.withWriter { writer ->
    writer << JsonOutput.toJson([username: username, password: password])
  }
  return new JsonSlurper().parseText(content.text).access_token
}
 
instance = Pgx.getInstance(baseUrl, token)
session = instance.createSession("my-session")

インメモリー・アナリストZeppelin Interpreterは、インメモリー・アナリスト・シェルと同じ方法で段落を評価して出力を返します。したがって、有効なインメモリー・アナリストのシェル・スクリプトはすべて、次の例のようにインメモリー・アナリスト・インタプリタで実行されます。

%pgx
g_brands = session.readGraphWithProperties("/opt/data/exommerce/brand_cat.json")
g_brands.getNumVertices()
rank = analyst.pagerank(g_brands, 0.001, 0.85, 100)
rank.getTopKValues(10)

次の図は、アイコンをクリックしてその問合せを実行した後の問合せの結果を示しています。

前述の図で確認できるように、Zeppelinインタプリタは、rank.getTopKValues(10)によってZeppelin表として返された値を自動的にレンダリングし、より便利な方法で結果を参照できるようにします。

プロパティ値(getTopKValues()getBottomKValues()およびgetValues())の他に、次の戻り型が段落から返された場合は、それらも自動的に表としてレンダリングされます。

  • PgqlResultSet - PgxGraphクラスのqueryPgql("...")メソッドによって返されるオブジェクト
  • MapIterable - PgxMapクラスのentries()メソッドによって返されるオブジェクト

他のすべての戻り型およびエラーは、インメモリー・アナリスト・シェルと同様に、通常の文字列として返されます。

Zeppelinの詳細は、公式のZeppelinドキュメントを参照してください。

2.10 RDFグラフでのプロパティ・グラフ・ビューの作成

Oracle Graphでは、プロパティ・グラフとしてRDFデータを表示し、Oracle Databaseに格納されたRDFグラフを介して、プロパティ・グラフ・ビューを作成することで、グラフの分析操作を実行できます。

RDFモデル(または仮想モデル)を指定して、プロパティ・グラフ機能では2つのビュー(頂点用の<graph_name>VT$ビューおよびエッジ用の<graph_name>GE$ビュー)が作成されます。

PGUtils.createPropertyGraphViewOnRDFメソッドにより、RDFデータに対するプロパティ・グラフ・ビューをカスタマイズできます。

public static void createPropertyGraphViewOnRDF( Connection conn /* a Connection instance to Oracle database */,
      String pgGraphName /* the name of the property graph to be created */,
      String rdfModelName /* the name of the RDF model */,
      boolean virtualModel /* a flag represents if the RDF model
                              is virtual model or not; 
                              true – virtual mode, false – normal model*/,
      RDFPredicate[] predListForVertexAttrs /* an array of RDFPredicate objects specifying how to create vertex view using these predicates; each RDFPredicate includes two fields: an URL of the RDF predicate, the corresponding name of vertex key in the Property Graph. The mapping from RDF predicates to vertex keys will be created based on this parameter.  */,
      RDFPredicate[] predListForEdges /* an array of RDFPredicate specifying how to create edge view using these predicates; each RDFPredicate includes two (or three) fields: an URL of the RDF predicate, the edge label in the Property Graph, the weight of the edge (optional). The mapping from RDF predicates to edges will be created based on this parameter. */)

この操作には、プロパティ・グラフの名前、プロパティ・グラフ・ビューを生成するのに使用するRDFモデルの名前、およびトリプルを頂点またはエッジに解析する方法を決定するマッピングのセットが必要です。createPropertyGraphViewOnRDFメソッドには、RDF述語の頂点用のキー/値プロパティへのマッピング方法を指定するキー/値マッピング配列と、RDF述語のエッジへのマップ方法を指定するエッジ・マッピング配列が必要です。PGUtils.RDFPredicate APIによりRDFアサーションから頂点/エッジへのマップを作成できます。

キー/値マッピングの少なくとも1つのRDF述語に一致するトリプルに基づき、頂点が作成されます。マッピング配列で定義されたRDF述語のいずれかを満たす各トリプルは、トリプルのサブジェクトの内部RDFリソースIDに基づくIDと、自身のマッピングにより定義されたキーおよびトリプルのオブジェクトから取得した値を持つキー/値ペアを持つ頂点へと解析されます。

次の例は、プロパティ名がtitleのキー/値プロパティへのRDF述語URI http://purl.org/dc/elements/1.1/titleのキー/値マッピングを定義します。

String titleURL = "http://purl.org/dc/elements/1.1/title";
// create an RDFPredicate to specify how to map the RDF predicate to vertex keys
RDFPredicate titleRDFPredicate 
              = RDFPredicate.getInstance(titleURL /* RDF Predicate URI */ , 
                                         "title" /* property name */);

エッジのマッピング配列の少なくとも1つのRDF述語に一致するトリプルに基づき、エッジが作成されます。マッピング配列で定義されたRDF述語を満たす各トリプルは、行番号に基づくID、自身のマッピングにより定義されたエッジ・ラベル、トリプルのサブジェクトのRDFリソースIDから取得した出力頂点、トリプルのオブジェクトのRDFリソースIDから取得した入力頂点を持つエッジに解析されます。ここで解析される各トリプルに対し、キー/値マッピングから生成されていない場合は、2つの頂点が作成されます。

次の例は、RDF述語URI http://purl.org/dc/elements/1.1/referenceのラベルreferencesで重みが0.5dのエッジへのエッジ・マッピングを定義します。

String referencesURL = "http://purl.org/dc/terms/references";
// create an RDFPredicate to specify how to map the RDF predicate to edges
RDFPredicate referencesRDFPredicate    
                      = RDFPredicate.getInstance(referencesURL, "references", 0.5d);

次の例は、様々なパブリケーション、作成者および参照を記述する、RDFモデルarticlesに対するプロパティ・グラフ・ビューを作成します。生成されたプロパティ・グラフには、titleおよびcreatorを含む、キー/値プロパティを持つ頂点が含まれます。このプロパティ・グラフのエッジは、パブリケーション間の参照により決定されます。

Oracle oracle = null;
Connection conn = null;
OraclePropertyGraph pggraph = null;
try {
  // create the connection instance to Oracle database
  OracleDataSource ds = new oracle.jdbc.pool.OracleDataSource();
  ds.setURL(jdbcUrl);
  conn = (OracleConnection) ds.getConnection(user, password);
 	
  // define some string variables for RDF predicates
  String titleURL = "http://purl.org/dc/elements/1.1/title";
  String creatorURL = "http://purl.org/dc/elements/1.1/creator";
  String serialnumberURL = "http://purl.org/dc/elements/1.1/serialnumber";
  String widthURL = "http://purl.org/dc/elements/1.1/width";
  String weightURL = "http://purl.org/dc/elements/1.1/weight";
  String onsaleURL = "http://purl.org/dc/elements/1.1/onsale";
  String publicationDateURL = "http://purl.org/dc/elements/1.1/publicationDate";
  String publicationTimeURL = "http://purl.org/dc/elements/1.1/publicationTime";
  String referencesURL = "http://purl.org/dc/terms/references";
     
  // create RDFPredicate[] predsForVertexAttrs to specify how to map 
  // RDF predicate to vertex keys
  RDFPredicate[] predsForVertexAttrs = new RDFPredicate[8];
  predsForVertexAttrs[0] = RDFPredicate.getInstance(titleURL, "title");
  predsForVertexAttrs[1] = RDFPredicate.getInstance(creatorURL, "creator");
  predsForVertexAttrs[2] = RDFPredicate.getInstance(serialnumberURL, 
                                                    "serialnumber");
  predsForVertexAttrs[3] = RDFPredicate.getInstance(widthURL, "width");
  predsForVertexAttrs[4] = RDFPredicate.getInstance(weightURL, "weight");
  predsForVertexAttrs[5] = RDFPredicate.getInstance(onsaleURL, "onsale");
  predsForVertexAttrs[6] = RDFPredicate.getInstance(publicationDateURL, 
                                                    "publicationDate");
  predsForVertexAttrs[7] = RDFPredicate.getInstance(publicationTimeURL, 
                                                    "publicationTime");

  // create RDFPredicate[] predsForEdges to specify how to map RDF predicates to 
  // edges
  RDFPredicate[] predsForEdges = new RDFPredicate[1];
  predsForEdges[0] = RDFPredicate.getInstance(referencesURL, "references", 0.5d);
      
  // create PG view on RDF model
  PGUtils.createPropertyGraphViewOnRDF(conn, "articles", "articles", false, 
                                       predsForVertexAttrs, predsForEdges);

  // get the Property Graph instance
  oracle = new Oracle(jdbcUrl, user, password);
  pggraph = OraclePropertyGraph.getInstance(oracle, "articles", 24);

  System.err.println("------ Vertices from property graph view ------");
  pggraph.getVertices();
  System.err.println("------ Edges from property graph view ------");
  pggraph.getEdges();
}
finally {
  pggraph.shutdown();
  oracle.dispose();
  conn.close();
}

articles RDFモデル(11トリプル)の次のトリプルを指定すると、出力のプロパティ・グラフには2つの頂点、1つは<http://nature.example.com/Article1> (v1)用、およびもう1つは <http://nature.example.com/Article2> (v2)用が含まれます。頂点v1の場合、8つのプロパティを持ち、その値はRDF述語と同じです。たとえば、v1のタイトルは“All about XYZ”です。同様に、頂点v2には、2つのプロパティ、titleおよびcreatorがあります。出力プロパティ・グラフには、エッジ・ラベル“references”で重みが0.5dの、頂点v1から頂点v2への1つのエッジ(eid:1)が含まれます。

<http://nature.example.com/Article1> <http://purl.org/dc/elements/1.1/title> “All about XYZ”^^xsd:string.
<http://nature.example.com/Article1> <http://purl.org/dc/elements/1.1/creator> “Jane Smith”^^xsd:string. 
<http://nature.example.com/Article1> <http://purl.org/dc/elements/1.1/serialnumber> “123456”^^xsd:integer.
<http://nature.example.com/Article1> <http://purl.org/dc/elements/1.1/width> “10.5”^^xsd:float.
<http://nature.example.com/Article1> <http://purl.org/dc/elements/1.1/weight> “1.08”^^xsd:double. 
<http://nature.example.com/Article1> <http://purl.org/dc/elements/1.1/onsale> “false”^^xsd:boolean. 
<http://nature.example.com/Article1> <http://purl.org/dc/elements/1.1/publicationDate> “2016-03-08”^^xsd:date) 
<http://nature.example.com/Article1> <http://purl.org/dc/elements/1.1/publicationTime> “2016-03-08T10:10:10”^^xsd:dateTime) 
<http://nature.example.com/Article2> <http://purl.org/dc/elements/1.1/title> “A review of ABC”^^xsd:string.
<http://nature.example.com/Article2> <http://purl.org/dc/elements/1.1/creator> “Joe Bloggs”^^xsd:string.
<http://nature.example.com/Article1> <http://purl.org/dc/terms/references> <http://nature.example.com/Article2>.

前述のコードは次のような出力を生成します。内部RDFリソースID値は、異なるOracleデータベースの間では変動する可能性があります。

------ Vertices from property graph view ------
Vertex ID 7299961478807817799 {creator:str:Jane Smith, onsale:bol:false, publicationDate:dat:Mon Mar 07 16:00:00 PST 2016, publicationTime:dat:Tue Mar 08 02:10:10 PST 2016, serialnumber:dbl:123456.0, title:str:All about XYZ, weight:dbl:1.08, width:flo:10.5}
Vertex ID 7074365724528867041 {creator:str:Joe Bloggs, title:str:A review of ABC}
------ Edges from property graph view ------
Edge ID 1 from Vertex ID 7299961478807817799 {creator:str:Jane Smith, onsale:bol:false, publicationDate:dat:Mon Mar 07 16:00:00 PST 2016, publicationTime:dat:Tue Mar 08 02:10:10 PST 2016, serialnumber:dbl:123456.0, title:str:All about XYZ, weight:dbl:1.08, width:flo:10.5} =[references]=> Vertex ID 7074365724528867041 {creator:str:Joe Bloggs, title:str:A review of ABC} edgeKV[{weight:dbl:0.5}]

2.11 Oracleフラット・ファイル形式の定義

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

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

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

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

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

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

2.11.2 エッジ・ファイル

エッジ・ファイルの各行は、プロパティ・グラフの1つのエッジを記述する1つのレコードです。1つのレコードはエッジの1つのキー値プロパティを記述できるので、複数のプロパティを含むエッジを記述する場合は複数のレコードが使用されます。

レコードには、カンマで区切られた9つのフィールドが含まれています。各レコードには、値があるかどうかに関係なく、すべてのフィールドを区切るために8つのカンマが含まれている必要があります。

edge_ID, source_vertex_ID, destination_vertex_ID, edge_label, key_name, value_type, value, value, value

次の表では、エッジ・ファイルのレコードを構成するフィールドについて説明します。

表2-2 エッジ・ファイルのレコードの形式

フィールド番号 名前 説明

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 Integer
  • 3 Float
  • 4 Double
  • 5 Timestamp (date)
  • 6 Boolean
  • 7 Long integer
  • 8 Short integer
  • 9 Byte
  • 10 Char
  • 20 Spatial
  • 101 Serializable 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'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.outputEdgeRecord(os, eid, svid, dvid, label, key, value)ユーティリティ・メソッドを使用して、エッジ・レコードをOracleフラット・ファイル形式で直接直列化できます。このメソッドでは、特殊文字のエンコーディングについて心配する必要はありません。このメソッドは、eidによって識別される特定のエッジのキー/値プロパティを記述する新しいテキスト行を特定の出力ストリーム内に書き込みます。

例2-2 OraclePropertyGraphUtils.outputEdgeRecordの使用

この例では、OraclePropertyGraphUtils.outputEdgeRecordを使用して、ラベルfriendOfを使用して頂点1と2の間にエッジ100の新しい行を2本書き込んでいます。

OutputStream os = new FileOutputStream("./example.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();

生成される出力ファイルの1行目では、プロパティ「since (year)」が値2009を使用して記述され、2行目および次の行でエッジの重みが1に設定されています。

% cat example.ope
100,1,2,friendOf,since%20(year),2,,2009,
100,1,2,friendOf,weight,2,,1,

2.11.3 頂点ファイル

頂点ファイルの各行は、プロパティ・グラフの1つの頂点を記述する1つのレコードです。1つのレコードは1つの頂点のキー値プロパティを記述できるので、複数のプロパティを持つ頂点を記述する場合は複数のレコード/行が使用されます。

レコードには、カンマで区切られたフィールドが含まれています。各レコードには、値があるかどうかに関係なく、最初の6つのフィールドを区切るために5つのカンマが含まれている必要があります。オプションの7番目のフィールドを(カンマで6番目のフィールドから区切って)追加して、頂点のラベルを定義できます。

vertex_ID, key_name, value_type, value, value, value, vertex_label

次の表では、頂点ファイルのレコードを構成するフィールドについて説明します。

表2-3 頂点ファイルのレコードの形式

フィールド番号 名前 説明

1

vertex_ID

頂点を一意に識別する整数

2

key_name

キー値ペアのキーの名前

頂点にプロパティが指定されていない場合は、空白(%20)を入力します。この例ではプロパティが指定されていない頂点1について説明します。

1,%20,,,,

3

value_type

キー値ペアの値のデータ型を表す整数。

  • 1 String
  • 2 Integer
  • 3 Float
  • 4 Double
  • 5 Timestamp (date)
  • 6 Boolean
  • 7 Long integer
  • 8 Short integer
  • 9 Byte
  • 10 Char
  • 20 地理空間座標、線、ポリゴン、またはWell-Known Text (WKT)リテラルにできる空間データ
  • 101 Serializable 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));

7

vertex_label

頂点のオプションのエンコードされたラベルで、頂点のタイプまたはカテゴリを示すために使用できます。

頂点の必須グループ化: 1つの頂点には複数のプロパティを指定でき、頂点ファイルには、頂点IDとその頂点の1つのプロパティの組合せごとに1つのレコード(フラット・ファイル内の単一テキスト行によって表される)が含まれます。頂点ファイルでは、各頂点のすべてのレコードがまとめてグループ化されている(つまり、他の頂点のレコードが間に入っていない)必要があります。これは任意の方法で行えますが、便利な方法は、頂点ファイルのレコードを頂点ID別に昇順(または降順)にソートすることです(ただし、頂点ファイルのすべてのレコードを頂点ID別にソートする必要があるわけではありません。これはグループ化要件を満たすための単なる1つの方法です)。

Oracleフラット・ファイル形式でエッジ・ファイルを構築する場合、頂点プロパティ名と値フィールドが適切にエンコードされていることを確認することが重要です(特に特殊文字のエンコーディングを参照)。エンコーディングを簡素化するには、OraclePropertyGraphUtils.escape Java APIを使用できます。

OraclePropertyGraphUtils.outputVertexRecord(os, vid, key, value)ユーティリティ・メソッドを使用して、頂点レコードをOracleフラット・ファイル形式で直接直列化できます。このメソッドでは、特殊文字のエンコーディングについて心配する必要はありません。このメソッドは、vidによって識別される特定の頂点のキー/値プロパティを記述する新しいテキスト行を特定の出力ストリーム内に書き込みます。

例2-3 OraclePropertyGraphUtils.outputVertexRecordの使用

この例では、OraclePropertyGraphUtils.outputVertexRecordを使用して、頂点1に2つの新しい行を書き込んでいます。

OutputStream os = new FileOutputStream("./example.opv");
long vid = 1;
String label = "person";
OraclePropertyGraphUtils.outputVertexRecord(os, vid, label, "name", "Robert Smith");
OraclePropertyGraphUtils.outputVertexRecord(os, vid, label, "birth year", 1961);
os.flush();
os.close();

生成される出力ファイルの1行目では、値「Robert Smith」を使用してプロパティ名を記述し、2行目はその出生年の1961年を記述しています。

% cat example.opv
1,name,1,Robert%20OSmith,,,person
1,birth%20year,2,,1961,,person

2.11.4 特殊文字のエンコーディング

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

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

特殊文字 文字列のエンコーディング 説明

%

%25

パーセント

\t

%09

タブ

(空白)

%20

スペース

\n

%0A

改行

\r

%0D

復帰

,

%2C

カンマ

2.11.5 Oracleフラット・ファイル形式のプロパティ・グラフの例

Oracleフラット・ファイル形式でのプロパティ・グラフの例を次に示します。この例では、2つの頂点(JohnとMary)と、JohnがMaryの友人であることを示す1つのエッジがあります。

%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,,,,

2.11.6 Oracleデータベース表からOracle定義のプロパティ・グラフ・フラット・ファイルへの変換

グラフの頂点とエッジを表すOracleデータベース表を、Oracle定義のフラット・ファイル形式(ファイルの拡張子が.opvおよび.ope)に変換します

Oracleデータベース表に格納されたグラフ・データがある場合、Java APIメソッドを使用して、そのデータをフラット・ファイルに変換し、後でプロパティ・グラフとしてOracleデータベースへロードできます。これにより、既存のOracleデータベース表からフラット・ファイルを生成するための、その他の手動アプローチを使用する必要性がなくなります。

グラフの頂点を格納している表の.opvファイルへの変換

エンティティ(グラフの頂点として表すことができる)を含むOracleデータベース表を、.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"は、IDが1101で属性がname/"Jean", age/20, salary/120.0である頂点に変換されます。オフセット1000lが適用されるため、元のempID 101と頂点ID 1101の間にはオフセットがあります。オフセットはグラフ要素のID値の衝突を避けるのに有用です。

グラフのエッジを格納している表の.opeファイルへの変換

エンティティの関係(グラフのエッジとして表すことができる)を含むOracleデータベース表を、.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"は、IDが100001で頂点1101から頂点1102にリンクしているエッジに変換されます。このエッジは属性since/"2015-05-10T00:00:00.000-07:00"を持ちます。オフセット10000lが適用されるため、元のrelationID "90001"とエッジID "100001"の間にはオフセットがあります。同様に、オフセット1000lが出力および入力頂点IDに適用されます。

2.11.7 頂点およびエッジのCSVファイルからOracle定義のプロパティ・グラフ・フラット・ファイルへの変換

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

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

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

次のサブトピックで、頂点およびエッジの変換手順を示します。

  • 頂点: CSVファイルのOracle定義フラット・ファイル形式(.opv)への変換

  • エッジ: CSVファイルのOracle定義フラット・ファイル形式(.ope)への変換

どちらの手順も非常に似ていますが、頂点に固有、およびエッジに固有という違いがあります。

頂点: CSVファイルのOracle定義フラット・ファイル形式(.opv)への変換

CSVファイルにヘッダーが含まれていない場合、すべての属性名(その値のデータ型にマップされる)を記述しているColumnToAttrMapping配列を、CSVファイルに現れるのと同じ順番で、指定する必要があります。さらに、頂点のIDなどの特別な列を含む、CSVファイルからの列はすべて、配列で記述される必要があります。同じCSVファイルの最初の行に列のヘッダーを指定する場合、このパラメータはnullに設定する必要があります。

列を表しているCSVファイルを変換するには、いずれかのconvertCSV2OPV APIを使用することができます。これらのAPIのうち最も単純なものには次が必要です。

  • CSVファイルから頂点を読み取るためのInputStream

  • 頂点IDを表している列の名前(この列はCSVファイルにある必要があります)

  • VIDに追加する整数オフセット(オフセットはグラフ要素のID値の衝突を避けるのに有用です)

  • ColumnToAttrMapping配列(ヘッダーがファイルで指定されている場合、これはnullである必要があります)

  • 並列度(DOP)

  • 変換の前にオフセットを示す整数(スキップする頂点のレコード数)

  • 頂点フラット・ファイル(.opv)が書き込まれるOutputStream

  • オプションで、変換の進捗をトラッキングし、エラーの発生時に何を実行するかを決定するのに使用できるDataConverterListener

追加のパラメータは、CSVファイルの別の形式を指定するのに使用できます。

  • レコードのトークンを区切るのに使用する区切り文字。デフォルトはカンマ文字','です。

  • 文字列値を引用するのに使用され、カンマなどの特殊文字を含めることができる、引用符。文字列値そのものに引用符が表れた場合、重複か、またはバックスラッシュ文字'\'をその前に配置することのいずれかで、エスケープする必要があります。次に例を示します。

    • """Hello, world"", the screen showed…"

    • "But Vader replied: \"No, I am your father.\""

  • 日付値を解析するのに使用する日付書式。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に設定されていると、改行文字または引用符が値として含まれているファイル内のすべての文字列は、引用符で囲まれる必要があります。

    • "The first lines of Don Quixote are:""In a village of La Mancha, the name of which I have no desire to call to mind""."

次のコード・フラグメントは、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ファイルのOracle定義フラット・ファイル形式(.ope)への変換

CSVファイルにヘッダーが含まれていない場合、すべての属性名(その値のデータ型にマップされる)を記述しているColumnToAttrMapping配列を、CSVファイルに現れるのと同じ順番で、指定する必要があります。さらに、適用される場合はエッジのID、必要なSTART_ID、END_ID、TYPEなどの特別な列を含む、CSVファイルからの列はすべて、配列で記述される必要があります。同じCSVファイルの最初の行に列のヘッダーを指定する場合、このパラメータはnullに設定する必要があります。

列を表しているCSVファイルを変換するには、いずれかのconvertCSV2OPE APIを使用することができます。これらの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"", the screen showed…"

    • "But Vader replied: \"No, I am your father.\""

  • 日付値を解析するのに使用する日付書式。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に設定されていると、改行文字または引用符が値として含まれているファイル内のすべての文字列は、引用符で囲まれる必要があります。

    • "The first lines of Don Quixote are:""In a village of La Mancha, the name of which I have no desire to call to mind""."

次のコード・フラグメントは、APIを使用して、CSVファイルを.opeファイルとnullのColumnToAttrMapping配列に変換する方法を示します。

    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,