グラフデータベースは、グラフとして構造化されたデータを格納および管理します。グラフデータベースは、ソーシャルネットワークや知識グラフなど、複雑なリレーションシップを持つデータの管理に最適です。Cypher や Gremlin などのグラフクエリ言語を使用して、グラフデータベース内のデータに対する操作を実行できます。PolarDB は OpenCypher をサポートしており、グラフデータの作成、クエリ、更新、削除が可能です。また、PolarDB はパターンマッチング、データフィルタリング、重複を避けるための MERGE 操作、そしてグラフデータの管理と応用を簡素化する可視化ツールなどの機能も提供します。
適用範囲
この機能は、以下のバージョンの PolarDB for PostgreSQL で利用できます。
PostgreSQL 16 (マイナーエンジンバージョン 2.0.16.8.3.0 以降)
PostgreSQL 15 (マイナーエンジンバージョン 2.0.15.12.4.0 以降)
PostgreSQL 14 (マイナーエンジンバージョン 2.0.14.12.24.0 以降)
コンソールで、または SHOW polardb_version; 文を実行することで、マイナーエンジンバージョンを表示できます。ご利用のクラスターがバージョンの要件を満たしていない場合は、マイナーエンジンバージョンをアップグレードできます。
用語
グラフ:ノードとエッジで構成されるデータ構造。たとえば、グラフを使用してソーシャルネットワーク内の複雑なリレーションシップを表すことができます。ソーシャルネットワークでは、各個人がノードであり、友情、家族の絆、仕事上のつながりなどのリレーションシップがエッジです。

ノード:グラフデータベースにおける基本的な要素で、エンティティを表します。ノードはプロパティを持つことができ、プロパティはエンティティに関する情報を格納するキーと値のペアです。たとえば、ソーシャルネットワークでは、ノードを使用してユーザー、企業、組織を表すことができます。
エッジ:2 つのノード間の接続で、それらの間のリレーションシップを表します。エッジは、リレーションシップの強さ、重要性、方向などを記述するために、重みや方向などのプロパティを持つこともできます。たとえば、ソーシャルネットワークでは、エッジは友情、フォロー、ファンなど、ユーザー間のさまざまな種類のリレーションシップを表すことができます。
ラベル:グラフ内のノードまたはエッジを識別し、分類するために使用される分類または属性。ラベルは、データに意味的な意味を加え、理解、管理、クエリを容易にするのに役立ちます。たとえば、ソーシャルネットワークでは、ノードには Person や Company などのラベルを割り当てることができ、エッジには Knows や WorkIn などのラベルを割り当てることができます。
プロパティグラフ:ノードまたはエッジがプロパティを持つことができるグラフの一種。次の図は、ノードとエッジがプロパティを持つ専門的なリレーションシップのプロパティグラフを示しています。

