4.6.1 同期の例

次の例を使用して、グラフの同期を実行できます。

例4-5 CREATE PROPERTY GRAPH文を使用したグラフの同期

  1. 次のOracle Database表(PERSONSおよびFRIENDSHIPS)があるとします。
    CREATE TABLE persons (
        person_id NUMBER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
        name VARCHAR2(200),
        birthdate DATE,
        height FLOAT DEFAULT on null 0,
        CONSTRAINT person_pk PRIMARY KEY (person_id)
    );
     
    CREATE TABLE friendships (
      friendship_id NUMBER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
      person_a NUMBER,
      person_b NUMBER,
      meeting_date DATE,
      CONSTRAINT fk_person_a_id FOREIGN KEY (person_a) REFERENCES persons(person_id),
      CONSTRAINT fk_person_b_id FOREIGN KEY (person_b) REFERENCES persons(person_id)
      CONSTRAINT fs_pk PRIMARY KEY (friendship_id)
    );
  2. 次に示すように、これらの表にサンプル・データをいくつか追加できます。
    INSERT INTO persons (name, height, birthdate) VALUES ('John', 1.80, to_date('13/06/1963', 'DD/MM/YYYY'));
    INSERT INTO persons (name, height, birthdate) VALUES ('Mary', 1.65, to_date('25/09/1982', 'DD/MM/YYYY'));
    INSERT INTO persons (name, height, birthdate) VALUES ('Bob', 1.75, to_date('11/03/1966', 'DD/MM/YYYY'));
    INSERT INTO persons (name, height, birthdate) VALUES ('Alice', 1.70, to_date('01/02/1987', 'DD/MM/YYYY'));
     
    INSERT INTO friendships (person_a, person_b, meeting_date) VALUES (1, 3, to_date('01/09/1972', 'DD/MM/YYYY'));
    INSERT INTO friendships (person_a, person_b, meeting_date) VALUES (2, 4, to_date('19/09/1992', 'DD/MM/YYYY'));
    INSERT INTO friendships (person_a, person_b, meeting_date) VALUES (4, 2, to_date('19/09/1992', 'DD/MM/YYYY'));
    INSERT INTO friendships (person_a, person_b, meeting_date) VALUES (3, 2, to_date('10/07/2001', 'DD/MM/YYYY'));
    
  3. 次のJavaコードの例に示すように、これらの表をグラフとしてロードする方法を示す、対応するCREATE PROPERTY GRAPH文を記述します。
    session.executePgql(
        "CREATE PROPERTY GRAPH friends VERTEX TABLES ("
            + "  persons KEY (person_id) LABEL person PROPERTIES (name,height,birthdate)"
            + ")"
            + "EDGE TABLES ("
            + "  friendships "
            + "    KEY (friendship_id) "
            + "    SOURCE KEY (person_a) REFERENCES persons "
            + "    DESTINATION KEY (person_b) REFERENCES persons "
            + "    LABEL friendof PROPERTIES (meeting_date)"
            + ")"
    );
    PgxGraph graph = session.getGraph("friends");

    これにより、メモリーにロードされるグラフのスナップショットが作成されます。これで、グラフに対してアルゴリズムおよび問合せを実行できるようになります。

  4. ここで、データベースの入力表のデータを変更します。たとえば、新しい個人をPERSONS表に追加し、別のエッジも追加します。

    次のコードに示すように、データベースへの新しいJDBC接続を開き、いくつかのINSERT文を実行できます。

    Connection conn = DriverManager.getConnection("<jdbc-url>", "<user>", "<pass>");
    conn.createStatement().executeQuery("INSERT INTO persons(name, birthdate, height) VALUES ('Mariana',to_date('21/08/1996','DD/MM/YYYY'),1.65)");
    conn.createStatement().executeQuery("INSERT INTO persons (name, birthdate, height) VALUES ('Francisco',to_date('13/06/1963','DD/MM/YYYY'),1.75)");
    conn.createStatement().executeQuery("INSERT INTO friendships (person_a, person_b, meeting_date) VALUES (1, 6, to_date('13/06/2013','DD/MM/YYYY'))");
    conn.commit();

    データベースの変更をコミットすると、メモリー内のグラフがデータベースのソース表と同期しなくなります。

  5. 次のコードに示すように、新しいシンクロナイザ・オブジェクトを作成することで、インメモリー・グラフとデータベースを同期できます。
    Synchronizer synchronizer = new Synchronizer.Builder<FlashbackSynchronizer>()
        .setType(FlashbackSynchronizer.class)
        .setGraph(graph)
        .setConnection(conn)
        .build();
    内部的に、グラフ・サーバーは、現在のグラフ・スナップショットが属するOracleシステム変更番号(SCN)をトラッキングします。シンクロナイザはデータベースに接続するクライアント側コンポーネントとして、フラッシュバック・メカニズムを介して現在のSCNを使用して元の入力表の状態を比較することで変更を検出し、その後、変更セットAPIを使用して、グラフ・サーバーにすべての変更を送信します。これを行うには、シンクロナイザによって、データベースへの接続方法(connパラメータ)および同期を維持するグラフ(graphパラメータ)が認識される必要があります。
    • または、次の同等のショートカットを使用することもできます。
      Synchronizer synchronizer = graph.createSynchronizer(FlashbackSynchronizer.class, conn);
  6. sync()操作をコールして、データベース変更をフェッチし、新しいインメモリー・スナップショットを作成します。
    graph = synchronizer.sync();

    2つの新しい頂点と新しいエッジがグラフに適用されていることがわかります。

    graph ==> PgxGraph[name=FRIENDS,N=6,E=5,created=1594754376861]

    変更のフェッチおよび適用の分割

    前述のコードでsynchronizer.sync()を呼び出すと、1回のコールで変更のフェッチと適用が行われます。しかし、このプロセスを別個の fetch()呼出しとapply()呼出しに分割することで、より複雑な更新ロジックをエンコードできます。次に例を示します。

    synchronizer.fetch() // fetches changes from the database
    if (synchronizer.getGraphDelta().getTotalNumberOfChanges() > 100) {  // only create snapshot if there have been more than 100 changes
      synchronizer.apply()
    }

