圖表查詢總覽
BigQuery Graph 可讓您編寫圖譜查詢,比對節點、邊緣和路徑模式,並使用Graph Query Language (GQL) 掃遍關係。本文件中的範例參照名為 FinGraph 的圖表,其中顯示人員、他們擁有的帳戶,以及帳戶之間的轉帳關係。如要瞭解圖表的定義,請參閱 FinGraph 範例。
查詢結構
圖表查詢包含圖表名稱,後方則是一或多個線性查詢陳述式。每個線性查詢都包含一或多個陳述式,可讓您處理圖形資料,找出模式比對、定義變數、篩選及轉換中繼資料,以及傳回結果。執行圖表查詢的方式與在 BigQuery 執行 SQL 查詢相同。
圖表模式比對
圖譜模式比對:在圖譜中尋找特定模式。最基本的模式是元素模式,例如與節點相符的節點模式,以及與邊相符的邊模式。
節點模式
節點模式會比對圖中的節點。這個模式包含成對的括號,其中可包含圖表模式變數、標籤運算式和屬性篩選器。
找出所有節點
下列查詢會傳回圖表中的所有節點。圖表模式變數 n 會繫結至相符的節點。在這種情況下,節點模式會比對圖表中的所有節點。
GRAPH graph_db.FinGraph
MATCH (n)
RETURN LABELS(n) AS label, n.id;
這項查詢會傳回 label 和 id:
label |
id |
|---|---|
Account |
7 |
Account |
16 |
Account |
20 |
Person |
1 |
Person |
2 |
Person |
3 |
找出所有具有特定標籤的節點
下列查詢會比對圖表中具有 Person
標籤的所有節點。查詢會傳回相符節點的標籤和部分屬性。
GRAPH graph_db.FinGraph
MATCH (p:Person)
RETURN LABELS(p) AS label, p.id, p.name;
這項查詢會傳回相符節點的下列屬性:
label |
id |
name |
|---|---|---|
Person |
1 |
Alex |
Person |
2 |
Dana |
Person |
3 |
Lee |
找出與標籤運算式相符的所有節點
您可以使用一或多個邏輯運算子建立標籤運算式。舉例來說,下列查詢會比對圖表中所有具有 Person 或 Account 標籤的節點。圖表模式變數 n 會公開具有 Person 或 Account 標籤的節點的所有屬性。
GRAPH graph_db.FinGraph
MATCH (n:Person|Account)
RETURN LABELS(n) AS label, n.id, n.birthday, n.create_time;
請注意這項查詢結果的下列事項:
- 所有節點都有
id屬性。 - 與
Account標籤相符的節點具有create_time屬性,但沒有birthday屬性。這些節點的birthday屬性為NULL。 - 符合
Person標籤的節點具有birthday屬性,但沒有create_time屬性。這些節點的create_time屬性為NULL。
label |
id |
birthday |
create_time |
|---|---|---|---|
Account |
7 |
NULL |
2020-01-10T14:22:20.222Z |
Account |
16 |
NULL |
2020-01-28T01:55:09.206Z |
Account |
20 |
NULL |
2020-02-18T13:44:20.655Z |
Person |
1 |
1991-12-21T08:00:00Z |
NULL |
Person |
2 |
1980-10-31T08:00:00Z |
NULL |
Person |
3 |
1986-12-07T08:00:00Z |
NULL |
找出符合標籤運算式和屬性篩選條件的所有節點
下列查詢會比對圖表中具有 Person 標籤且 id 屬性等於 1 的所有節點:
GRAPH graph_db.FinGraph
MATCH (p:Person {id: 1})
RETURN LABELS(p) AS label, p.id, p.name, p.birthday;
結果大致如下:
label |
id |
name |
birthday |
|---|---|---|---|
Person |
1 |
Alex |
1991-12-21T08:00:00Z |
您可以使用 WHERE 子句,在標籤和屬性上建立更複雜的篩選條件。
下列查詢使用 WHERE 子句篩選 birthday 屬性早於 1990-01-10 的節點:
GRAPH graph_db.FinGraph
MATCH (p:Person WHERE p.birthday < '1990-01-10')
RETURN LABELS(p) AS label, p.name, p.birthday;
結果大致如下:
label |
name |
birthday |
|---|---|---|
Person |
Dana |
1980-10-31T08:00:00Z |
Person |
Lee |
1986-12-07T08:00:00Z |
邊緣模式
邊緣模式會比對節點之間的邊緣或關係。邊緣模式會以方括號 ([]) 括住,並包含 -、-> 或 <- 等符號來表示方向。邊緣模式可選擇包含圖表模式變數,繫結至相符的邊緣。
找出所有標籤相符的邊
這項查詢會傳回圖表中所有標籤為 Transfers 的邊。查詢會將圖表模式變數 e 繫結至相符的邊。
GRAPH graph_db.FinGraph
MATCH -[e:Transfers]->
RETURN e.Id as src_account, e.order_number;
結果大致如下:
src_account |
order_number |
|---|---|
7 |
304330008004315 |
7 |
304120005529714 |
16 |
103650009791820 |
20 |
304120005529714 |
20 |
302290001255747 |
找出符合標籤運算式和屬性篩選器的所有邊
下列查詢中的邊緣模式使用標籤運算式和屬性篩選器,找出所有標示為 Transfers 且符合指定訂單編號的邊緣:
GRAPH graph_db.FinGraph
MATCH -[e:Transfers {order_number: "304120005529714"}]->
RETURN e.Id AS src_account, e.order_number;
結果大致如下:
src_account |
order_number |
|---|---|
7 |
304120005529714 |
20 |
304120005529714 |
使用任何方向邊緣模式尋找所有邊緣
您可以在查詢中使用 any direction 邊緣模式 (-[]-),比對任一方向的邊緣。下列查詢會找出所有使用遭封鎖帳戶的轉帳:
GRAPH graph_db.FinGraph
MATCH (account:Account)-[transfer:Transfers]-(:Account {is_blocked:true})
RETURN transfer.order_number, transfer.amount;
結果大致如下:
order_number |
amount |
|---|---|
304330008004315 |
300 |
304120005529714 |
100 |
103650009791820 |
300 |
302290001255747 |
200 |
路徑模式
路徑模式是由交替的節點和邊緣模式組成。
使用路徑模式找出特定節點的所有路徑
下列查詢會找出從 Person 擁有的帳戶 (id 等於 2) 發起的所有帳戶轉帳。
每個相符結果都代表一條路徑,從 id 等於 2 的 Person 節點,透過使用 Owns 邊緣的已連結 Account 節點,進入使用 Transfers 邊緣的另一個 Account 節點。
GRAPH graph_db.FinGraph
MATCH
(p:Person {id: 2})-[:Owns]->(account:Account)-[t:Transfers]->
(to_account:Account)
RETURN
p.id AS sender_id, account.id AS from_id, to_account.id AS to_id;
結果大致如下:
sender_id |
from_id |
to_id |
|---|---|---|
2 |
20 |
7 |
2 |
20 |
16 |
量化路徑模式
比對量化邊緣模式
如要尋找可變長度的路徑,可以將數量詞套用至邊緣模式。下列查詢會尋找與來源 Account (id 值為 7) 相距一到三次轉帳的目標帳戶,藉此示範這項功能。
查詢會將數量詞 {1, 3} 套用至邊緣模式 -[e:Transfers]->。這會指示查詢比對重複 Transfers 邊緣模式一、二或三次的路徑。WHERE 子句用於從結果中排除來源帳戶。ARRAY_LENGTH 函式用於存取 group variable e。
GRAPH graph_db.FinGraph
MATCH (src:Account {id: 7})-[e:Transfers]->{1, 3}(dst:Account)
WHERE src != dst
RETURN src.id AS src_account_id, ARRAY_LENGTH(e) AS path_length, dst.id AS dst_account_id;
結果大致如下:
src_account_id |
path_length |
dst_account_id |
|---|---|---|
7 |
1 |
16 |
7 |
1 |
16 |
7 |
3 |
16 |
7 |
3 |
16 |
7 |
2 |
20 |
7 |
2 |
20 |
結果中的某些資料列會重複。這是因為在相同的來源和目的地節點之間,可能存在多個符合模式的路徑,而查詢會傳回所有路徑。
比對量化路徑模式
下列查詢會透過遭封鎖的中介帳戶,找出 Account 節點之間有一到兩個 Transfers 邊的路徑。
系統會量化括號內的路徑模式,並透過 WHERE 子句指定重複模式的條件。
GRAPH graph_db.FinGraph
MATCH
(src:Account)
((a:Account)-[:Transfers]->(b:Account {is_blocked:true}) WHERE a != b){1,2}
-[:Transfers]->(dst:Account)
RETURN src.id AS src_account_id, dst.id AS dst_account_id;
結果大致如下:
src_account_id |
dst_account_id |
|---|---|
7 |
20 |
7 |
20 |
20 |
20 |
群組變數
在量化模式中宣告的圖表模式變數,在該模式外存取時會變成「群組變數」。然後繫結至相符圖表元素的陣列。
您可以將群組變數當做陣列存取。圖表元素會按照在相符路徑中出現的順序保留。您可以使用水平匯總匯總群組變數。
存取權群組變數
在以下範例中,變數 e 的存取方式如下:
- 在
WHERE子句中,當圖表模式變數位於量化模式內時,繫結至單一邊緣。e.amount > 100 - 當群組變數位於量化模式之外時,在
RETURN陳述式中繫結至ARRAY_LENGTH(e)邊緣元素陣列。 - 做為繫結至邊緣元素陣列的群組變數,由量化模式外的
SUM(e.amount)匯總。這是水平匯總的範例。
GRAPH graph_db.FinGraph
MATCH
(src:Account {id: 7})-[e:Transfers WHERE e.amount > 100]->{0,2}
(dst:Account)
WHERE src.id != dst.id
LET total_amount = SUM(e.amount)
RETURN
src.id AS src_account_id, ARRAY_LENGTH(e) AS path_length,
total_amount, dst.id AS dst_account_id;
結果大致如下:
src_account_id |
path_length |
total_amount |
dst_account_id |
|---|---|---|---|
7 |
1 |
300 |
16 |
7 |
2 |
600 |
20 |
路徑搜尋前置字串
如要限制共用來源和目的地節點的群組內相符路徑,可以使用 ANY、ANY SHORTEST 或 ANY CHEAPEST 路徑搜尋前置字元。這些前置字元只能套用在完整路徑模式之前,不能套用在括號內。
使用 ANY 進行比對
下列查詢會找出與指定 Account 節點相距一或兩個
Transfers 的所有可連線不重複帳戶。
ANY 路徑搜尋前置字元可確保查詢只會傳回一組不重複 src 和 dst Account 節點之間的一條路徑。在以下範例中,雖然您可以透過來源 Account 節點的兩個不同路徑,使用 {id: 16} 連線至 Account 節點,但查詢只會傳回一個路徑。
GRAPH graph_db.FinGraph
MATCH ANY (src:Account {id: 7})-[e:Transfers]->{1,2}(dst:Account)
LET ids_in_path = ARRAY_CONCAT(ARRAY_AGG(e.Id), [dst.Id])
RETURN src.id AS src_account_id, dst.id AS dst_account_id, ids_in_path;
結果大致如下:
src_account_id |
dst_account_id |
ids_in_path |
|---|---|---|
7 |
16 |
7,16 |
7 |
20 |
7,16,20 |
使用 ANY SHORTEST 進行比對
ANY SHORTEST 路徑搜尋前置字元會為每組來源和目的地節點傳回單一路徑,並從邊緣數量最少的路徑中選取。
舉例來說,下列查詢會找出 id 值為 7 的 Account 節點,與 id 值為 20 的 Account 節點之間,其中一條最短路徑。查詢會考量具有一到三個 Transfers 邊的路徑。
GRAPH graph_db.FinGraph
MATCH ANY SHORTEST (src:Account {id: 7})-[e:Transfers]->{1, 3}(dst:Account {id: 20})
RETURN src.id AS src_account_id, dst.id AS dst_account_id, ARRAY_LENGTH(e) AS path_length;
結果大致如下:
src_account_id |
dst_account_id |
path_length |
|---|---|---|
7 |
20 |
2 |
使用 ANY CHEAPEST 進行比對
ANY CHEAPEST 路徑搜尋前置字元可確保每組來源和目標帳戶,查詢只會傳回一條總運算成本最低的路徑。
下列查詢會找出 Account 節點之間總運算成本最低的路徑。這項費用是根據 Transfers 邊緣的 amount 屬性總和計算。搜尋會考慮具有一到三個 Transfers 邊緣的路徑。
GRAPH graph_db.FinGraph
MATCH ANY CHEAPEST (src:Account)-[e:Transfers COST e.amount]->{1,3}(dst:Account)
LET total_cost = sum(e.amount)
RETURN src.id AS src_account_id, dst.id AS dst_account_id, total_cost;
結果大致如下:
src_account_id |
dst_account_id |
total_cost |
|---|---|---|
7 |
7 |
900 |
7 |
16 |
100 |
7 |
20 |
400 |
16 |
7 |
800 |
16 |
16 |
500 |
16 |
20 |
300 |
20 |
7 |
500 |
20 |
16 |
200 |
20 |
20 |
500 |
圖表模式
圖表模式由一或多個路徑模式組成,並以半形逗號 (,) 分隔。圖表模式可包含 WHERE 子句,讓您存取路徑模式中的所有圖表模式變數,以形成篩選條件。每個路徑模式都會產生一組路徑。
使用圖形模式進行比對
下列查詢會找出交易金額超過 200 的中介帳戶及其擁有者,資金會透過這些帳戶從來源帳戶轉移至封鎖帳戶。
下列路徑模式會形成圖表模式:
- 第一個模式會找出透過中介帳戶,從一個帳戶轉移至封鎖帳戶的路徑。
- 第二個模式會找出從帳戶到擁有者的路徑。
變數 interm 是兩個路徑模式之間的共同連結,因此 interm 必須在兩個路徑模式中參照相同的元素節點。這會根據 interm 變數建立等值彙整作業。
GRAPH graph_db.FinGraph
MATCH
(src:Account)-[t1:Transfers]->(interm:Account)-[t2:Transfers]->(dst:Account),
(interm)<-[:Owns]-(p:Person)
WHERE dst.is_blocked = TRUE AND t1.amount > 200 AND t2.amount > 200
RETURN
src.id AS src_account_id, dst.id AS dst_account_id,
interm.id AS interm_account_id, p.id AS owner_id;
結果大致如下:
src_account_id |
dst_account_id |
interm_account_id |
owner_id |
|---|---|---|---|
20 |
16 |
7 |
1 |
線性查詢陳述式
您可以將多個圖表陳述式鏈結在一起,形成線性查詢陳述式。陳述式會按照在查詢中顯示的順序執行。
每個陳述式都會將前一個陳述式的輸出內容做為輸入內容。第一個陳述式的輸入內容為空白。
最後一個陳述式的輸出內容就是最終結果。
舉例來說,您可以使用線性查詢陳述式,找出轉移至封鎖帳戶的最大金額。下列查詢會找出轉出至封鎖帳戶的金額最大的帳戶及其擁有者。
GRAPH graph_db.FinGraph
MATCH (src_account:Account)-[transfer:Transfers]->(dst_account:Account {is_blocked:true})
ORDER BY transfer.amount DESC
LIMIT 1
MATCH (src_account:Account)<-[owns:Owns]-(owner:Person)
RETURN src_account.id AS account_id, owner.name AS owner_name;
下表顯示各陳述式之間傳遞的中繼結果,說明這項程序。為求簡潔,這裡只列出部分屬性。
| 陳述式 | 中間結果 (縮寫) | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MATCH
(src_account:Account)
-[transfer:Transfers]->
(dst_account:Account {is_blocked:true})
|
|
||||||||||||
ORDER BY transfer.amount DESC |
|
||||||||||||
LIMIT 1 |
|
||||||||||||
MATCH
(src_account:Account)
<-[owns:Owns]-
(owner:Person)
|
|
||||||||||||
RETURN
src_account.id AS account_id,
owner.name AS owner_name
|
|
結果大致如下:
| account_id | owner_name |
|---|---|
7 |
Alex |
回傳敘述
RETURN 陳述式會指定要從相符模式傳回的內容。可存取圖表模式變數,並包含運算式和其他子句,例如 ORDER BY 和 GROUP BY。
BigQuery Graph 不支援以查詢結果的形式傳回圖表元素。如要傳回整個圖表元素,請使用 TO_JSON 函式。
以 JSON 格式傳回圖表元素
GRAPH graph_db.FinGraph
MATCH (n:Account {id: 7})
-- Returning a graph element in the final results is NOT allowed. Instead, use
-- the TO_JSON function or explicitly return the graph element's properties.
RETURN TO_JSON(n) AS n;
結果大致如下:
| n |
|---|
{"identifier":"mUZpbkdyYXBoLkFjY291bnQAeJEO","kind":"node","labels":["Account"],"properties":{"create_time":"2020-01-10T14:22:20.222Z","id":7,"is_blocked":false,"nick_name":"Vacation
Fund"}} |
使用 NEXT 關鍵字撰寫較大的查詢
您可以使用 NEXT 關鍵字,鏈結多個圖形線性查詢陳述式。第一個陳述式會收到空白輸入,後續每個陳述式的輸出則會成為下一個陳述式的輸入。
以下範例會鏈結多個圖表線性陳述式,找出收到最多轉帳的帳戶擁有者。您可以使用同一個變數 (例如 account),在多個線性陳述式中參照同一個圖表元素。
GRAPH graph_db.FinGraph
MATCH (:Account)-[:Transfers]->(account:Account)
RETURN account, COUNT(*) AS num_incoming_transfers
GROUP BY account
ORDER BY num_incoming_transfers DESC
LIMIT 1
NEXT
MATCH (account:Account)<-[:Owns]-(owner:Person)
RETURN account.id AS account_id, owner.name AS owner_name, num_incoming_transfers;
結果大致如下:
| account_id | owner_name | num_incoming_transfers |
|---|---|---|
16 |
Lee |
3 |
您也可以將線性查詢陳述式與集合運算子結合。
函式和運算式
您可以在圖形查詢中使用所有 GoogleSQL 函式 (包括匯總和純量函式)、運算子和條件運算式。BigQuery Graph 也支援只能用於圖表查詢的 GQL 函式和 GQL 運算子。
下列查詢在圖表查詢中混合使用 GQL 和 SQL 函式及運算子:
GRAPH graph_db.FinGraph
MATCH (person:Person)-[o:Owns]->(account:Account)
WHERE person IS SOURCE OF o
RETURN person, ARRAY_AGG(account.nick_name) AS accounts
GROUP BY person
NEXT
RETURN
LABELS(person) AS labels,
accounts,
CONCAT(person.city, ", ", person.country) AS location,
TO_JSON(person) AS person
LIMIT 1;
結果大致如下:
| 標籤 | 帳戶 | 位置 | 使用者圖示 |
|---|---|---|---|
Person |
["Vacation Fund"] |
Adelaide, Australia |
{"identifier":"mUZpbkdyYXBoLlBlcnNvbgB4kQI=","kind":"node","labels":["Person"],"properties":{"birthday":"1991-12-21T08:00:00Z","city":"Adelaide","country":"Australia","id":1,"name":"Alex"}} |
子查詢
「子查詢」是巢狀結構在其他查詢中的查詢。圖表查詢中的子查詢適用下列規則:
- 子查詢會包含在一組大括號
{}內。 - 子查詢會以
GRAPH子句開頭,指定範圍內的圖。指定的圖表不一定要與外部查詢中使用的圖表相同。 - 在子查詢範圍外宣告的圖表模式變數,無法在子查詢內再次宣告,但可以在子查詢內的運算式或函式中參照。
使用子查詢找出每個帳戶的轉帳總數
以下查詢說明如何使用 VALUE 子查詢。子查詢會以大括號 {} 括住,並加上 VALUE 關鍵字。查詢會傳回從帳戶發起的轉帳總數。
GRAPH graph_db.FinGraph
MATCH (p:Person)-[:Owns]->(account:Account)
RETURN p.name, account.id AS account_id, VALUE {
GRAPH graph_db.FinGraph
MATCH (a:Account)-[transfer:Transfers]->(:Account)
WHERE a = account
RETURN COUNT(transfer) AS num_transfers
} AS num_transfers;
結果大致如下:
| 名稱 | account_id | num_transfers |
|---|---|---|
Alex |
7 |
2 |
Dana |
20 |
2 |
Lee |
16 |
1 |
如需支援的子查詢運算式清單,請參閱「BigQuery Graph 子查詢」。
查詢參數
您可以使用參數查詢 BigQuery Graph。詳情請參閱語法,並瞭解如何執行參數化查詢。
下列查詢會比對 id 值與查詢參數相符的 Person 節點:
GRAPH graph_db.FinGraph
MATCH (person:Person {id: @id})
RETURN person.name;
同時查詢圖表和資料表
您可以使用 GRAPH_TABLE 運算子,結合圖形查詢和 SQL 查詢。
GRAPH_TABLE 運算子會採用線性圖表查詢,並以表格形式傳回結果,可整合至 SQL 查詢。這項互通性可讓您使用非圖表內容豐富圖表查詢結果,反之亦然。
舉例來說,您可以建立 CreditReports 資料表,並插入幾份信用報告,如以下範例所示:
CREATE TABLE graph_db.CreditReports (
person_id INT64 NOT NULL,
create_time TIMESTAMP NOT NULL,
score INT64 NOT NULL,
PRIMARY KEY (person_id, create_time) NOT ENFORCED
);
INSERT INTO graph_db.CreditReports (person_id, create_time, score)
VALUES
(1,"2020-01-10 06:22:20.222", 700),
(2,"2020-02-10 06:22:20.222", 800),
(3,"2020-03-10 06:22:20.222", 750);
接著,您可以透過 GRAPH_TABLE 中的圖表模式比對,找出特定人員,並將圖表查詢結果與 CreditReports 資料表彙整,擷取信用評分。
SELECT
gt.person.id,
credit.score AS latest_credit_score
FROM GRAPH_TABLE(
graph_db.FinGraph
MATCH (person:Person)-[:Owns]->(:Account)-[:Transfers]->(account:Account {is_blocked:true})
RETURN DISTINCT person
) AS gt
JOIN graph_db.CreditReports AS credit
ON gt.person.id = credit.person_id
ORDER BY credit.create_time;
結果大致如下:
| person_id | latest_credit_score |
|---|---|
1 |
700 |
2 |
800 |