グラフデータベース:グラフを使用してデータを格納および管理する特殊なタイプのデータベース。グラフデータベースでは、ノードはエンティティを表し、エッジはエンティティ間のリレーションシップを表します。グラフデータベースは、ソーシャルネットワーク、信頼ネットワーク、知識グラフなどのドメインにおける複雑なリレーションシップデータの管理に適しています。
グラフデータベースでは、Cypher や Gremlin などのグラフクエリ言語を使用してデータをクエリできます。PolarDB は OpenCypher をサポートしています。OpenCypher は Cypher クエリ言語のオープンソースのサブセットであり、ほとんどのユースケースで Cypher と機能的に同等になるように設計されています。
スキーマ
プロパティ
Cypher 言語では、プロパティは JSON の構造と同様に、中括弧 {} で囲まれたキーと値のペアとして表現されます。キーはプロパティを識別する文字列で、値は文字列、数値、または配列にすることができます。たとえば、{name: 'Reeves'} と表現されるプロパティは、name プロパティの値が Reeves であることを示します。
ノード
Cypher 言語では、ノードは丸括弧 () で囲まれます。以下はノード表現の例です。
()
(matrix)
(:Movie)
(matrix:Movie)
(matrix:Movie {title: 'The Matrix'})
(matrix:Movie {title: 'The Matrix', released: 1997})ここで:
最も単純な形式である
()は、匿名でラベルのないノードを表します。同じ文の他の場所でノードを参照するには、
(matrix)のような変数を追加できます。変数は単一の文にのみ適用されます。他の文では、異なる意味を持つか、意味を持たない場合があります。:Movieパターンはノードのラベルを宣言します。これにより、パターンを制限して、他のラベルを持つノードと一致しないようにすることができます。{title: 'The Matrix'}はノードのプロパティを宣言します。たとえば、プロパティは情報を格納したり、パターンを制限したりするために使用できます。
エッジ
Cypher 言語では、無向エッジは一対のハイフン -- で表されます。有向エッジは、<-- や --> のように、一方の端に矢印で表されます。角括弧式 [...] を使用して、変数、プロパティ、型情報などの詳細を追加できます。以下はエッジ表現の例です。
--
-->
-[role]->
-[:ACTED_IN]->
-[role:ACTED_IN]->
-[role:ACTED_IN {roles: ['Neo']}]->ここで:
--は、匿名の無向エッジを表します。-->は、匿名の有向エッジを表します。文の他の場所で使用するために、
roleなどの変数を定義できます。:ACTED_INなどのリレーションシップのラベルは、ノードのラベルに似ています。roles: ['Neo']などのプロパティは、ノードのプロパティと同じ方法で定義されます。
操作例
このセクションでは、簡単な映画データベースを例として、PolarDB でのグラフの基本的な使用方法を説明します。サンプルデータには、俳優と映画に関する情報が含まれています。
プラグインの作成
このトピックの操作を実行するには、特権アカウントを使用する必要があります。特権アカウントの作成方法の詳細については、「データベースアカウントの作成」をご参照ください。
age 拡張機能は手動で作成できません。この機能を使用するには、チケットを送信して、弊社に拡張機能の作成を依頼する必要があります。
CREATE EXTENSION age;データベースの設定
各接続で、クエリを簡素化するために ag_catalog スキーマを search_path に追加し、get_cypher_keywords 関数を使用して拡張機能をロードします。
Data Management (DMS) を使用して search_path を設定すると、互換性の問題が発生する可能性があります。このような場合は、PolarDB-Tools を使用して関連する文を実行できます。
SET search_path = ag_catalog, "$user", public;
SELECT * FROM get_cypher_keywords() limit 0;特権アカウントを使用してデータベースパラメーターを設定し、拡張機能を永続的にロードすることができます。これにより、各接続で前述の操作を繰り返す必要がなくなり、プロセスが簡素化されます。
ALTER DATABASE <dbname> SET search_path = "$user", public, ag_catalog;
ALTER DATABASE <dbname> SET session_preload_libraries TO 'age';一般ユーザーへの AGE の使用許可
ag_catalog スキーマに対する USAGE 権限を一般ユーザーに付与できます。
GRANT USAGE ON SCHEMA ag_catalog TO <username>;一般ユーザーが読み取り/書き込みユーザーである場合は、テーブルを作成するための CREATE 権限も付与する必要があります。
GRANT CREATE ON DATABASE <dbname> TO <username>;クエリ構造
PolarDB では、Cypher クエリは ag_catalog スキーマ内の cypher という名前の関数を呼び出すことによって構築されます。この関数は SETOF レコードを返します。以下は典型的なクエリの例です。
SELECT * FROM cypher('graph_name', $$
/* ここに Cypher クエリを記述します */
$$) AS (result1 agtype, result2 agtype);この例では、graph_name はグラフの名前です。/* */ 内のコンテンツを実際の Cypher クエリに置き換えてください。
グラフの作成
グラフを使用する前に、まずグラフを作成する必要があります。ag_catalog 名前空間の create_graph 関数を使用してグラフを作成できます。
構文:
SELECT create_graph('<graph_name>');例:
moviedb という名前のグラフを作成します。
SELECT create_graph('moviedb');データの挿入
次の SQL 文を使用して、サンプルデータを moviedb グラフに挿入できます。
SELECT * FROM cypher('moviedb', $$
CREATE (matrix:Movie {title: 'The Matrix', released: 1997})
CREATE (cloudAtlas:Movie {title: 'Cloud Atlas', released: 2012})
CREATE (forrestGump:Movie {title: 'Forrest Gump', released: 1994})
CREATE (keanu:Person {name: 'Keanu Reeves', born: 1964})
CREATE (robert:Person {name: 'Robert Zemeckis', born: 1951})
CREATE (tom:Person {name: 'Tom Hanks', born: 1956})
CREATE (tom)-[:ACTED_IN {roles: ['Forrest']}]->(forrestGump)
CREATE (tom)-[:ACTED_IN {roles: ['Zachry']}]->(cloudAtlas)
CREATE (robert)-[:DIRECTED]->(forrestGump)
$$) AS (result1 agtype);この文は、6 つのノードと 3 つのエッジを作成します。3 つのノードには Movie ラベルがあり、3 つのノードには Person ラベルがあります。2 つのエッジには ACTED_IN ラベルがあり、1 つのエッジには DIRECTED ラベルがあります。次のリレーションシップグラフが作成されます。

