11 プロパティ・グラフ問合せ言語(PGQL)
PGQLは、頂点からなり、エッジにより別の頂点に接続され、それぞれが関連付けられたキー値ペア(プロパティ)を持つことができる、プロパティ・グラフ・データ構造のためのSQLライクな問合せ言語です。
この言語はグラフ・パターン一致の概念に基づき、データ・グラフの頂点およびエッジに対し一致するパターンを指定することができます。
プロパティ・グラフ・サポートでは、Java APIを介してプロパティ・グラフ問合せ言語(PGQL)の問合せを実行するための2つの方法が提供されています。
-
「グラフ・サーバー(PGX)に対するPGQL問合せの実行」で説明されているように、
oracle.pgx.apiJavaパッケージを使用して、グラフ・サーバー(PGX)にロードされているグラフのインメモリー・スナップショットを問い合せます。 -
oracle.pg.rdbms.pgqlJavaパッケージを使用して、Oracle Databaseに格納されたグラフ・データを直接問い合せます。詳細は、「プロパティ・グラフ・ビューに対するPGQL問合せの実行」および「SQLプロパティ・グラフに対するPGQL問合せの実行」を参照してください。
PGQLの詳細は、PGQL Specificationを参照してください。
- PGQLを使用したプロパティ・グラフの作成
- PGQLによるパターン一致
- エッジ・パターンはPGQLによって方向を持つ
- PGQLによる頂点およびエッジ・ラベル
- PGQLによる可変長のパス
- PGQLによる集計およびソート
- プロパティ・グラフ・ビューに対するPGQL問合せの実行
このトピックでは、Oracle Database表のプロパティ・グラフ・ビューに対して直接PGQL問合せを実行する方法について説明します。
親トピック: プロパティ・グラフ・ビュー
11.1 PGQLを使用したプロパティ・グラフの作成
CREATE PROPERTY GRAPHは、データベース表からプロパティ・グラフ・ビュー(PGビュー)を作成するPGQL DDL文です。
CREATE PROPERTY GRAPH文は、グラフに付ける名前で始まり、その後に頂点表とエッジ表のセットが続きます。グラフには、頂点表またはエッジ表がない(空のグラフ)か、頂点表がありエッジ表はない(頂点のみでエッジなしのグラフ)か、頂点表とエッジ表の両方がある(頂点とエッジのあるグラフ)場合があります。ただし、エッジ表のみで頂点表のないグラフは指定できません。
opt/oracle/graph/dataディレクトリのサンプル・グラフ・データを使用して作成されたbank_accountsおよびbank_txnsデータベース表について考えてみます。詳細は、「CSVファイルからのデータのインポート」を参照してください。
- BANK_ACCOUNTSは、列
id、nameが含まれる表です。新しい口座ごとに、この表に行が追加されます。 - BANK_TXNSは、列
txn_id、from_acct_id、to_acct_id、descriptionおよびamountが含まれる表です。from_acct_idからto_acct_idへの新しいトランザクションごとに、この表に行が追加されます。
次のようにデータベース表を使用してPGビューを作成できます:
CREATE PROPERTY GRAPH bank_graph
VERTEX TABLES(
bank_accounts AS accounts
KEY(id)
LABEL accounts
PROPERTIES (id, name)
)
EDGE TABLES(
bank_txns AS transfers
KEY (txn_id)
SOURCE KEY (from_acct_id) REFERENCES accounts (id)
DESTINATION KEY (to_acct_id) REFERENCES accounts (id)
PROPERTIES (description, amount)
) OPTIONS (PG_VIEW)次のグラフの概念については、データベース表をグラフにマップし、前述のPGQL DDL文を使用して説明します:
- 頂点表: データ・エンティティが含まれる表は頂点表です(
bank_accountsなど)。- 頂点表の各行は頂点です。
- 頂点表の列は、頂点のプロパティです。
- 頂点表の名前は、この頂点セットのデフォルト・ラベルです。あるいは、CREATE PROPERTY GRAPH文の一部としてラベル名を指定できます。
- エッジ表: エッジ表は、2つの頂点表をリンクする任意の表、またはソース・エンティティからターゲット・エンティティへのアクションを示すデータを含む表です。たとえば、
FROM_ACCOUNT_IDからTO_ACCOUNT_IDへの送金は自然なエッジです。- 外部キー関係により、データ内で関連しているリンクを知ることができます。CREATE PROPERTY GRAPHは、デフォルトで外部キー関係を使用してエッジを識別します。
- エッジ表のプロパティの一部は、エッジのプロパティにできます。たとえば、
from_acct_idからto_acct_idへのエッジには、プロパティdescriptionおよびamountを指定できます。 - エッジ表の名前は、エッジ・セットのデフォルト・ラベルです。あるいは、CREATE PROPERTY GRAPH文の一部としてラベル名を指定できます。
- キー:
- 頂点表のキー: 頂点表のキーは、グラフ内の一意の頂点を識別します。キーはCREATE PROPERTY GRAPH文で指定できます。指定しない場合、デフォルトで表の主キーになります。表に重複した行がある場合は、CREATE PROPERTY GRAPH文によってエラーが返されます。
- エッジ表のキー: エッジ表のキーは、グラフ内のエッジを一意に識別します。ソースと宛先の頂点を指定すると、KEY句はソースと宛先の頂点キーを一意に識別します。
- 表の別名: 頂点表とエッジ表には一意の名前が付いている必要があります。同じリレーショナル表から複数の頂点表を識別したり、同じリレーショナル表から複数のエッジ表を識別する必要がある場合は、別名を使用する必要があります。たとえば、次のように、1つの表
bank_accountsから2つの頂点表bank_accountsおよびaccountsを作成できます:CREATE PROPERTY GRAPH bank_transfers VERTEX TABLES (bank_accounts KEY(id) bank_accounts AS accounts KEY(id))頂点表とエッジ表のいずれかが同じ名前を共有する場合は、表の別名を再度使用する必要があります。次の例では、同じ名前で参照されている頂点表があるため、エッジ表DEPARTMENTSに表の別名が使用されます。
CREATE PROPERTY GRAPH hr VERTEX TABLES ( employees KEY(employee_id) PROPERTIES ARE ALL COLUMNS, departments KEY(department_id) PROPERTIES ARE ALL COLUMNS ) EDGE TABLES ( departments AS managed_by SOURCE KEY ( department_id ) REFERENCES departments ( department_id ) DESTINATION employees PROPERTIES ARE ALL COLUMNS )OPTIONS (PG_VIEW) - プロパティ: グラフの頂点プロパティおよびエッジ・プロパティはそれぞれ、頂点表およびエッジ表の列から導出され、デフォルトでは基礎となる表の列と同じ名前になります。ただし、列ごとに異なるプロパティ名を選択できます。これは、2つの表の列名が同じでデータ型が異なる場合に競合を回避するのに役立ちます。
次の例では、頂点プロパティ
idおよびnameの名前がそれぞれacct_noおよびacct_nameに変更されます。CREATE PROPERTY GRAPH bank_transfers VERTEX TABLES ( bank_accounts AS accounts LABEL accounts PROPERTIES (id AS acct_no, name AS acct_name) ) - REFERENCES句: エッジのソースおよび宛先の頂点を、対応する頂点表に接続します。
CREATE PROPERTY GRAPH文の詳細は、PGQL Specificationを参照してください。
プロパティ・グラフの作成方法は、次の表を参照してください。
表11-1 CREATE PROPERTY GRAPH文のサポート
| メソッド | 詳細情報 |
|---|---|
oracle.pgx.api Javaパッケージを使用して、グラフ・サーバー(PGX)にプロパティ・グラフを作成する
|
CREATE PROPERTY GRAPH文を実行するためのJava API |
pypgx.api Pythonパッケージを使用して、グラフ・サーバー(PGX)にプロパティ・グラフを作成する
|
CREATE PROPERTY GRAPH文を実行するためのPython API |
| Oracle Database表でプロパティ・グラフ・ビューを作成する | プロパティ・グラフ・ビューの作成 |
親トピック: プロパティ・グラフ問合せ言語(PGQL)
11.2 PGQLによるパターン一致
パターン一致は、MATCH句で1つ以上のパス・パターンを指定することで行われます。単一パス・パターンは頂点およびエッジの線形パスと一致しますが、より複雑なパターンは、複数のパス・パターンをカンマで区切って組み合せることによって一致させることができます。(対応するSQL文に類似した)値式はWHERE句で指定され、通常、頂点およびエッジのプロパティに制約を指定することによって一致をフィルタ処理で除外できます
たとえば、コンピュータ・ネットワーク上のTCP/IP接続のグラフを想定し、誰かが1つのマシンにログインし、そこから別のマシンへ、そこからさらに別のマシンへという場合を検出するとします。次のようなパターンを問合せます。
SELECT id(host1) AS id1, id(host2) AS id2, id(host3) AS id3 /* choose what to return */
FROM MATCH
(host1) -[connection1]-> (host2) -[connection2]-> (host3) /* single linear path pattern to match */
WHERE
connection1.toPort = 22 AND connection1.opened = true AND
connection2.toPort = 22 AND connection2.opened = true AND
connection1.bytes > 300 AND /* meaningful amount of data was exchanged */
connection2.bytes > 300 AND
connection1.start < connection2.start AND /* second connection within time-frame of first */
connection2.start + connection2.duration < connection1.start + connection1.duration
GROUP BY id1, id2, id3 /* aggregate multiple matching connections */
パターン一致のその他の例については、PGQL仕様のWriting simple queriesを参照してください。
親トピック: プロパティ・グラフ問合せ言語(PGQL)
11.3 エッジ・パターンはPGQLによって方向を持つ
エッジ・パターンは、グラフのエッジと同様に方向を持ちます。そのため、(a) <-[]- (b)は、bにはaに向けられたエッジがある場合を指定するのに対し、(a) -[]-> (b)は、逆の方向のエッジを探します。
次の例は、AprilとChrisの共通の友人で両者よりも年上の人を探します。
SELECT friend.name, friend.dob
FROM MATCH /* note the arrow directions below */
(p1:person) -[:likes]-> (friend) <-[:likes]- (p2:person)
WHERE
p1.name = 'April' AND p2.name ='Chris' AND
friend.dob > p1.dob AND friend.dob > p2.dob
ORDER BY friend.dob DESC
エッジ・パターンのその他の例については、PGQL仕様のEdge Patternsを参照してください。
親トピック: プロパティ・グラフ問合せ言語(PGQL)
11.4 PGQLによる頂点およびエッジ・ラベル
ラベルは、グラフのエッジおよびノードにタイプ情報を添付する方法で、すべてのノードが同じものを表しているわけではないグラフの制約に使用することができます。たとえば:
SELECT p.name
FROM MATCH (p:person) -[e1:likes]-> (m1:movie),
MATCH (p) -[e2:likes]-> (m2:movie)
WHERE m1.title = 'Star Wars'
AND m2.title = 'Avatar'
この例では、ラベルpersonの頂点セット、ラベルmovieの頂点セットおよびラベルlikesのエッジ・セットが含まれるグラフを問い合せます。ラベル述語は、コロン(:)またはキーワードISのいずれかで始め、その後に1つ以上のラベルを続けることができます。複数のラベルを使用する場合、ラベルは縦棒(|)で区切られます。
次の問合せは、ラベル述語にキーワードISを使用した前述の問合せの例を示しています。
SELECT p.name
FROM MATCH (p IS person) -[e1 IS likes]-> (m1 IS movie),
MATCH (p IS person) -[e2 IS likes]-> (m2 IS movie)
WHERE m1.title = 'Star Wars'
AND m2.title = 'Avatar'関連項目:
- PGQL仕様のLabel Expressions
- PGQL仕様のLabel Predicates
親トピック: プロパティ・グラフ問合せ言語(PGQL)
11.5 PGQLによる可変長のパス
可変長パス・パターンは、頂点およびエッジの変数と一致するように*のような数量詞を持ちます。PATHマクロを使用すると、名前を参照することにより、MATCH句に任意の回数だけ埋め込むことのできる問合せの開始時に、名前付きパス・パターンを指定できます。次の例は、MarioとLuigiの共通の祖先をすべて検索します。
PATH has_parent AS () -[:has_father|has_mother]-> ()
SELECT ancestor.name
FROM MATCH (p1:Person) -/:has_parent*/-> (ancestor:Person)
, MATCH (p2:Person) -/:has_parent*/-> (ancestor)
WHERE
p1.name = 'Mario' AND
p2.name = 'Luigi'
追加の制約または問合せ結果では使用されない、中間エッジまたはノードの名前は定義する必要がないため、前のパス仕様では、匿名制約の使用も示しています。匿名要素は、[:has_father|has_mother]などの制約を持つことができます。エッジは変数名を取得できません(他の場所で参照されないため)が、制約はされます。
可変長パス・パターン一致のその他の例については、PGQL仕様のVariable-Length Pathsを参照してください。
親トピック: プロパティ・グラフ問合せ言語(PGQL)
11.6 PGQLによる集計およびソート
SQLのように、PGQLは次のサポートがあります。
-
ソリューションのグループを作成するGROUP BY
-
MIN、MAX、SUMおよびAVG集計
-
結果をソートするORDER BY
および、その他の多くのなじみのあるSQL構造がサポートされます。
関連項目:
GROUP BYの詳細は、Grouping and Aggregationを参照してくださいORDER BYの詳細は、Sorting and Row Limitingを参照してください
親トピック: プロパティ・グラフ問合せ言語(PGQL)
11.7 プロパティ・グラフ・ビューに対するPGQL問合せの実行
このトピックでは、Oracle Database表のプロパティ・グラフ・ビューに対して直接PGQL問合せを実行する方法について説明します。
PGQL問合せの実行フローを次の図に示します。
基本的な実行フローは次のとおりです。
- PGQL問合せはJava APIを介してRDBMS上のPGQLに送信されます。
- プロパティ・グラフ・ビューの内部メタデータ表を使用してPGQL問合せがSQL文に変換されます。
- 変換されたSQLは、JDBCによってOracle Databaseに送信されます。
- SQL結果セットは、PGQL結果セットとしてラップされてコール元に返されます。
- PGビューでサポートされているPGQL機能および制限事項
プロパティ・グラフ・ビュー(PGビュー)でサポートされているPGQL機能および制限事項について学習します。 - PGQL問合せでのパフォーマンスの考慮事項
- JavaおよびPython APIを使用したPGQL問合せの実行
親トピック: プロパティ・グラフ問合せ言語(PGQL)
11.7.1 PGビューでサポートされているPGQL機能および制限事項
プロパティ・グラフ・ビュー(PGビュー)でサポートされているPGQL機能および制限事項について学習します。
次の表では、PGビューでサポートされているPGQL機能およびサポートされていないPGQL機能の完全なリストについて説明します:
表11-2 PGビューでサポートされているPGQL機能および制限事項
| 機能 | PGビュー上のPGQL |
|---|---|
CREATE PROPERTY GRAPH |
サポート対象 |
DROP PROPERTY GRAPH |
サポート対象 |
| 固定長パターン一致 | サポート対象 |
| 可変長パターン一致の目標 | サポート対象:
制限事項:
|
| 可変長パターン一致の数量詞 | サポート対象:
|
| 可変長パスのネスト解除 | サポート対象外 |
GROUP BY |
サポート対象 |
HAVING |
サポート対象 |
| 集計 | サポート対象:
制限事項:
|
DISTINCT
|
サポート対象 |
SELECT v.* |
サポート対象 |
ORDER BY (+ASC/DESC)、LIMIT、OFFSET |
サポート対象 |
| データ型 | 使用可能なすべてのOracle RDBMSデータ型がサポートされています |
| JSON | サポート対象:
|
| 演算子 | サポート対象:
|
| 関数および述語 |
サポート対象は、オプションのスキーマおよびパッケージ修飾子が指定された サポートされているPGQL関数/述語:
制限事項:
|
| ユーザー定義関数 | サポート対象:
|
副問合せ:
|
サポート対象 |
INSERT/UPDATE/DELETE |
サポート対象 |
INTERVALリテラルおよび操作
|
サポート対象外 |
11.7.1.1 例でサポートされているPGQL機能に関する追加情報
プロパティ・グラフ・ビュー(PGビュー)では、次のPGQL機能がサポートされています:
- 再帰的問合せは、次の可変長パス検索の目標でサポートされています。
- 到達可能性
- ANY
- ANY SHORTEST
- TOP k SHORTEST
- 再帰的問合せは、次の水平集計でサポートされています。
- LISTAGG
SELECT LISTAGG(src.first_name || ' ' || src.last_name, ',') FROM MATCH TOP 2 SHORTEST ( (n:Person) ((src)-[e:knows]->)* (m:Person) ) WHERE n.id = 1234 - SUM
SELECT SUM(e.weight + 3) FROM MATCH TOP 2 SHORTEST ( (n:Person) -[e:knows]->* (m:Person) ) WHERE n.id = 1234 - COUNT
SELECT COUNT(e) FROM MATCH TOP 2 SHORTEST ( (n:Person) -[e:knows]->* (m:Person) ) WHERE n.id = 1234 - AVG
SELECT AVG(dst.age) FROM MATCH TOP 2 SHORTEST ( (n:Person) (-[e:knows]->(dst))* (m:Person) ) WHERE n.id = 1234 - MIN (プロパティ値または
CAST式の場合のみ)SELECT MIN(CAST(dst.age + 5 AS INTEGER)) FROM MATCH TOP 2 SHORTEST ( (n:Person) (-[e:knows]->(dst))* (m:Person) ) WHERE n.id = 1234 - MAX (プロパティ値または
CAST式の場合のみ)SELECT MAX(dst.birthday) FROM MATCH TOP 2 SHORTEST ( (n:Person) (-[e:knows]->(dst))* (m:Person) ) WHERE n.id = 1234
- LISTAGG
- 再帰的問合せでは、次の数量詞がサポートされています。
表11-3 PGQL SELECT問合せでサポートされる数量詞
構文 説明 *0 (ゼロ)以上 +1以上 ?0 (ゼロ)または1 {n}nに等しい {n,}n以上 {n,m}nとmの間(両端を含む) {,m}0からmの間(両端を含む) - 精度とスケールによるデータ型キャストがサポートされています。
SELECT CAST(v.id AS VARCHAR2(10)) || '→' || CAST(w.id AS VARCHAR2(10)) AS friendOf FROM MATCH (v) -[:friendOf]->(w)SELECT CAST(e.mval AS NUMBER(5,2)) AS mval FROM MATCH () -[e:knows]->() WHERE e.mval = '342.5' - Oracle Databaseの組込み関数とユーザー定義関数(UDF)が両方ともサポートされています。
たとえば:
- 表に、
{"name":"John", "age": 43}などの値が含まれているJSON列があると仮定します。SELECT JSON_VALUE(p.attributes, '$.name') AS name FROM MATCH (p:Person) WHERE JSON_VALUE(p.attributes, '$.age') > 35 - Oracle Text索引が表内のテキスト列に存在すると仮定します。
SELECT n.text FROM MATCH (n) WHERE CONTAINS(n.text, 'cat', 1) > 0 - UDFの
updated_idがグラフ・サーバー(PGX)に登録されていると仮定します。SELECT my.updated_id(n.ID) FROM MATCH(n) LIMIT 10
- 表に、
SELECT v.*句では、頂点またはエッジのすべてのプロパティの選択がサポートされています。vは、プロパティが選択されている変数です。次の例では、グラフのすべてのエッジ・プロパティを取得します。SELECT label(e), e.* FROM MATCH (n)-[e]->(m) ON bank_graph_view LIMIT 3実行時に、前述の問合せが、次のように変数
eにバインドされているすべてのプロパティを取得します。+--------------------------------------------------------------+ | label(e) | AMOUNT | DESCRIPTION | FROM_ACCT_ID | TO_ACCT_ID | +--------------------------------------------------------------+ | TRANSFERS | 1000 | transfer | 178 | 921 | | TRANSFERS | 1000 | transfer | 178 | 462 | | TRANSFERS | 1000 | transfer | 179 | 688 | +--------------------------------------------------------------+複数の変数を使用してすべてのプロパティを選択した場合に、列名が重複しないように
PREFIXを指定できます。たとえば:SELECT n.* PREFIX 'n_', e.* PREFIX 'e_', m.* PREFIX 'm_' FROM MATCH (n:Accounts) -[e:transfers]-> (m:Accounts) ON bank_graph_view LIMIT 3問合せ出力は次のようになります。
+--------------------------------------------------------------------------------------------+ | n_ID | n_NAME | e_AMOUNT | e_DESCRIPTION | e_FROM_ACCT_ID | e_TO_ACCT_ID | m_ID | m_NAME | +--------------------------------------------------------------------------------------------+ | 178 | Account | 1000 | transfer | 178 | 921 | 921 | Account | | 178 | Account | 1000 | transfer | 178 | 462 | 462 | Account | | 179 | Account | 1000 | transfer | 179 | 688 | 688 | Account | +--------------------------------------------------------------------------------------------+ラベル式を使用すると、指定した頂点またはエッジ・ラベルに属するプロパティのみを選択できます。
SELECT LABEL(n), n.* FROM MATCH (n:Accounts) ON bank_graph_view LIMIT 3前述の問合せ出力は次のようになります。
+-----------------------+ | LABEL(n) | ID | NAME | +-----------------------+ | ACCOUNTS | 1 | User1 | | ACCOUNTS | 2 | User2 | | ACCOUNTS | 3 | User3 | +-----------------------+- 頂点ペア間のすべてのパスを戻す
ALLパス検索の目標がサポートされています。ただし、無限サイクルを回避するために、次の数量詞のみがサポートされています。- ?
- {n}
- {n.m}
- {,m}
たとえば、次のPGQL問合せでは、アカウント
284からアカウント616へのすべてのトランザクション・パスを検索します。SELECT LISTAGG(e.amount, ' + ') || ' = ', SUM(e.amount) AS total_amount FROM MATCH ALL (a:Accounts) -[e:Transfers]->{1,4}(b:Accounts) WHERE a.id = 284 AND b.id = 616 ORDER BY total_amount実行すると、問合せによって次の結果が生成されます。
+--------------------------------------------------+ | LISTAGG(e.amount, ' + ') || ' = ' | TOTAL_AMOUNT | +--------------------------------------------------+ | 1000 + 1000 + 1000 = | 3000 | | 1000 + 1500 + 1000 = | 3500 | | 1000 + 1000 + 1000 + 1000 = | 4000 | +--------------------------------------------------+ $16 ==> oracle.pg.rdbms.pgql.pgview.PgViewResultSet@4f38acf - 1列1行のみを戻すスカラー副問合せがサポートされています。
たとえば:
SELECT p.name AS name , ( SELECT SUM(t.amount) FROM MATCH (a) <-[t:transaction]- (:Account) ) AS sum_incoming , ( SELECT SUM(t.amount) FROM MATCH (a) -[t:transaction]-> (:Account) ) AS sum_outgoing , ( SELECT COUNT(DISTINCT p2) FROM MATCH (a) -[t:transaction]- (:Account) -[:owner]-> (p2:Person) WHERE p2 <> p ) AS num_persons_transacted_with , ( SELECT COUNT(DISTINCT c) FROM MATCH (a) -[t:transaction]- (:Account) -[:owner]-> (c:Company) ) AS num_companies_transacted_with FROM MATCH (p:Person) <-[:owner]- (a:Account) ORDER BY sum_outgoing + sum_incoming DESC EXISTSおよびNOT EXISTS副問合せがサポートされています。このような問合せでは、外部問合せのバインディングが指定された場合に問合せで1つ以上の結果が生成されるかどうかに応じて、TRUEまたはFALSEになります。たとえば:
SELECT fof.name, COUNT(friend) AS num_common_friends FROM MATCH (p:Person) -[:knows]-> (friend:Person) -[:knows]-> (fof:Person) WHERE NOT EXISTS ( SELECT * FROM MATCH (p) -[:knows]-> (fof) )
- PGQLの次の
SELECT機能はサポートされていません。- パス式でのバインド変数の使用。
バインド変数を使用しようとすると、次のようなエラーになります。
opg4j> String s = "SELECT id(a) FROM MATCH ANY SHORTEST (a) -[e]->* (b) WHERE id(a) = ?"; s ==> "SELECT id(a) FROM MATCH ANY SHORTEST (a) -[e]->* (b) WHERE id(a) = ?" opg4j> PgqlPreparedStatement ps = pgqlConn.prepareStatement(s); ps ==> oracle.pg.rdbms.pgql.PgqlExecution@7806db3f opg4j> ps.setString(1, "PERSON(3)"); opg4j> ps.executeQuery(); | Exception java.lang.UnsupportedOperationException: Use of bind variables for path queries is not supported in_degree関数とout_degree関数
- パス式でのバインド変数の使用。
ノート:
- PGビューでサポートされているPGQL機能およびサポートされていないPGQL機能の完全なリストは、「PGビューでサポートされているPGQL機能および制限事項」を参照してください。
- 再帰的問合せの問合せパフォーマンスを向上させるための推奨プラクティスの詳細は、PGQL問合せでのパフォーマンスの考慮事項を参照してください。
親トピック: PGビューでサポートされているPGQL機能および制限事項
11.7.2 PGQL問合せでのパフォーマンスの考慮事項
次に、問合せのパフォーマンスのためのお薦めの慣例をいくつか示します。
再帰的問合せ
再帰的問合せの実行を高速化するために、次の索引をお薦めします。
- 再帰パターンの基礎となるVERTEX表の場合、キー列の索引
- 再帰パターンの基礎となるEDGE表の場合、ソース・キー列の索引
ノート:
(ソース・キー, 宛先キー)に索引を作成することもできます。
たとえば、次のCREATE PROPERTY GRAPH文について考えてみます。
CREATE PROPERTY GRAPH people
VERTEX TABLES(
person
KEY ( id )
LABEL person
PROPERTIES( name, age )
)
EDGE TABLES(
knows
key (person1, person2)
SOURCE KEY ( person1 ) REFERENCES person (id)
DESTINATION KEY ( person2 ) REFERENCES person (id)
NO PROPERTIES
)
OPTIONS ( PG_VIEW )
また、次の問合せも考えてみます。
SELECT COUNT(*)
FROM MATCH ANY SHORTEST ( (n:Person) -[e:knows]->* (m:Person) )
WHERE n.id = 1234
前述の問合せの再帰的部分のパフォーマンスを向上させるには、次の索引が存在する必要があります。
CREATE INDEX <INDEX_NAME> ON PERSON(ID)CREATE INDEX <INDEX_NAME> ON KNOWS(PERSON1)またはCREATE INDEX <INDEX_NAME> ON KNOWS(PERSON1, PERSON2)
コンポジット頂点キー
コンポジット頂点キーの場合、キー列にファンクション索引を作成することで、問合せの実行を最適化できます。
- 再帰パターンの基礎となるVERTEX表の場合、カンマ区切りのキー列の連結に対するファンクション索引
- 再帰パターンの基礎となるEDGE表の場合、カンマ区切りのソース・キー列の連結に対するファンクション索引
ノート:
(ソース・キー列, 宛先キー列)に索引を作成することもできます。
たとえば、次のCREATE PROPERTY GRAPH文について考えてみます。
CREATE PROPERTY GRAPH people
VERTEX TABLES(
person
KEY ( id1, id2 )
LABEL person
PROPERTIES( name, age )
)
EDGE TABLES(
knows
key (id)
SOURCE KEY ( id1person1, id2person1 ) REFERENCES person (id1,id2)
DESTINATION KEY ( id1person2, id2person2 ) REFERENCES person (id1,id2)
NO PROPERTIES
)
OPTIONS ( PG_VIEW )
また、次の問合せも考えてみます。
SELECT COUNT(*)
FROM MATCH ANY SHORTEST ( (n:Person) -[e:knows]->* (m:Person) )
WHERE n.id = 1234
前述の問合せの再帰的部分のパフォーマンスを向上させるには、次の索引が存在する必要があります。
CREATE INDEX <INDEX_NAME> ON PERSON (ID1 || ',' || ID2)CREATE INDEX <INDEX_NAME> ON KNOWS (ID1PERSON1 || ',' || ID2PERSON1)またはCREATE INDEX <INDEX_NAME> ON KNOWS (ID1PERSON1 || ',' || ID2PERSON1, ID1PERSON2 || ',' || ID2PERSON2)
コンポジット頂点キーの一部の列が文字列列である場合、その列は、ファンクション索引の作成でカンマをエスケープする必要があります。
たとえば、前述の例の表PERSONの列ID1の型がVARCHAR2(10)の場合、次のように列のカンマをエスケープする必要があります。
replace(ID1, ',', '\,')
そのため、パフォーマンスを向上させるための索引は次のようになります。
CREATE INDEX <INDEX_NAME> ON PERSON (replace(ID1, ',', '\,') || ',' || ID2)CREATE INDEX <INDEX_NAME> ON KNOWS (replace(ID1PERSON1, ',', '\,') || ',' || ID2PERSON1)
問合せオプティマイザ・ヒントの使用
次のヒントを使用すると、PGQL可変長パス・パターンのSQLへの変換に影響を与えることができます。
REVERSE_PATH: 逆パス最適化のオンとオフを切り替えます(デフォルトではON)。ONの場合、指定されたフィルタ述語に基づいて、パターンを最適に評価できるは、ソースから宛先なのか宛先からソースなのかを自動的に判断します。PUSH_SRC_HOPS: ソース・フィルタ最適化の強要のオンとオフを切り替えます(デフォルトではON)。ONの場合、フィルタ述語を使用して、ソース頂点(パス評価が逆の場合は宛先頂点)の数を制限し、それによって可変長パス・パターン評価の検索領域を制限します。PUSH_DST_HOPS: 宛先フィルタ最適化の強要のオンとオフを切り替えます(デフォルトではOFF)。ONの場合、フィルタ述語を使用して、宛先頂点(パス評価が逆の場合はソース頂点)の数を制限し、それによって可変長パス・パターン評価の検索領域を制限します。
前述のヒントは、次のJava APIメソッドでoptionsパラメータとして構成できます。
executeQuery(String pgql, String options)translateQuery(String pgql, String options)execute(String pgql, String matchOptions, String options)
たとえば、次のPGQL問合せについて考えます。
SELECT v1.name AS v1, v2.name AS v2, v3.name As v3
FROM MATCH (v1:Person)-[e1:friendOf]->(v2:Person),
MATCH ANY (v2:Person)-[e2:friendOf]->*(v3:Person)
WHERE v1.name= 'Bob'
PUSH_SRC_HOPSのデフォルト・オプションを使用して前述の問合せを実行すると、次のようにstart_nodes_translationの出力にフィルタ式が表示されます。
System.out.println(pgqlStatement.translateQuery(pgql).getSqlTranslation())
...
...
start_nodes_translation => (to_clob('SELECT ''PERSONS'' AS "src_table", e1.person_b AS "src_key"
FROM "GRAPHUSER"."PERSONS" "V1", "GRAPHUSER"."FRIENDSHIPS" "E1"
WHERE (((e1.person_a = v1.person_id) AND NOT(e1.person_b IS NULL)) AND (v1.name = ''Bob''))')),
end_nodes_translation => (to_clob('SELECT ''PERSONS'' AS "dst_table", v3.person_id AS "dst_key"
FROM "GRAPHUSER"."PERSONS" "V3"')),
...
...
ヒントPUSH_SRC_HOPS=Fを指定して前述の問合せを実行すると、次のように問合せはSQLに変換されます。
System.out.println(pgqlStatement.translateQuery(pgql,"PUSH_SRC_HOPS=F").getSqlTranslation())
...
...start_nodes_translation => (to_clob('SELECT ''PERSONS'' AS "src_table", v2.person_id AS "src_key"
FROM "GRAPHUSER"."PERSONS" "V2"')),
end_nodes_translation => (to_clob('SELECT ''PERSONS'' AS "dst_table", v3.person_id AS "dst_key"
FROM "GRAPHUSER"."PERSONS" "V3"')),
...
...
グラフ・メタデータ・キャッシュおよび変換キャッシュを使用した問合せ変換の高速化
次のグローバル・キャッシュは、PGQL問合せ変換の高速化に役立ちます。
- グラフ・メタデータ・キャッシュ: 表、ラベル、プロパティなどのグラフ・メタデータを格納します。
- 変換キャッシュ: PGQLからSQLへの変換を格納します。
次のJava APIを使用してキャッシュを構成できます。
clearTranslationCache()disableTranslationCache()enableTranslationCache()setTranslationCacheMaxCapacity(int maxCapacity)clearGraphMetadataCache()disableGraphMetadataCache()enableGraphMetadataCache()setGraphMetadataCacheMaxCapacity(int maxCapacity)
前述のこれらのメソッドは、PgqlConnectionクラスに属します。個々のキャッシュはデータベース・ユーザーごとに保持されるため、キャッシュされたオブジェクトは、接続URLとその下のユーザーが同じである場合に、異なるPgqlConnectionオブジェクト間で共有されます。
親トピック: プロパティ・グラフ・ビューに対するPGQL問合せの実行
11.7.3 JavaおよびPython APIを使用したPGQL問合せの実行
oracle.pg.rdbms.pgqlパッケージのJava APIを使用して、PGQL問合せを実行できます。また、Python OPG4Pyパッケージを使用して、Oracle Databaseのグラフ・データに対してPGQL問合せを実行できます。このパッケージには、oracle.pg.rdbms.pgqlパッケージのJava APIをラップする1つ以上のモジュールを含むサブパッケージPgqlが含まれています。
- プロパティ・グラフ・ビューの作成
- PGQL SELECT問合せの実行
- JDBCドライバを使用したPGQL問合せの実行
- プロパティ・グラフ・ビューを変更するためのPGQL問合せの実行
- プロパティ・グラフ・ビューの削除
親トピック: プロパティ・グラフ・ビューに対するPGQL問合せの実行
11.7.3.1 プロパティ・グラフ・ビューの作成
CREATE PROPERTY GRAPH文を使用してプロパティ・グラフ・ビュー(PGビュー)を作成できます。
例11-1 プロパティ・グラフ・ビューの作成
次の例では、PGビューの作成について説明します。
opg4j> var jdbcUrl="jdbc:oracle:thin:@<host_name>:<port>/<db_service>"
opg4j> var conn = DriverManager.getConnection(jdbcUrl,"<username>","<password>");
opg4j> var pgqlConn = PgqlConnection.getConnection(conn)
opg4j> var pgqlStmt = pgqlConn.createStatement() //create a PGQL Statement
opg4j> conn.setAutoCommit(false)
opg4j> var pgql =
...> "CREATE PROPERTY GRAPH bank_graph "
...> + "VERTEX TABLES ( bank_accounts AS Accounts "
...> + "KEY (id) "
...> + "LABEL Accounts "
...> + "PROPERTIES (id, name) "
...> + ") "
...> + "EDGE TABLES ( bank_txns AS Transfers "
...> + "KEY (txn_id) "
...> + "SOURCE KEY (from_acct_id) REFERENCES Accounts (id) "
...> + "DESTINATION KEY (to_acct_id) REFERENCES Accounts (id) "
...> + "LABEL Transfers "
...> + "PROPERTIES (from_acct_id, to_acct_id, amount, description) "
...> + ") OPTIONS (PG_VIEW) "
opg4j> pgqlStmt.execute(pgql)import java.sql.Connection;
import java.sql.Statement;
import java.sql.DriverManager;
import oracle.pg.rdbms.pgql.jdbc.PgqlJdbcRdbmsDriver;
import oracle.pg.rdbms.pgql.PgqlConnection;
import oracle.pg.rdbms.pgql.PgqlStatement;
/*
* This example shows how to create a property graph view.
*/
public class PgqlCreate
{
public static void main(String[] args) throws Exception
{
int idx=0;
String jdbcUrl = args[idx++];
String username = args[idx++];
String password = args[idx++];
String graph = args[idx++];
Connection conn = null;
PgqlStatement pgqlStmt = null;
try {
//Get a jdbc connection
DriverManager.registerDriver(new PgqlJdbcRdbmsDriver());
conn = DriverManager.getConnection(jdbcUrl, username, password);
conn.setAutoCommit(false);
// Get a PGQL connection
PgqlConnection pgqlConn = PgqlConnection.getConnection(conn);
// Create a PGQL Statement
pgqlStmt = pgqlConn.createStatement();
// Execute PGQL Query
String pgql =
"CREATE PROPERTY GRAPH " + graph + " " +
"VERTEX TABLES ( bank_accounts as Accounts " +
"KEY (id) " +
"LABEL \"Accounts\"" +
"PROPERTIES (id, name)" +
") " +
"EDGE TABLES ( bank_txns as Transfers " +
"KEY (txn_id) " +
"SOURCE KEY (from_acct_id) REFERENCES Accounts (id) " +
"DESTINATION KEY (to_acct_id) REFERENCES Accounts (id) " +
"LABEL \"Transfers\"" +
"PROPERTIES (from_acct_id, to_acct_id, amount, description)" +
") OPTIONS (PG_VIEW) ";
// Print the results
pgqlStmt.execute(pgql);
}
finally {
// close the statement
if (pgqlStmt != null) {
pgqlStmt.close();
}
// close the connection
if (conn != null) {
conn.close();
}
}
}
}>>> pgql_conn = opg4py.pgql.get_connection("<username>","<password>", "jdbc:oracle:thin:@localhost:1521/orclpdb")
>>> pgql_statement = pgql_conn.create_statement()
>>> pgql = """
... CREATE PROPERTY GRAPH bank_graph
... VERTEX TABLES (
... bank_accounts
... LABEL Accounts
... PROPERTIES (id, name)
... )
... EDGE TABLES (
... bank_txns
... KEY (txn_id)
... SOURCE KEY (from_acct_id) REFERENCES bank_accounts
... DESTINATION KEY (to_acct_id) REFERENCES bank_accounts
... LABEL TRANSFERS
... PROPERTIES (from_acct_id, to_acct_id, amount, description)
... ) OPTIONS(PG_VIEW)
... """
>>> pgql_statement.execute(pgql)
Falseプロパティ・グラフ・ビューの作成を確認するには、データベースで作成されるメタデータ表を確認します。
11.7.3.2 PGQL SELECT問合せの実行
次の例で説明するように、PGQL SELECT問合せを実行できます。
例11-2 PgqlStatementおよびPgqlResultSetを使用した単純なSELECT問合せの実行
次の例では、PgqlConnectionを使用してPgqlStatementを取得します。次に、PgqlStatementのexecuteQueryメソッドをコールし、これにより、PgqlResultSetオブジェクトが返されます。PgqlResultSetには、表形式モードで結果を表示するprint()メソッドがあります。
opg4j> var jdbcUrl="jdbc:oracle:thin:@<host_name>:<port>/<db_service>"
opg4j> var conn = DriverManager.getConnection(jdbcUrl,"<username>","<password>");
opg4j> var pgqlConn = PgqlConnection.getConnection(conn)
opg4j> pgqlConn.setGraph("BANK_GRAPH")
opg4j> var pgqlStmt = pgqlConn.createStatement() //create a PGQL Statement
opg4j> String s = "SELECT n.* FROM MATCH (n:Accounts) LIMIT 3"
opg4j> var resultSet = pgqlStmt.executeQuery(s)
opg4j> resultSet.print() //Prints the query result set
+---------------+
| ID | NAME |
+---------------+
| 1 | Account1 |
| 2 | Account2 |
| 3 | Account3 |
+---------------+import java.sql.Connection;
import java.sql.Statement;
import java.sql.DriverManager;
import oracle.pg.rdbms.pgql.jdbc.PgqlJdbcRdbmsDriver;
import oracle.pg.rdbms.pgql.PgqlConnection;
import oracle.pg.rdbms.pgql.PgqlResultSet;
import oracle.pg.rdbms.pgql.PgqlStatement;
/*
* This example shows how to execute a SELECT query on a property graph view.
*/
public class PgqlExample1
{
public static void main(String[] args) throws Exception
{
int idx=0;
String jdbcUrl = args[idx++];
String username = args[idx++];
String password = args[idx++];
String graph = args[idx++];
Connection conn = null;
PgqlStatement pgqlStmt = null;
PgqlResultSet rs = null;
try {
//Get a jdbc connection
DriverManager.registerDriver(new PgqlJdbcRdbmsDriver());
conn = DriverManager.getConnection(jdbcUrl, username, password);
conn.setAutoCommit(false);
// Get a PGQL connection
PgqlConnection pgqlConn = PgqlConnection.getConnection(conn);
pgqlConn.setGraph(graph);
// Create a PGQL Statement
pgqlStmt = pgqlConn.createStatement();
// Execute PGQL Query
String query = "SELECT n.* FROM MATCH (n:Accounts) LIMIT 5";
rs = pgqlStmt.executeQuery(query);
// Print the results
rs.print();
}
finally {
// close the result set
if (rs != null) {
rs.close();
}
// close the statement
if (pgqlStmt != null) {
pgqlStmt.close();
}
// close the connection
if (conn != null) {
conn.close();
}
}
}
}>>> pgql_conn = opg4py.pgql.get_connection("<username>","<password>", "<jdbcUrl>")
>>> pgql_statement = pgql_conn.create_statement()
>>> pgql_conn.set_graph("BANK_GRAPH")
>>> s = "SELECT n.* FROM MATCH (n:Accounts) LIMIT 3"
>>> pgql_statement.execute_query(s)
>>> pgql_result_set = pgql_statement.execute_query(s)
>>> pgql_result_set.print()
+---------------+
| ID | NAME |
+---------------+
| 1 | Account1 |
| 2 | Account2 |
| 3 | Account3 |
+---------------+
>>> pgql_result_set
PgqlResultSet(java_pgql_result_set: oracle.pg.rdbms.pgql.PgqlResultSet, # of results: 3)また、to_pandas()メソッドを使用して、前述のコードで取得したPGQL結果セットをPandasデータフレームに変換できます。
ノート:
to_pandas()のコールを正常に実行するには、システムにpandasパッケージをインストールする必要があります。このパッケージは、バージョンPython 3.8およびPython 3.9のPythonクライアントのインストール時に自動的にインストールされます。ただし、to_pandas()のコールに失敗した場合は、pandasモジュールがシステムにインストールされているかどうかを確認してください。モジュールが見つからないか、Pythonのバージョンが前述のバージョンと異なる場合は、pandasパッケージを手動でインストールします。
例11-3 PgqlPreparedStatementを使用したSELECT問合せの実行
opg4j> var jdbcUrl="jdbc:oracle:thin:@<host_name>:<port>/<db_service>"
opg4j> var conn = DriverManager.getConnection(jdbcUrl,"<username>","<password>");
opg4j> var pgqlConn = PgqlConnection.getConnection(conn)
opg4j> pgqlConn.setGraph("BANK_GRAPH");
opg4j> String s = "SELECT n.* FROM MATCH (n:Accounts) LIMIT ?"
opg4j> var ps = pgqlConn.prepareStatement(s, 0 /* timeout */, 4 /* parallel */, 2 /* dynamic sampling */, -1 /* max results */, null /* match options */, null /* options */)
opg4j> ps.setInt(1, 3)
opg4j> var rs = ps.executeQuery()
opg4j> rs.print() //Prints the query result set
+---------------+
| ID | NAME |
+---------------+
| 1 | Account1 |
| 2 | Account2 |
| 3 | Account3 |
+---------------+import java.sql.Statement;
import java.sql.DriverManager;
import oracle.pg.rdbms.pgql.jdbc.PgqlJdbcRdbmsDriver;
import oracle.pg.rdbms.pgql.*;
public class PgqlExample2
{
public static void main(String[] args) throws Exception
{
int idx=0;
String jdbcUrl = args[idx++];
String username = args[idx++];
String password = args[idx++];
String graph = args[idx++];
Connection conn = null;
PgqlStatement pgqlStmt = null;
PgqlResultSet rs = null;
try {
//Get a jdbc connection
DriverManager.registerDriver(new PgqlJdbcRdbmsDriver());
conn = DriverManager.getConnection(jdbcUrl, username, password);
conn.setAutoCommit(false);
// Get a PGQL connection
PgqlConnection pgqlConn = PgqlConnection.getConnection(conn);
pgqlConn.setGraph(graph);
// Execute PGQL Query
String s = "SELECT n.* FROM MATCH (n:Accounts) LIMIT ?";
PgqlPreparedStatement pStmt = pgqlConn.prepareStatement(s, 0, 4 , 2 , -1 , null , null);
pStmt.setInt(1,3);
rs = pStmt.executeQuery();
// Print the results
rs.print();
}
finally {
// close the result set
if (rs != null) {
rs.close();
}
// close the statement
if (pgqlStmt != null) {
pgqlStmt.close();
}
// close the connection
if (conn != null) {
conn.close();
}
}
}
}>>> pgql_conn = opg4py.pgql.get_connection("<username>","<password>", "<jdbcUrl>")
>>> pgql_statement = pgql_conn.create_statement()
>>> pgql_conn.set_graph("BANK_GRAPH")
>>> s = "SELECT n.* FROM MATCH (n:Accounts) LIMIT ?"
>>> ps = pgql_conn.prepare_statement(s, timeout=0, parallel=4, dynamicSampling=2, maxResults=-1, matchOptions=None, options=None)
>>> ps.set_int(1,3)
>>> ps.execute_query().print()
+---------------+
| ID | NAME |
+---------------+
| 1 | Account1 |
| 2 | Account2 |
| 3 | Account3 |
+---------------+例11-4 グループ化と集計を指定したSELECT問合せの実行
opg4j> var jdbcUrl="jdbc:oracle:thin:@<host_name>:<port>/<db_service>"
opg4j> var conn = DriverManager.getConnection(jdbcUrl,"<username>","<password>");
opg4j> var pgqlConn = PgqlConnection.getConnection(conn)
opg4j> pgqlConn.setGraph("BANK_GRAPH")
opg4j> var pgqlStmt = pgqlConn.createStatement() //create a PGQL Statement
opg4j> String query = "SELECT v1.id, COUNT(v2) AS numTxns "+
...> "FROM MATCH (v1)-[e IS Transfers]->(v2) "+
...> "GROUP BY v1 "+
...> "ORDER BY numTxns DESC "+
...> "LIMIT 3"
opg4j> var resultSet = pgqlStmt.executeQuery(query)
opg4j> resultSet.print() //Prints the query result set
+---------------+
| ID | NUMTXNS |
+---------------+
| 687 | 6 |
| 195 | 5 |
| 192 | 5 |
+---------------+
import java.sql.Connection;
import java.sql.Statement;
import java.sql.DriverManager;
import oracle.pg.rdbms.pgql.jdbc.PgqlJdbcRdbmsDriver;
import oracle.pg.rdbms.pgql.PgqlConnection;
import oracle.pg.rdbms.pgql.PgqlResultSet;
import oracle.pg.rdbms.pgql.PgqlStatement;
/*
* This example shows how to execute a SELECT query with aggregation .*/
public class PgqlExample3
{
public static void main(String[] args) throws Exception
{
int idx=0;
String jdbcUrl = args[idx++];
String username = args[idx++];
String password = args[idx++];
String graph = args[idx++];
Connection conn = null;
PgqlStatement pgqlStmt = null;
PgqlResultSet rs = null;
try {
//Get a jdbc connection
DriverManager.registerDriver(new PgqlJdbcRdbmsDriver());
conn = DriverManager.getConnection(jdbcUrl, username, password);
conn.setAutoCommit(false);
// Get a PGQL connection
PgqlConnection pgqlConn = PgqlConnection.getConnection(conn);
pgqlConn.setGraph(graph);
// Create a PGQL Statement
pgqlStmt = pgqlConn.createStatement();
// Execute PGQL Query
String query =
"SELECT v1.id, COUNT(v2) AS numTxns "+
"FROM MATCH (v1)-[e IS Transfers]->(v2) "+
"GROUP BY v1 "+
"ORDER BY numTxns DESC";
rs = pgqlStmt.executeQuery(query);
// Print the results
rs.print();
}
finally {
// close the result set
if (rs != null) {
rs.close();
}
// close the statement
if (pgqlStmt != null) {
pgqlStmt.close();
}
// close the connection
if (conn != null) {
conn.close();
}
}
}
}>>> pgql_conn = opg4py.pgql.get_connection("<username>","<password>", "<jdbcUrl>")
>>> pgql_statement = pgql_conn.create_statement()
>>> pgql_conn.set_graph("BANK_GRAPH")
>>> query = """
... SELECT v1.id, COUNT(v2) AS numtxns
... FROM MATCH (v1)-[e IS Transfers]->(v2)
... GROUP BY v1
... ORDER BY numtxns DESC
... LIMIT 3
... """
>>> pgql_statement.execute_query(query).print()
+---------------+
| ID | NUMTXNS |
+---------------+
| 687 | 6 |
| 195 | 5 |
| 192 | 5 |
+---------------+例11-5 PGQLパス問合せの表示
opg4j> var jdbcUrl="jdbc:oracle:thin:@<host_name>:<port>/<db_service>"
opg4j> var conn = DriverManager.getConnection(jdbcUrl,"<username>","<password>");
opg4j> var pgqlConn = PgqlConnection.getConnection(conn)
opg4j> pgqlConn.setGraph("BANK_GRAPH")
opg4j> var pgqlStmt = pgqlConn.createStatement() //create a PGQL Statement
opg4j> String query = "PATH onehop AS ()-[IS transfers]->() "+
...> "SELECT v1.id FROM MATCH (v1)-/:onehop/->(v2) "+
...> "WHERE v2.id = 365"
opg4j> var resultSet = pgqlStmt.executeQuery(query)
opg4j> resultSet.print() //Prints the query result set
+-----+
| ID |
+-----+
| 132 |
| 435 |
| 296 |
| 327 |
| 328 |
| 399 |
| 684 |
| 919 |
| 923 |
| 771 |
+-----+import java.sql.Connection;
import java.sql.Statement;
import java.sql.DriverManager;
import oracle.pg.rdbms.pgql.jdbc.PgqlJdbcRdbmsDriver;
import oracle.pg.rdbms.pgql.PgqlConnection;
import oracle.pg.rdbms.pgql.PgqlResultSet;
import oracle.pg.rdbms.pgql.PgqlStatement;
/*
* This example shows how to execute a PGQL PATH query.*/
public class PgqlExample4
{
public static void main(String[] args) throws Exception
{
int idx=0;
String jdbcUrl = args[idx++];
String username = args[idx++];
String password = args[idx++];
String graph = args[idx++];
Connection conn = null;
PgqlStatement pgqlStmt = null;
PgqlResultSet rs = null;
try {
//Get a jdbc connection
DriverManager.registerDriver(new PgqlJdbcRdbmsDriver());
conn = DriverManager.getConnection(jdbcUrl, username, password);
conn.setAutoCommit(false);
// Get a PGQL connection
PgqlConnection pgqlConn = PgqlConnection.getConnection(conn);
pgqlConn.setGraph(graph);
// Create a PGQL Statement
pgqlStmt = pgqlConn.createStatement();
// Execute PGQL Query
String query =
"PATH onehop AS ()-[IS transfers]->() "+
"SELECT v1.id FROM MATCH (v1)-/:onehop/->(v2) "+
"WHERE v2.id = 365";
rs = pgqlStmt.executeQuery(query);
// Print the results
rs.print();
}
finally {
// close the result set
if (rs != null) {
rs.close();
}
// close the statement
if (pgqlStmt != null) {
pgqlStmt.close();
}
// close the connection
if (conn != null) {
conn.close();
}
}
}
}>>> pgql_conn = opg4py.pgql.get_connection("<username>","<password>", "<jdbcUrl>")
>>> pgql_statement = pgql_conn.create_statement()
>>> pgql_conn.set_graph("BANK_GRAPH")
>>> query = """
... PATH onehop AS ()-[IS transfers]->()
... SELECT v1.id FROM MATCH (v1)-/:onehop/->(v2)
... WHERE v2.id = 365
... """
>>> pgql_statement.execute_query(query).print()
+-----+
| ID |
+-----+
| 132 |
| 435 |
| 296 |
| 327 |
| 328 |
| 399 |
| 684 |
| 919 |
| 923 |
| 771 |
+-----+11.7.3.3 JDBCドライバを使用したPGQL問合せの実行
Oracle Graph Server and Clientリリース21.2.0には、Oracle Databaseに対してPGQL問合せを直接実行できるJDBCドライバが含まれています。ドライバを使用するには、次のクラスをJDBCドライバ・マネージャで登録します。
import java.sql.DriverManager;
import oracle.pg.rdbms.pgql.jdbc.PgqlJdbcRdbmsDriver;
...
DriverManager.registerDriver(new PgqlJdbcRdbmsDriver());JDBCでドライバを使用するには、次の例に示すように、JDBC URLに接頭辞としてjdbc:oracle:pgqlを付ける必要があります。
import java.sql.Connection;
import java.sql.DriverManager;
Connection conn = DriverManager.getConnection("jdbc:oracle:pgql:@<DB Host>:<DB Port>/<DB SID>", "<DB Username>", "<DB Password>");jdbc:oracle:pgql後の部分は、通常のOracle JDBCシン・ドライバと同じ構文に従います。つまり、jdbc:oracle:thinをjdbc:oracle:pgqlに置き換えると、有効なOracle JDBCシン・ドライバURLをPGQLドライバURLに変換できます。接続オブジェクトを取得したら、これを使用して、PGQL構文でプロパティ・グラフを問い合せることができます。たとえば:
例11-6 PGQL JDBCドライバを使用したPGQL問合せの実行
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
import oracle.pg.rdbms.pgql.jdbc.PgqlJdbcRdbmsDriver;
public class PgqlJdbcTest {
public static void main(String[] args) throws Exception {
DriverManager.registerDriver(new PgqlJdbcRdbmsDriver());
String jdbcUrl = "jdbc:oracle:pgql:@<DB Host>:<DB Port>/<DB SID>";
String username = "<DB Username>";
String password = "<DB Password>";
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
String query = "SELECT n.name FROM MATCH(n) ON test_graph WHERE id(n) = ?";
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setLong(1, 10L);
pstmt.execute();
ResultSet rs = pstmt.getResultSet();
while(rs.next()){
System.out.println("NAME = " + rs.getString("name"));
}
}
}
}前述のコードをファイルPgqlJdbcTest.javaに保存し、次を使用してコンパイルします。
javac -cp "<graph-client>/lib/*" PgqlJdbcTest.javaドライバは、通常のグラフ・サーバー(RPM)のインストールにも含まれます。たとえば:
javac -cp "/opt/oracle/graph/lib/*" PgqlJdbcTest.java11.7.3.4 プロパティ・グラフ・ビューを変更するためのPGQL問合せの実行
PGQL INSERT、UPDATEおよびDELETEの各問合せをプロパティ・グラフ・ビューに対して実行するには、OPG4J Javaシェル、OPG4Py Pythonシェルを使用するか、JavaまたはPythonアプリケーションを使用します。
グラフに頂点またはエッジを挿入する際に、一意のIDが自動生成されないことに注意してください。このため、キー列値がグラフ・プロパティに存在するか、データベースによって自動生成されるようにする(SEQUENCEおよびTRIGGERSを使用するか、IDENTITY列を使用して自動増分機能で実現する)必要があります。
次の例では、2つの新しい頂点を挿入し、2つの頂点間にエッジ関係も追加します。
opg4j> String pgql =
...> "INSERT VERTEX v1 LABELS (Person) PROPERTIES (v1.name= 'ABC', v1.height=1.6, v1.birthdate = to_date('13/06/1963', 'DD/MM/YYYY')) "+
...> " , VERTEX v2 LABELS (Person) PROPERTIES (v2.name= 'XYZ', v2.height=1.75, v2.birthdate = to_date('19/06/1963', 'DD/MM/YYYY')) "+
...> " , EDGE e BETWEEN v1 AND v2 LABELS (friendof) PROPERTIES ( e.meeting_date = to_date('19/06/2021', 'DD/MM/YYYY')) "
pgql ==> "INSERT VERTEX v1 LABELS (Person) PROPERTIES (v1.name= 'ABC', v1.height=1.6, v1.birthdate = to_date('13/06/1963', 'DD/MM/YYYY')) , VERTEX v2 LABELS (Person) PROPERTIES (v2.name= 'XYZ', v2.height=1.75, v2.birthdate = to_date('19/06/1963', 'DD/MM/YYYY')) , EDGE e BETWEEN v1 AND v2 LABELS (friendof) PROPERTIES ( e.meeting_date = to_date('19/06/2021', 'DD/MM/YYYY')) "
opg4j> pgqlStmt.execute(pgql)
$14 ==> falseString pgql =
...> "INSERT VERTEX v1 LABELS (Person) PROPERTIES (v1.name= 'ABC', v1.height=1.6, v1.birthdate = to_date('13/06/1963', 'DD/MM/YYYY')) "+
...> " , VERTEX v2 LABELS (Person) PROPERTIES (v2.name= 'XYZ', v2.height=1.75, v2.birthdate = to_date('19/06/1963', 'DD/MM/YYYY')) "+
...> " , EDGE e BETWEEN v1 AND v2 LABELS (friendof) PROPERTIES ( e.meeting_date = to_date('19/06/2021', 'DD/MM/YYYY')) ";
pgqlStmt.execute(pgql);>>> pgql = """
... INSERT VERTEX v1 LABELS (Person) PROPERTIES (v1.name= 'ABC', v1.height=1.6, v1.birthdate = to_date('13/06/1963', 'DD/MM/YYYY'))
... , VERTEX v2 LABELS (Person) PROPERTIES (v2.name= 'XYZ', v2.height=1.75, v2.birthdate = to_date('19/06/1963', 'DD/MM/YYYY'))
... , EDGE e BETWEEN v1 AND v2 LABELS (friendof) PROPERTIES ( e.meeting_date = to_date('19/06/2021', 'DD/MM/YYYY'))
... """
>>> pgql_statement.execute(pgql)
False
次の例では、UPDATE問合せを実行して前述の例で挿入されたエッジ・プロパティを変更してから、SELECT問合せを使用して更新操作を検証します。
opg4j> String pgql = "UPDATE e SET (e.meeting_date = to_date('12/02/2022', 'DD/MM/YYYY')) "+
...> "FROM MATCH (v1:Person)-[e:friendof]->(v2:Person) "+
...> "WHERE v1.person_id = 27 AND v2.person_id = 28"
pgql ==> "UPDATE e SET (e.meeting_date = to_date('12/02/2022', 'DD/MM/YYYY')) FROM MATCH (v1:Person)-[e:friendof]->(v2:Person) WHERE v1.person_id = 27 AND v2.person_id = 28"
opg4j> pgqlStmt.execute(pgql)
$40 ==> false
opg4j>pgqlStmt.executeQuery("SELECT e.meeting_date FROM MATCH (v1:Person)-[e:friendof]->(v2:Person) WHERE v1.person_id = 27").print()
+-----------------------+
| MEETING_DATE |
+-----------------------+
| 2022-02-12 00:00:00.0 |
+-----------------------+String pgql ="UPDATE e SET (e.meeting_date = to_date('12/02/2022', 'DD/MM/YYYY')) "+
"FROM MATCH (v1:Person)-[e:friendof]->(v2:Person) "+
"WHERE v1.person_id = 27 AND v2.person_id = 28";
pgqlStmt.execute(pgql);>>> pgql = """
... UPDATE e SET (e.meeting_date = to_date('12/02/2022', 'DD/MM/YYYY'))
... FROM MATCH (v1:Person)-[e:friendof]->(v2:Person)
... WHERE v1.person_id = 27 AND v2.person_id = 28
... """
>>> pgql_statement.execute(pgql)
False
>>> pgql_statement.execute_query("SELECT e.meeting_date FROM MATCH(v1:Person)-[e:friendof]->(v2:Person) WHERE v1.person_id = 27").print()
+-----------------------+
| MEETING_DATE |
+-----------------------+
| 2022-02-12 00:00:00.0 |
+-----------------------+ DELETE問合せを使用すると、グラフ内の頂点およびエッジを削除できます。次の例では、DELETE問合せを実行してグラフのエッジを削除します。
opg4j> pgqlStmt.execute("DELETE e FROM MATCH (v1:Person)-[e:friendof]->(v2:Person) WHERE v.person_id=27")
$14 ==> falsepgqlStmt.execute("DELETE e FROM MATCH (v1:Person)-[e:friendof]->(v2:Person) WHERE v.person_id=27");>>> pgql_statement.execute("DELETE e FROM MATCH (v1:Person)-[e:friendof]->(v2:Person) WHERE v1.person_id=27")
False
11.7.3.5 プロパティ・グラフ・ビューの削除
PGQL DROP PROPERTY GRAPH文を使用して、プロパティ・グラフ・ビュー(PGビュー)を削除できます。PGビューのメタデータ表はすべて削除されることに注意してください。
例11-7 プロパティ・グラフ・ビューの作成
次の例では、PGビューの作成について説明します。
opg4j> var jdbcUrl="jdbc:oracle:thin:@<host_name>:<port>/<db_service>"
opg4j> var conn = DriverManager.getConnection(jdbcUrl,"<username>","<password>")
opg4j> var pgqlConn = PgqlConnection.getConnection(conn)
opg4j> var pgqlStmt = pgqlConn.createStatement() //create a PGQL Statement
opg4j> pgqlStmt.execute("DROP PROPERTY GRAPH <pgview>")
$9 ==> falseimport java.sql.Connection;
import java.sql.Statement;
import java.sql.DriverManager;
import oracle.pg.rdbms.pgql.jdbc.PgqlJdbcRdbmsDriver;
import oracle.pg.rdbms.pgql.PgqlConnection;
import oracle.pg.rdbms.pgql.PgqlStatement;
/**
* This example shows how to drop a property graph view.
*/
public class DropPgView
{
public static void main(String[] args) throws Exception
{
int idx=0;
String jdbcUrl = args[idx++];
String username = args[idx++];
String password = args[idx++];
String graph = args[idx++];
Connection conn = null;
PgqlStatement pgqlStmt = null;
try {
//Get a jdbc connection
DriverManager.registerDriver(new PgqlJdbcRdbmsDriver());
conn = DriverManager.getConnection(jdbcUrl, username, password);
conn.setAutoCommit(false);
// Get a PGQL connection
PgqlConnection pgqlConn = PgqlConnection.getConnection(conn);
// Create PGQL Statement
pgqlStmt = pgqlConn.createStatement();
String query = "DROP PROPERTY GRAPH " +pgview;
pgqlStmt.execute(query);
}
finally {
// close the statement
if (pgqlStmt != null) {
pgqlStmt.close();
}
// close the connection
if (conn != null) {
conn.close();
}
}
}
}
>>> pgql_conn = opg4py.pgql.get_connection("<username>","<password>", "jdbc:oracle:thin:@localhost:1521/orclpdb")
>>> pgql_statement = pgql_conn.create_statement()
>>> pgql = "DROP PROPERTY GRAPH <pgview>"
>>> pgql_statement.execute(pgql)
False