Oracle Database 23aiのプロパティ・グラフ: SQL/PGQ標準 (2025/03/20)

Oracle Database 23aiのプロパティ・グラフ: SQL/PGQ標準 (2025/03/20)

https://blogs.oracle.com/database/post/property-graphs-in-oracle-database-23ai-the-sql-pgq-standard

投稿者: Oskar van Rest | Consulting Member of Technical Staff


SQLプロパティ・グラフ問合せ(SQL/PGQ)は、プロパティ・グラフを作成および問合せできるISO/IEC SQL標準への新しい追加です。2023年6月に公開されたSQL Standard、SQL:2023の最新バージョンのパート16です。「SQL:2023 Standardの一般提供の発表」を参照してください。SQL/PGQは、Oracle Database 23aiのリリースでOracle Databaseで使用可能になりました。


Oracleは、標準ベースの製品とプロパティ・グラフをSQLで構築することにコミットしています。Oracleは、標準化の取り組みを先導しただけでなく、Oracle Database 23aiの一部として、市販の最初のSQL/PGQ実装を導入しました。プロパティ・グラフはSQLに深く統合され、Oracleのコンバージド・データベースの不可欠な要素となります。



SQLにプロパティ・グラフがある理由


プロパティ・グラフのユースケースは多数あります。これには、不正検出(不正リング検出など)、ソーシャル・ネットワーク分析(コミュニティ検出など)、サプライチェーンとロジスティクス(最短経路の検索、ネットワーク中断の影響分析)、通信(顧客離れ分析)、医療(患者ジャーニー分析)、サイバーセキュリティ(攻撃パス分析)などがあります。これらのユースケースの多くでは、可変数のリンクまたは接続(基本的にリレーショナル・データベース内の可変数の結合)をトラバースする必要があります。Oracle Databaseでの再帰的WITHおよびCONNECT BYは、すでにこれを実行できていましたが、SQLでのネイティブ・グラフのサポートにより、あらゆる種類のグラフ問合せを非常に直接的かつ直感的に表現できます。また、ユーザーの意図をより正確にシステムに認識させることで、グラフ固有の評価戦略とパフォーマンスの最適化が可能になります。


グラフを問い合せるためのその他の言語が存在します。ISO/IEC GQLおよびW3C SPARQLは、それぞれプロパティ・グラフおよびRDFグラフの標準ですが、Oracle PGQL、Neo4j Cypher、TigerGraph GSQLおよびApache TinkerPop Gremlinは独自のプロパティ・グラフ問合せ言語です(SQLおよびPGQLを使用したグラフの問合せ: 違いは何ですか?を参照)。SQLをこれらのグラフ固有の言語とは別に設定するのは、リレーショナル・モデルとの緊密な統合です。SQLのプロパティ・グラフは、既存の表上にあるビューのようなオブジェクトです。そのため、すでに多くのデータが表に格納されているため、データをレプリケートする必要はありません。既存のデータは1箇所に安全に保管できますが、プロパティ・グラフとして問い合せることもできます。さらに、プロパティ・グラフ問合せは常に最新のデータに対して実行されます。さらに、同じデータをアプリケーションの1つのコンポーネントでリレーショナル・データとして使用し、別のコンポーネントでグラフ・データとして使用できます。Oracleのコンバージド・データベースは、このマルチモデル設計を完全に採用し、プロパティ・グラフをSQLおよび他のデータベース・エコシステムにシームレスに統合します。プロパティ・グラフ問合せをリレーショナル問合せと組み合せることができるだけでなく、JSON問合せ、ベクトル検索、空間問合せ、およびデータベース内のその他の機能と組み合せることもできます。


SQLには開発者やツールの膨大なエコシステムがあり、SQL/PGQは、プロパティ・グラフを作成してSQL開発者の手に渡す機能を即座に利用できます。さらに、プロパティ・グラフの操作にはSQLをサポートするツールを使用できるため、お気に入りのツールを使用してプロパティ・グラフを操作できます。プロパティグラフは、特殊な言語の知識を必要とする専門技術から、アプリケーションに広く統合できる技術に移行できます。



SQLへのプロパティ・グラフの統合