データのクエリ
データクエリ
Cypher では、MATCH および RETURN キーワードを使用してデータをクエリできます。
MATCHキーワードはパターンマッチングを実装し、指定されたパターンに一致するコンテンツを検索します。RETURNキーワードは、Cypher クエリが返してほしい値または結果を指定します。
構文:
SELECT * FROM cypher('graph_name', $$
MATCH <patterns>
RETURN <variables>
$$) AS (result1 agtype);例:
Movieラベルを持つすべてのノードを検索します。SELECT * FROM cypher('moviedb', $$ MATCH (m:Movie) RETURN m $$) AS (result1 agtype);PersonノードとMovieノードを接続するACTED_INラベルを持つエッジを検索します。SELECT * FROM cypher('moviedb', $$ MATCH (:Person)-[r:ACTED_IN]->(:Movie) RETURN r $$) AS (result1 agtype);
データフィルタリング
グラフでパターンマッチングを実行し、データの一部のみを返す必要がある場合は、WHERE 句を使用できます。この句を使用すると、ブール式を使用してデータのサブセットをフィルタリングできます。
例:
タイトルが
The Matrixのすべての映画をクエリします。SELECT * FROM cypher('moviedb', $$ MATCH (m:Movie) WHERE m.title = 'The Matrix' RETURN m $$) AS (result1 agtype);タイトルが
Forrest Gumpの映画のすべての俳優をクエリします。SELECT * FROM cypher('moviedb', $$ MATCH (p:Person)-[:ACTED_IN]->(m) WHERE m.title = 'Forrest Gump' RETURN p $$) AS (result1 agtype);2000 年以降に公開された映画の俳優をクエリします。
SELECT * FROM cypher('moviedb', $$ MATCH (p:Person)-[:ACTED_IN]->(m) WHERE m.released > 2000 RETURN p, m $$) AS (result1 agtype, result2 agtype);
ノードまたはエッジの作成
Cypher では、CREATE キーワードを使用して新しいノードまたはエッジを作成できます。
構文:
SELECT * FROM cypher('<graph_name>', $$
CREATE <patterns>
$$) AS (result1 agtype);例:
Personラベルを持つノードを作成します。name プロパティをTom Tykwerに、born プロパティを1965に設定します。SELECT * FROM cypher('moviedb', $$ CREATE (:Person {name: 'Tom Tykwer', born: 1965}) $$) AS (result1 agtype);Person
Tom Tykwerと映画Cloud Atlasの間にエッジを作成し、Tom Tykwerが映画Cloud Atlasを監督したことを表します。SELECT * FROM cypher('moviedb', $$ MATCH (p:Person), (m:Movie) WHERE p.name='Tom Tykwer' AND m.title='Cloud Atlas' CREATE (p)-[:DIRECTED]->(m) $$) AS (result1 agtype);
MERGE を使用した重複データ挿入の回避
同じ CREATE 文が複数回実行されると、複数の重複データエントリが挿入されます。このような重複データを防ぐために、挿入に MERGE キーワードを使用できます。MERGE は選択または挿入操作を実行します。まず、データがデータベースに既に存在するかどうかを確認します。データが存在する場合、データをそのまま返すか、既存のノードまたはリレーションシップを更新します。データが存在しない場合、Cypher は指定された情報に基づいてデータを作成します。
構文:
SELECT * FROM cypher('<graph_name>', $$
MERGE <patterns>
$$) AS (result1 agtype);例:
Personラベルを持つノードを作成します。name プロパティをTom Cruiseに、born プロパティを1962に設定します。SELECT * FROM cypher('moviedb', $$ MERGE (:Person {name: 'Tom Cruise', born: 1962}) $$) AS (result1 agtype);Tom HanksとTom Cruiseの間にエッジを作成し、友人関係を表します。SELECT * FROM cypher('moviedb', $$ MATCH (t1:Person),(t2:Person) WHERE t1.name='Tom Hanks' AND t2.name='Tom Cruise' MERGE (t1)-[:FRIEND]-(t2) $$) AS (result1 agtype);
更新
既に存在するノードやリレーションシップについては、必要なパターンに一致させてプロパティを変更し、SET キーワードを使用してプロパティを追加または更新できます。
構文:
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
SET <property>
RETURN <variable>
$$) AS (result1 agtype);例:
Person
Tom Tykwerの生年を 1970 に変更します。SELECT * FROM cypher('moviedb', $$ MATCH (p:Person {name: 'Tom Tykwer', born: 1965}) SET p.born = 1970 RETURN p $$) AS (result1 agtype);Person
Tom Tykwerに、値がmaleの gender プロパティを追加します。SELECT * FROM cypher('moviedb', $$ MATCH (p:Person {name: 'Tom Tykwer', born: 1970}) SET p.gender = 'male' RETURN p $$) AS (result1 agtype);
削除
Cypher では、DELETE キーワードを使用してノードとエッジを削除できます。
エッジの削除
エッジを削除するには、MATCH キーワードを使用してパターンに一致するエッジを見つけ、次に DELETE キーワードを使用してそれを削除します。
構文
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
DELETE <variable>
$$) AS (result1 agtype);例
Person Tom Tykwer と映画 Cloud Atlas の間の監督エッジを削除します。
SELECT * FROM cypher('moviedb', $$
MATCH (p:Person)-[r:DIRECTED]->(m:Movie)
WHERE p.name='Tom Tykwer' AND m.title='Cloud Atlas'
DELETE r
$$) AS (result1 agtype);ノードの削除
ノードを削除するには、MATCH キーワードを使用して条件を満たすノードを見つけ、次に DELETE キーワードを使用してそれを削除することもできます。
構文
SELECT * FROM cypher('<グラフ名>', $$
MATCH <パターン>
DELETE <変数>
$$) AS (result1 agtype);例
人物 Tom Tykwer を削除します。
SELECT * FROM cypher('moviedb', $$
MATCH (p:Person {name: 'Tom Tykwer', born: 1970})
DELETE p
$$) AS (result1 agtype);ノードとそのエッジの削除
関連するエッジがある場合、ノードを直接削除することはできません。DETACH DELETE 構文を使用して、ノードのエッジリレーションシップを削除してからノード自体を削除できます。
構文
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
DETACH DELETE <variable>
$$) AS (result1 agtype);例
人物 Tom Hanks と、それに関連付けられたエッジを削除します。
SELECT * FROM cypher('moviedb', $$
MATCH (p:Person {name: 'Tom Hanks', born: 1956})
DETACH DELETE p
$$) AS (result1 agtype);プロパティの削除
ノードまたはエッジのプロパティが不要になった場合は、REMOVE キーワードを使用してプロパティを削除できます。
構文
SELECT * FROM cypher('<graph_name>', $$
MATCH <match_pattern>
REMOVE <property>
$$) AS (result1 agtype);例
映画 Cloud Atlas の released プロパティを削除します。
SELECT * FROM cypher('moviedb', $$
MATCH (m:Movie {title: 'Cloud Atlas', released: 2012})
REMOVE m.released
RETURN m
$$) AS (result1 agtype);可視化ツール
PolarDB for PostgreSQL と は、オープンソースのグラフエンジン Apache AGE を統合しています。これにより、同じクラスター内で標準 SQL と業界をリードする openCypher グラフクエリ言語の両方を使用できます。グラフデータを効率的に格納、クエリ、分析して、複雑なリレーションシップシナリオに対応できます。詳細については、「グラフアプリケーション」をご参照ください。
