このトピックでは、AnalyticDB for PostgreSQL でグラフ分析エンジンを作成し、使用する方法について説明します。
Cypher とは
Cypher は、openCypher プロジェクトによって提供されるオープンソースの宣言型クエリ言語です。SQL に似ていますが、グラフデータ構造に最適化されています。直感的で自然言語に近い構文を持つ Cypher は、ノード間のリレーションシップを明確に表現し、グラフのマッチングパターンを定義できるため、効率的かつ容易にグラフデータをクエリできます。例:
MATCH (n:nodes)-[r:ARE_CONNECTED_TO]->(o:otherNodes)
RETURN n,r,o上記の Cypher クエリは、パターンマッチングを使用して、特定の条件を満たすすべてのノードとリレーションシップをグラフ内で見つけます。クエリにおいて、(n:nodes) は nodes ラベルを持つノードを表し、n はそのエイリアスです。[r:ARE_CONNECTED_TO] は ARE_CONNECTED_TO ラベルを持つリレーションシップを表し、r はそのエイリアスです。(o:otherNodes) は otherNodes ラベルを持つターゲットノードを表し、o はそのエイリアスです。このクエリは、このパターンに一致するすべてのソースノード、ターゲットノード、およびそれらの間のリレーションシップを返します。
構文
ノードの構文
Cypher では、一対の丸括弧 () を使用してノードを表すことができます。一般的なノードの表現とその意味は次のとおりです。
():匿名ノード。これは、ラベルが指定されていない匿名ノードを表します。通常、任意のノードに一致させるために使用されます。(node):変数を持つノード。これにより、nodeのような変数名をノードに割り当て、クエリ内で参照できるようになります。(:City):ラベルを持つノード。これは、Cityラベルを持つノードを表します。ラベルは、リレーショナルデータベースのテーブル名や分類識別子に似ています。特定のタイプのノードをフィルターするために使用できます。(city:City):変数とラベルを持つノード。これにより、変数cityとラベルCityがノードに割り当てられます。これにより、ノードが参照しやすくなり、そのタイプが明確に定義されます。(city:City {name: 'Hangzhou'}):プロパティを持つノード。これにより、プロパティ{name: 'Hangzhou'}がノードに追加され、その特性がさらに定義されます。これは、リレーショナルデータベースのWHERE句に似ており、特定のプロパティ値を持つノードを完全に一致させることができます。(city:City {name: 'Hangzhou', province: 'Zhejiang'}):複数のプロパティを持つノード。ノードは複数のプロパティを持つことができ、より複雑なフィルター条件をサポートします。
リレーションシップの構文
Cypher では、一対のハイフン -- を使用してリレーションシップを表すことができます。有向リレーションシップの場合、--> のように一方の端に矢印を追加できます。リレーションシップをより詳細に記述するには、角括弧 [] を使用できます。角括弧には、変数、タイプ、プロパティなどの情報を含めることができます。一般的なリレーションシップの表現とその意味は次のとおりです。
--:タイプが指定されていない、匿名の無向リレーションシップ。-->:タイプが指定されていない、匿名の有向リレーションシップ。-[role]->:リレーションシップに変数roleを定義し、クエリ内で参照できるようにします。-[:ACTED_IN]->:リレーションシップのタイプをACTED_INとして指定します。これはノードのラベルに似ています。-[role:ACTED_IN]->:リレーションシップに変数roleとタイプACTED_INの両方を定義します。-[role:ACTED_IN {roles: ['Neo']}]->:リレーションシップにプロパティ{roles: ['Neo']}を追加し、その特定の特性を記述します。
リレーションシップの構文とセマンティクスは、ノードのものと非常によく似ています。
変数:リレーションシップ内の変数 (例:
role) は、ノード内の変数に似ています。クエリ内で参照するために使用できます。タイプ:リレーションシップのタイプ (例:
ACTED_IN) は、ノードのラベルに似ています。特定のリレーションシップを分類し、フィルターするために使用できます。プロパティ:リレーションシップのプロパティ (例:
{roles: ['Neo']}) は、ノードのプロパティと同等です。キーと値のフォーマットをサポートし、リレーションシップを詳細に記述します。
パターンの構文
ノードとリレーションシップの構文を統合して、豊富なセマンティック情報を持つパターンを構築できます。パターン式の例:
(city_from:City {province: 'Zhejiang'})-[:NEXT_TO]-(city_next:City {province: 'Jiangsu'})
式の意味:
(city_from:City {province: 'Zhejiang'}):Cityラベルと、provinceプロパティが'Zhejiang'であるノードを表します。これは浙江省にある都市です。(city_next:City {province: 'Jiangsu'}):Cityラベルと、provinceプロパティが'Jiangsu'である別のノードを表します。これは江蘇省にある都市です。-[:NEXT_TO]-:タイプがNEXT_TOの無向エッジを表します。これは、2つの都市が地理的に隣接していることを示します。
このパターン式は、浙江省と江蘇省の隣接する都市間のリレーションシップに一致します。
city_fromとcity_nextは、それぞれ浙江省と江蘇省の都市ノードを表します。[:NEXT_TO]は、2つの都市間の地理的な隣接関係を表します。
バージョンの制限事項
AnalyticDB for PostgreSQL V7.0 インスタンスの V7.2.1.0 以降。
AnalyticDB for PostgreSQL コンソールのインスタンスの [基本情報] ページでマイナーバージョンを確認できます。ご利用のインスタンスが必要なバージョンを満たしていない場合は、インスタンスのマイナーバージョンを更新してください。
前提条件
AnalyticDB for PostgreSQL インスタンスに age 拡張機能がインストールされていること。
age 拡張機能は、マイナーエンジンバージョンが 7.2.1.4 以降の AnalyticDB for PostgreSQL V7.0 インスタンスに自動的にインストールされます。
クエリを簡略化するために、`ag_catalog` スキーマが `search_path` パラメーターで指定された検索パスに追加されていること。次のいずれかのメソッドを使用できます。
セッションレベルの構成。
SET search_path TO "$user", public, ag_catalog;データベースレベルの永続的な構成。
ALTER DATABASE <database_name> SET search_path TO "$user", public, ag_catalog;
(オプション) 初期アカウントまたは RDS_SUPERUSER 権限を持つ特権アカウントを使用して、他のユーザーに `ag_catalog` スキーマへのアクセスを許可します。
GRANT USAGE ON SCHEMA ag_catalog TO <username>;
グラフ分析エンジンの作成と使用
グラフの作成
構文
create_graph 関数を使用してグラフを作成できます。
SELECT create_graph('<graph_name>');パラメーター
graph_name:グラフの名前。
例
SELECT create_graph('relation');データの書き込み
構文
ag_catalog の cypher 関数を式で呼び出して、ノードとリレーションシップを作成します。
SELECT * FROM cypher('<graph_name>', $$
/* Cypher 式を記述します。*/
$$) AS (result_a agtype, result_b agtype);例
以下のグラフには、3 つの人物ノード (Zhang San、Li Si、Wang Wu) と 2 つの会社ノード (会社 A、会社 C) が含まれています。人物と会社は EMPLOYED エッジで接続され、人物同士は FRIENDS エッジおよび TEACHER エッジで接続されています。
relation グラフにデータを書き込みます。
SELECT * FROM cypher('relation', $$
CREATE (ZhangSan:Person {name: 'Zhang San'})
CREATE (LiSi:Person {name: 'Li Si'})
CREATE (WangWu:Person {name: 'Wang Wu'})
CREATE (company_a:Company {name: 'Company A'})
CREATE (company_c:Company {name: 'Company C'})
CREATE (ZhangSan)-[:EMPLOYED]->(company_a)
CREATE (LiSi)-[:EMPLOYED]->(company_c)
CREATE (WangWu)-[:EMPLOYED]->(company_a)
CREATE (ZhangSan)-[:FRIENDS]->(LiSi)
CREATE (WangWu)-[:TEACHER]->(ZhangSan)
$$) AS (result_a agtype)データのクエリ
構文
MATCH 文と RETURN 文を使用してデータをクエリできます。MATCH は一致させるグラフパターンを定義し、見つけるべきノード、リレーションシップ、およびそれらのプロパティを指定します。RETURN はクエリ結果で返す内容を指定します。
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
WHERE <expression> --optional
RETURN <variables>
$$) AS (result_a agtype);すべてのデータのクエリ
Personラベルを持つすべてのノードを検索します。SELECT * FROM cypher('relation', $$ MATCH (m:Person) RETURN m $$) AS (result_a agtype)結果は次のとおりです。
result_a ----------------------------------------------------------------------------------------- {"id": 844424930131969, "label": "Person", "properties": {"name": "Zhang San"}}::vertex {"id": 844424930131970, "label": "Person", "properties": {"name": "Li Si"}}::vertex {"id": 844424930131971, "label": "Person", "properties": {"name": "Wang Wu"}}::vertex (3 行)EMPLOYEDラベルを持つすべてのエッジを検索します。SELECT * FROM cypher('relation', $$ MATCH (:Person)-[r:EMPLOYED]->(:Company) RETURN r $$) AS (result_a agtype);次の結果が返されます。
result_a -------------------------------------------------------------------------------------------------------------------------------- {"id": 1407374883553281, "label": "EMPLOYED", "end_id": 1125899906842625, "start_id": 844424930131969, "properties": {}}::edge {"id": 1407374883553282, "label": "EMPLOYED", "end_id": 1125899906842626, "start_id": 844424930131970, "properties": {}}::edge {"id": 1407374883553283, "label": "EMPLOYED", "end_id": 1125899906842625, "start_id": 844424930131971, "properties": {}}::edge (3 rows)
部分的なデータ (フィルターされたデータ) のクエリ
グラフでパターンマッチングを実行し、特定のデータを返す必要がある場合、WHERE 句を使用して、条件に基づいて一致した結果をフィルターできます。
A社のすべての従業員をクエリします。
SELECT * FROM cypher('relation', $$ MATCH (p:Person)-[:EMPLOYED]->(a:Company) WHERE a.name='A社' RETURN p $$) AS (result_a agtype);結果は次のとおりです。
result_a ----------------------------------------------------------------------------------------- {"id": 844424930131969, "label": "Person", "properties": {"name": "Zhang San"}}::頂点 {"id": 844424930131971, "label": "Person", "properties": {"name": "Wang Wu"}}::頂点 (2 行)ワン・ウーの学生を照会します。
SELECT * FROM cypher('relation', $$ MATCH (p1:Person)-[:TEACHER]->(p2:Person) WHERE p1.name='Wang Wu' RETURN p2 $$) AS (result_a agtype)結果は次のとおりです。
result_a ----------------------------------------------------------------------------------------- {"id": 844424930131969, "label": "Person", "properties": {"name": "Zhang San"}}::vertex (1 行)
データ (ノードまたはエッジ) の更新
ノードやリレーションシップを含むグラフ内の既存のデータについて、ターゲットオブジェクトを照合し、SET キーワードを使用してプロパティを追加または更新することで、データを変更できます。
構文
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
SET <property>
RETURN <variable>
$$) AS (result_a agtype)例
Zhang San の名前を Zhang 3 に変更します。
SELECT * FROM cypher('relation', $$ MATCH (p:Person {name:'Zhang San'}) SET p.name='Zhang 3' RETURN p $$) AS (result_a agtype);更新結果は次のとおりです。
result_a --------------------------------------------------------------------------------------- {"id": 844424930131969, "label": "Person", "properties": {"name": "Zhang 3"}}::vertex (1 行)Zhang San に、値が male の gender ラベルを追加します。
SELECT * FROM cypher('relation', $$ MATCH (p:Person {name: 'Zhang 3'}) SET p.gender = 'male' RETURN p $$) AS (result_a agtype);更新結果は次のとおりです。
result_a --------------------------------------------------------------------------------------------------------- {"id": 844424930131969, "label": "Person", "properties": {"name": "田中三郎", "gender": "male"}}::vertex (1 row)
データの削除
ラベルの削除
ノードまたはエッジのラベルが不要になった場合、REMOVE キーワードを使用して削除できます。
構文
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
REMOVE <property>
$$) AS (result_a agtype);例
Zhang San から性別ラベルを削除します。
SELECT * FROM cypher('relation', $$
MATCH (p:Person {name: 'Zhang 3'})
REMOVE p.gender
RETURN p
$$) AS (result_a agtype);ノードの削除
DELETE キーワードを使用してノードまたはエッジを削除できます。
構文
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
DELETE <variable>
$$) AS (result_a agtype);例
Zhao Liu という名前のノードを作成し、次にそのノードを削除します。
-- Zhao Liu という名前のノードを作成します。
SELECT * FROM cypher('relation', $$
CREATE (:Person {name: 'Zhao Liu'})
$$) AS (result_a agtype)
-- ノードを削除します。
SELECT * FROM cypher('relation', $$
MATCH(p:Person {name: 'Zhao Liu'})
DELETE p
$$) AS (result_a agtype)エッジを持つノードを直接削除することはできません。代わりに、DETACH DELETE 文を使用してノードとそのエッジを削除する必要があります。
エッジの削除
まず、「Zhao Liu」という名前のノードと、Zhao Liu が Company C に雇用されていることを示すエッジを追加します。次に、その雇用関係を削除します。関係を削除するには、WHERE 句で人物名と会社名を指定します。
-- Zhao Liu という名前のノードと、Zhao Liu と C 社の間の EMPLOYED エッジを作成します。
SELECT * FROM cypher('relation', $$
CREATE (ZhaoLiu:Person {name: 'Zhao Liu'})
CREATE (ZhaoLiu)-[:EMPLOYED]->(:Company {name: 'Company C'})
$$) AS (result_a agtype);
-- エッジを削除します。
SELECT * FROM cypher('relation', $$
MATCH (p:Person)-[r:EMPLOYED]->(c:Company)
WHERE p.name='Zhao Liu' AND c.name='Company C'
DELETE r
$$) AS (result_a agtype);ノードとそのエッジの削除
ノードに関連するエッジがある場合、ノードを直接削除することはできません。DETACH DELETE 文を使用して、ノードとそのエッジの両方を削除する必要があります。
構文
SELECT * FROM cypher('<graph_name>', $$
MATCH <patterns>
DETACH DELETE <variable>
$$) AS (result_a agtype);例
Zhao Liu という名前のノードと、Zhao Liu と Company C の間に EMPLOYED エッジを作成します。次に、そのエッジと Zhao Liu ノードを削除します。
-- Zhao Liu という名前のノードと、Company C との間の EMPLOYED エッジを作成します。
SELECT * FROM cypher('relation', $$
CREATE (ZhaoLiu:Person {name: 'Zhao Liu'})
CREATE (ZhaoLiu)-[:EMPLOYED]->(:Company {name: 'Company C'})
$$) AS (result_a agtype);
-- ノードとそのエッジを削除します。
SELECT * FROM cypher('relation', $$
MATCH (p:Person {name: 'Zhao Liu'})
DETACH DELETE p
$$) AS (result_a agtype);