プロパティ・グラフは、SQLにシームレスに統合されます。


  • プロパティ・グラフは、表、ビューおよびその他のスキーマ・オブジェクトとともにSQLスキーマ内に存在します。これらの定義は、他のタイプのオブジェクトの定義とともにデータ・ディクショナリに格納されます。新しいディクショナリ・ビューは、このプロパティ・グラフ・メタデータへのアクセスを提供します。
  • プロパティ・グラフは、使い慣れたGRANTおよびREVOKE文で管理される権限を持つSQLのセキュリティ・モデルの一部です。
  • 頂点およびエッジ・プロパティのデータ型には、Oracle Database 23aiの新しいJSONおよびVECTOR型を含む、任意の既存のSQLデータ型を指定できます。
  • GRAPH_TABLEは、特定のグラフに対してグラフ問合せ(パターン)を実行し、通常のSQLでさらに処理するために表形式で一致を返すFROM句の新しい演算子です。
  • GRAPH_TABLE内のWHERE句およびCOLUMNS句は、SQLの他の場所にあるものと同じ演算子、関数および述語を使用します。
  • JSON型の頂点およびエッジ・プロパティには、単純なJSONドット表記法構文を使用できます。
  • グラフは、基礎となる表に対する更新が行われると、トランザクション上一貫した方法で問い合せられます。
  • Oracle Database 23aiでは、AS OF句をグラフ名の後に配置して、特定のタイムスタンプまたはSCNでグラフを問い合せることができます。
  • 既存のSQL機能はすべて、GROUP BY、行パターン一致、ウィンドウ/分析関数などのグラフと組み合せて使用できます。
  • 表、ビューおよびグラフのデータは、1つの問合せ内で結合できます。



CREATE PROPERTY GRAPH文およびGRAPH_TABLE問合せの例


次の文では、3つの既存の表(パーソン、アカウントおよび転送)の上にbank_graphという名前のプロパティ・グラフが作成されます。これらの表に対するCREATE TABLEおよびINSERT文は、このブログ投稿の末尾にあります。


CREATE PROPERTY GRAPH bank_graph
  VERTEX TABLES (
    persons AS person,
    accounts AS account
  )
  EDGE TABLES (
    transfers AS transfer
      SOURCE KEY (from_account) REFERENCES account (account_number)
      DESTINATION KEY (to_account) REFERENCES account (account_number)
      PROPERTIES (transfer_id, time, amount),
    accounts AS owner
      SOURCE KEY (account_number) REFERENCES account (account_number)
      DESTINATION person
      NO PROPERTIES
  );


グラフには、personおよびaccountという名前の2つの頂点表と、transferおよびownerという名前の2つのエッジ表があります。頂点表内の各行はグラフの頂点になり、エッジ表内の各行はグラフのエッジになります。頂点表とエッジ表には1つ以上のラベルがあり、各ラベルには任意の数のプロパティを指定できます。ラベルが指定されていない場合、デフォルトが適用されます。つまり、この例(person、account、transfer、owner)のように、頂点とエッジは要素テーブル名に対応する単一のラベルを持つことになります。また、この例では、プロパティはエッジに対して指定され、デフォルトは頂点に対して適用されます。つまり、プロパティはすべての列です。主キーが基礎となる表で定義されている場合は、頂点とエッジのキーを自動的に推測するために使用できます。また、外部キーが定義されている場合は、外部キーを使用して、エッジのソースと宛先を自動的に推測できます。この例では、頂点およびエッジ・キーが主キーから推測され、エッジ表所有者の宛先のキーが既存の外部キーから推測されるため、そのエッジ表に対するREFERENCES句が省略されます。


作成後は、SQL問合せのFROM句に配置された新しいGRAPH_TABLE演算子を使用して、プロパティ・グラフを問い合せることができます。GRAPH_TABLEは、グラフを入力として取得し、グラフ・パターン一致を実行して、出力として表を返します。たとえば、次の問合せでは、Camilleが仲介業者を介して直接的または間接的に資金を振り替えた人を見つけます。

SELECT *
FROM GRAPH_TABLE ( bank_graph
       MATCH (p1 IS person) <-[IS owner]- (a1 IS account),
             (a1) -[e IS transfer]->{1,2} (a2 IS account),
             (a2) -[IS owner]-> (p2 IS person)
       WHERE p1.first_name = 'Camille'
       COLUMNS (p2.first_name, p2.last_name,
                p2.more_data.address.address_line_1.string() AS street,
                COUNT(e.transfer_id) AS path_length,
                JSON_ARRAYAGG(e.amount) AS amounts))
ORDER BY path_length, amounts;

グラフ・パターンに一致するたびに、問合せによって次のものが返されます。


  • カミーユが仲介業者を介して直接または間接的に送金した個人の名、姓および番地。
  • その個人への転送パスに沿った転送の数: 直接転送の場合は1、中間を介した間接転送の場合は2。
  • 転送パスに沿ったトランザクション金額をJSON配列として指定します。


結果は次のとおりです。

FIRST_NAME LAST_NAME  STREET                     PATH_LENGTH AMOUNTS
---------- ---------- -------------------------- ----------- -------------
Nikita     Ivanov     1 Boolean Boulevard                  1 [1000]
Jake       Zimmerman  500 Property Graph Parkway           2 [1000,1500.3]
Jake       Zimmerman  500 Property Graph Parkway           2 [1000,3000]


JSONによるスキーマの柔軟性


