このページでは、Spanner Graph でグラフパスを操作する方法について説明します。
グラフ データベースでは、グラフパス データ型はエッジと交互に配置された一連のノードを表し、これらのノードとエッジがどのように関連しているかを示します。パスデータ型の詳細については、グラフパスの種類をご覧ください。
Spanner Graph Language(GQL)を使用すると、グラフパスを構築してクエリを実行できます。このドキュメントの例では、Spanner Graph を設定してクエリを実行するページと同じ Spanner Graph スキーマを使用します。
グラフパスを作成する
グラフパスを作成するには、グラフパターンでパス変数を作成するか、PATH
関数を使用します。
パス変数を使用してグラフパスを作成することをおすすめします。パス変数を作成する形式は次のとおりです。
MATCH p = PATH_PATTERN
詳細については、グラフパターンをご覧ください。
例
次の例のクエリは、FinGraph
内の口座間の送金パターンを検索します。
GRAPH FinGraph
MATCH p = (src:Account {id: 16})-[t1:Transfers]->(mid:Account)-[t2:Transfers]->
(dst:Account {id: 7})
RETURN TO_JSON(p) AS full_path;
結果
full_path |
---|
[{"identifier": ..., "properties": {"id": 16, ...}, ...}, {"identifier": ..., "properties": {"amount": 300.0, ...}, ...}, ...] |
この結果は、クエリがデータベースで Account -> Transfers -> Account
パターンを見つけたことを示しています。
グラフパスをクエリする
次のパス固有の関数を使用して、グラフパスをクエリできます。Spanner Graph クエリの一般的な情報については、クエリの概要をご覧ください。
EDGES
EDGES
関数は、グラフパス内のすべてのエッジを返します。セマンティクスの詳細については、EDGES
をご覧ください。
例
このクエリは、中間口座を経由する 2 つのアカウント間のパスを検索します。パス内の 2 番目の Transfers
エッジの量を返します。これは、src
と mid
の間、または mid
と dst
の間のいずれかです。
GRAPH FinGraph
MATCH p = (src:Account {id: 7})-[t1:Transfers]->{1,3}(mid:Account)-[t2:Transfers]->
{1,3}(dst:Account {id: 16})
LET second_edge = EDGES(p)[1]
RETURN DISTINCT src.id AS src, dst.id AS dst, second_edge.amount AS second_edge_amount;
結果
src | dst | second_edge_amount |
---|---|---|
7 | 16 | 300 |
NODES
NODES
関数は、グラフパス内のすべてのノードを返します。セマンティクスの詳細については、NODES
をご覧ください。
例
このクエリは、2 つの転送のグラフパスを見つけて、パスを表す JSON リストを返します。
GRAPH FinGraph
MATCH p = (src:Account)-[t1:Transfers]->(mid:Account)-[t2:Transfers]->(dst:Account)
RETURN TO_JSON(NODES(p)) AS nodes;
結果
ノード |
---|
[{"identifier": "...", "properties": {"id": 16}, ...}, {"identifier": "...", "properties": {"id": 20, ...}, ...] |
... |
PATH_FIRST
PATH_FIRST
関数は、グラフパス内の最初のノードを検索します。セマンティクスの詳細については、PATH_FIRST
をご覧ください。
例
このクエリは、2 つの転送のグラフパス内の最初のノードを検索します。Account
ノードのラベルとアカウントのニックネームを返します。
GRAPH FinGraph
MATCH p = -[:Transfers]->{1,3}(dst:Account{id: 7})
RETURN DISTINCT PATH_FIRST(p).id AS can_reach_target;
結果
can_reach_target |
---|
7 |
16 |
20 |
PATH_LAST
PATH_LAST
関数は、グラフパスの最後のノードを検索します。セマンティクスの詳細については、PATH_LAST
をご覧ください。
例
このクエリは、2 つの転送のグラフパス内の最後のノードを検索します。Account
ノードのラベルとアカウントのニックネームを返します。
GRAPH FinGraph
MATCH p =(start:Account{id: 7})-[:Transfers]->{1,3}
RETURN DISTINCT PATH_LAST(p).id as can_reach_target;
結果
can_reach_target |
---|
7 |
16 |
20 |
PATH_LENGTH
PATH_LENGTH
関数は、グラフパス内のエッジの数を検索します。セマンティクスの詳細については、PATH_LENGTH
をご覧ください。
例
このクエリは、1 ~ 3 個の転送を含むグラフパス内のエッジの数を検索します。
GRAPH FinGraph
MATCH p = (src:Account)-[e:Transfers]->{1,3}(dst:Account)
RETURN PATH_LENGTH(p) AS num_transfers, COUNT(*) AS num_paths;
結果
num_transfers | num_paths |
---|---|
1 | 5 |
2 | 7 |
3 | 11 |
IS_ACYCLIC
IS_ACYCLIC
関数は、グラフパスに繰り返しノードの有無を確認します。繰り返しが見つかった場合は TRUE
を返し、それ以外の場合は FALSE
を返します。セマンティクスの詳細については、IS_ACYCLIC
をご覧ください。
例
このクエリは、このグラフパスに重複するノードがあるかどうかを確認します。
GRAPH FinGraph
MATCH p = (src:Account)-[t1:Transfers]->(mid:Account)-[t2:Transfers]->(dst:Account)
RETURN IS_ACYCLIC(p) AS is_acyclic_path, src.id AS source_account_id,
mid.id AS mid_account_id, dst.id AS dst_account_id;
結果
is_acyclic_path | source_account_id | mid_account_id | dst_account_id |
---|---|---|---|
TRUE | 16 | 20 | 7 |
TRUE | 20 | 7 | 16 |
TRUE | 20 | 7 | 16 |
FALSE | 16 | 20 | 16 |
TRUE | 7 | 16 | 20 |
TRUE | 7 | 16 | 20 |
FALSE | 20 | 16 | 20 |
IS_TRAIL
IS_TRAIL
関数は、グラフパスに繰り返しエッジがあるかどうかを確認します。繰り返しが見つかった場合は TRUE
を返し、それ以外の場合は FALSE
を返します。セマンティクスの詳細については、IS_TRAIL
をご覧ください。
例
このクエリは、このグラフパスに重複するエッジがあるかどうかを確認します。
GRAPH FinGraph
MATCH p = (src:Account)-[t1:Transfers]->(mid1:Account)-[t2:Transfers]->
(mid2:Account)-[t3:Transfers]->(dst:Account)
WHERE src.id < dst.id
RETURN IS_TRAIL(p) AS is_trail_path, t1.id AS t1_id, t2.id AS t2_id, t3.id AS t3_id;
結果
is_trail_path | t1_id | t2_id | t3_id |
---|---|---|---|
FALSE | 16 | 20 | 16 |
TRUE | 7 | 16 | 20 |
TRUE | 7 | 16 | 20 |
パスモード
Spanner Graph では、重複するノードとエッジがデフォルトで返されます。次のパスモードを使用すると、指定されたモードに基づいて、ノードとエッジが繰り返されるパスを含めたり除外したりできます。セマンティクスの詳細については、パスモードをご覧ください。
WALK
デフォルトの WALK
パスモードでは、ノードやエッジが繰り返されるパスも含め、すべてのパスが保持されます。
例
次のクエリは、定量化されていないパスパターンで WALK
パスモードを使用する方法を示しています。結果の最初のパスでは、t1
と t3
に同じエッジが使用されています。
GRAPH FinGraph
MATCH p = WALK (src:Account)-[t1:Transfers]->(mid1:Account)-[t2:Transfers]->
(mid2:Account)-[t3:Transfers]->(dst:Account)
WHERE src.id < dst.id
RETURN t1.id AS transfer1_id, t2.id AS transfer2_id, t3.id AS transfer3_id;
結果
transfer1_id | transfer2_id | transfer3_id |
---|---|---|
16 | 20 | 16 |
7 | 16 | 20 |
7 | 16 | 20 |
ACYCLIC
デフォルトの ACYCLIC
パスモードでは、ノードが繰り返されるパスが除外されます。
例
次のクエリは、定量化されていないパスパターンで ACYCLIC
パスモードを使用する方法を示しています。src
ノードと dst
ノードが同じパスは除外されます。
GRAPH FinGraph
MATCH p = ACYCLIC (src:Account)-[t1:Transfers]->(mid:Account)-[t2:Transfers]->(dst:Account)
RETURN src.id AS account1_id, mid.id AS account2_id, dst.id AS account3_id;
結果
account1_id | account2_id | account3_id |
---|---|---|
20 | 7 | 16 |
20 | 7 | 16 |
7 | 16 | 20 |
7 | 16 | 20 |
16 | 20 | 7 |
TRAIL
デフォルトの TRAIL
パスモードでは、エッジが繰り返されるパスが除外されます。
例
次のクエリは、定量化されていないパスパターンで TRAIL
パスモードを使用する方法を示しています。t1
エッジと t3
エッジが同じパスは除外されます。
GRAPH FinGraph
MATCH p = TRAIL (src:Account)-[t1:Transfers]->(mid1:Account)-[t2:Transfers]->
(mid2:Account)-[t3:Transfers]->(dst:Account)
RETURN
t1.id AS transfer1_id, t2.id AS transfer2_id, t3.id AS transfer3_id;
結果
transfer1_id | transfer2_id | transfer3_id |
---|---|---|
16 | 20 | 7 |
16 | 20 | 7 |
20 | 7 | 16 |
20 | 7 | 16 |
7 | 16 | 20 |
7 | 16 | 20 |
7 | 16 | 20 |
7 | 16 | 20 |
20 | 16 | 20 |
パス検索の接頭辞
パス検索接頭辞を使用すると、パスパターンを制限して、各データ パーティションから最短パスを返すことができます。セマンティクスの詳細については、パス検索接頭辞をご覧ください。
ANY SHORTEST
ANY SHORTEST
パス検索接頭辞は、各データパーティションのパターンに一致する最短パス(エッジ数が最も少ないパス)を返します。パーティションごとに最短経路が複数ある場合は、いずれかを返します。
例
次のクエリは、各 [a, b]
ペア間の任意のパスに一致します。
GRAPH FinGraph
MATCH p = ANY SHORTEST (a:Account)-[t:Transfers]->{1,4}(b:Account)
WHERE a.is_blocked
LET total_amount = SUM(t.amount)
RETURN a.id AS account1_id, total_amount, b.id AS account2_id;
結果
account1_id | total_amount | account2_id |
---|---|---|
16 | 500 | 16 |
16 | 800 | 7 |
16 | 300 | 20 |
変換規則
詳細については、GRAPH_PATH 変換ルールをご覧ください。
ユースケースの例
次のユースケースの例では、すべてのアカウントがアカウント ID 20
から 1 ~ 3 つのアカウントを経由して転送されています。
GRAPH FinGraph
MATCH p = (start:Account {id: 20})-[:Transfers]->{1,3}(dst:Account)
RETURN DISTINCT dst.id AS dst;
結果
dst |
---|
7 |
16 |
20 |
ただし、アカウント ID 20
を返すクエリは、アカウント ID 20
で始まるため、範囲が広すぎる可能性があります。より具体的な結果を表示するには、繰り返しノードのない非巡回グラフパスのみを表示するようにクエリを適用します。手順は次のとおりです。
MATCH p = ACYCLIC <path_pattern>
を使用します。- クエリで
IS_ACYCLIC(p)
フィルタを適用する
次のクエリでは MATCH p = ACYCLIC PATH_PATTERN
を使用しています。
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->{1,3}(dst:Account)
RETURN DISTINCT dst.id AS dst;
結果
dst |
---|
7 |
16 |
送金の最初のアカウントを確認するには、次のクエリを実行します。
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})(-[:Transfers]->
(nexts:Account)){1,3}(dst:Account)
RETURN dst.id AS dst, ARRAY_AGG(DISTINCT nexts[0].id) AS unique_starts;
このクエリは、nexts
を使用して結果を取得する量化パス内に新しい変数を導入するため、従来型ではありません。パス変数を使用すると、クエリを簡素化できます。
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->{1,3}(dst:Account)
RETURN dst.id AS dst, ARRAY_AGG(DISTINCT NODES(p)[OFFSET(1)].id) AS unique_starts;
NODES(p)
を使用すると、パス上のすべてのノードが返されます。最初のノード アカウントが start
として指定されているため、次のアカウント(最初のオフセット)が、資金が最初に移行されるアカウントになります。
結果
dst | unique_starts |
---|---|
7 | 16、7 |
パスは、複数の量化パスがある場合に便利です。start
から見つかったパスがアカウント ID 7
を通過する必要があるという制約を追加できます。
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->
{1,3}(mid:Account {id: 7})-[:Transfers]->{1,3}(dst:Account)
RETURN dst.id AS dst,
ARRAY_AGG(DISTINCT NODES(p)[OFFSET(1)].id) AS unique_starts;
MATCH
ステートメントは変更されましたが、クエリの残りの部分は変更する必要はありません。パス変数を使用しないと、検査する量化パスを Spanner が静的に把握できない場合があります。
パス変数を使用すると、すべての転送の合計を取得できます。
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->
{1,3}(mid:Account {id: 7})-[:Transfers]->{1,3}(dst:Account)
LET all_transfers = EDGES(p)
LET transfer_amounts = SUM(all_transfers.amount)
RETURN dst.id AS dst,
ARRAY_AGG(DISTINCT NODES(p)[OFFSET(1)].id) AS participating_neighbor_nodes, transfer_amounts;
結果
dst | participating_neighbor_nodes | transfer_amounts |
---|---|---|
16 | 7 | 600 |
16 | 7 | 800 |