例4-6 グラフ構成オブジェクトを使用して作成されたグラフの同期

例4-5では、CREATE PROPERTY GRAPH文を使用して、より高度なグラフ構成のオプションの一部を非表示にするグラフを作成します。

グラフ構成オブジェクトを使用して作成されたグラフの同期は一般的にサポートされていますが、次のいくつかの制限が適用されます。

  • すべてのプロバイダがデータベース表であるパーティション化されたグラフ構成のみがサポートされます。
  • 各エッジまたは頂点プロバイダ、あるいはその両方で、ユーザー名フィールドを設定して表の所有者を指定する必要があります。たとえば、ユーザーSCOTTが表を所有している場合は、その表のプロバイダ・ブロックにユーザー名を適宜設定します。
    "username": "scott"
  • ルート・ロード・ブロックで、スナップショット・ソースをchange_setに設定する必要があります。
    "loading": {
      "snapshots_source": "change_set"
    }
  • 多くのスナップショットを作成する際にメモリーが不足しないように、"optimized_for"フィールドを"updates"に設定することをお薦めします。
    "optimized_for": "updates"

例4-5に示す同じグラフをロードするには、次のグラフ構成(JSON)ファイルを使用します。

{
  "name": "friends",
  "optimized_for": "updates",
  "vertex_id_strategy": "partitioned_ids",
  "edge_id_strategy": "partitioned_ids",
  "edge_id_type": "long",
  "vertex_id_type": "long",
  "jdbc_url": "<jdbc_url>",
  "username": "<username>",
  "keystore_alias": "<keystore_alias>",
  "vertex_providers": [
    {
      "format": "rdbms",
      "username": "<username>",
      "key_type": "long",
      "name": "person",
      "database_table_name": "persons",
      "key_column": "person_id",
      "props": [
        ...
      ],
      "loading": {
        "create_key_mapping": true
      }
    }
  ],
  "edge_providers": [
    {
      "format": "rdbms",
      "username": "<username>",
      "name": "friendOf",
      "source_vertex_provider": "person",
      "destination_vertex_provider": "person",
      "database_table_name": "friendships",
      "source_column": "person_a",
      "destination_column": "person_b",
      "key_column": "friendship_id",
      "key_type":"long",
      "props": [
        ...
      ],
      "loading": {
        "create_key_mapping": true
      }
    }
  ],
  "loading": {
    "snapshots_source": "change_set"
  }
}

ノート:

  • 前述のJSONファイルで、値<jdbc_url><username>および<keystore_alias>を、データベースに接続するための値に置き換えます。

  • グラフ構成ファイルを使用する場合、JShellを使用してグラフをメモリーにロードできます(起動時にデータベース・パスワードを含むキーストアを必ず登録してください)。
    var pgxGraph = session.readGraphWithProperties("<name_of_config_file>.json");