従来、グラフ・データベースはスキーマレスですが、Oracle DatabaseなどのSQLデータベースは本質的にスキーマ駆動型です。ただし、SQLでは、JSON (およびXML)を使用したグラフに対して柔軟なスキーマ機能が提供されます。


  • 頂点およびエッジ・プロパティのタイプはJSONです。これは、JSON用に最適化されたネイティブ・バイナリ・ストレージ形式であるOSONに基づく新しいデータ型です。
  • JSON型の頂点およびエッジ・プロパティには、単純なJSONドット表記法構文を使用できます。次の例では、ネストされたJSONオブジェクトから数値(zip_code)を取得し、それをOracle NUMBERと比較します: WHERE vertex.json_property.address.zip_code = 94065。
  • Oracle Database 23aiでは、JSON列のJSONスキーマ定義をサポートして、JSONドキュメントの構造と内容を検証します。デフォルトでは、特に指定されていないかぎり拡張可能なままになるように、最小要件のみが検証されます。プロパティ・グラフは、このようなJSONスキーマがアタッチされた列を持つ表の上に作成できます。


グラフとJSONを組み合わせることで、SQLは型の安全性と柔軟性に関して、両者の長所を最大限に引き出します。プロパティ・グラフは本質的にスキーマ駆動型であり、デフォルトでタイプの安全性を確保します。たとえば、ラベルまたはプロパティ名に誤字があると、空の結果が返されるのではなくエラーがトリガーされます。一方、JSONは、必要に応じてプロパティ・グラフの柔軟性と動的型付けを提供します。



Oracle Database 23aiのSQLプロパティ・グラフのドキュメント


Oracle Database 23aiでのプロパティ・グラフのサポートは、次の場所で説明されています。



CREATE TABLEおよびINSERT文の例


次の文は、前述の例を実行するために必要なデータを作成します。


CREATE TABLE persons (
  person_id NUMBER PRIMARY KEY,
  first_name VARCHAR2(200),
  last_name VARCHAR2(200),
  more_data JSON
);

INSERT INTO persons VALUES (
  1, 'Camille', 'Nichols', '{"address":{"address_line_1":"101 Ellison Avenue",
                                        "zip_code":10001,
                                        "city":"Larry Islands",
                                        "state":"AL"}}');
INSERT INTO persons VALUES (
  2, 'Jake', 'Zimmerman', '{"address":{"address_line_1":"500 Property Graph Parkway",
                                       "zip_code":75002,
                                       "city":"Oracle City",
                                       "state":"AK"}}');
INSERT INTO persons VALUES (
  3, 'Nikita', 'Ivanov', '{"address":{"address_line_1":"1 Boolean Boulevard",
                                      "zip_code":48201,
                                      "city":"Vectorville",
                                      "state":"AZ"}}');
INSERT INTO persons VALUES (
  4, 'Liam', 'O''Connor', '{"address":{"address_line_1":"16 SQL Street",
                                       "zip_code":9075,
                                       "city":"Json Town",
                                       "state":"CA"}}');

CREATE TABLE accounts (
  account_number NUMBER PRIMARY KEY,
  owner_id NUMBER,
  creation_date TIMESTAMP,
  FOREIGN KEY (owner_id) REFERENCES persons (person_id)
);

INSERT INTO accounts VALUES (1001, 2, TIMESTAMP '2000-01-01 14:31:00');
INSERT INTO accounts VALUES (2090, 4, TIMESTAMP '2004-12-15 08:15:00');
INSERT INTO accounts VALUES (8021, 3, TIMESTAMP '2005-03-20 10:45:00');
INSERT INTO accounts VALUES (10039, 1, TIMESTAMP '2020-12-15 14:17:00');

CREATE TABLE transfers (
  transfer_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  from_account NUMBER,
  to_account NUMBER,
  time TIMESTAMP,
  amount NUMBER(10,2)
);

INSERT INTO transfers (from_account, to_account, time, amount)
  VALUES (10039, 8021, TIMESTAMP '2024-03-12 14:30:00', 1000.00);
INSERT INTO transfers (from_account, to_account, time, amount)
  VALUES (8021, 1001, TIMESTAMP '2024-03-12 16:30:00', 1500.30);
INSERT INTO transfers (from_account, to_account, time, amount)
  VALUES (8021, 1001, TIMESTAMP '2024-03-12 16:31:00', 3000.00);
INSERT INTO transfers (from_account, to_account, time, amount)
  VALUES (1001, 2090, TIMESTAMP '2024-03-12 19:03:00', 9999.50);
INSERT INTO transfers (from_account, to_account, time, amount)
  VALUES (2090, 10039, TIMESTAMP '2024-03-12 19:45:00', 9900.00);

コメント

このブログの人気の投稿

Oracle Database 19cサポート・タイムラインの重要な更新 (2024/11/20)

Oracle GoldenGate 23aiでMicrosoft Fabricでのオープン・ミラーリングがサポートされるようになりました (2024/11/19)

Oracle APEX 24.1の一般提供の発表 (2024/06/17)