圖表查詢總覽
本文將簡要介紹圖形查詢語言 (GQL),以及如何為 BigQuery Graph 編寫圖形查詢。您可以執行圖形查詢,找出模式、周遊關係,並從房源圖形取得洞察資訊。本文中的範例是指名為 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。
每個相符結果都代表從 Person 節點開始的路徑,當 id 等於 2 時,會透過使用 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 節點的兩個不同路徑,抵達 Account 節點,但查詢只會傳回一個路徑。{id: 16}
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 路徑搜尋前置碼會為每對來源和目的地節點傳回單一路徑,並從邊緣數量最少的路徑中選取。
舉例來說,下列查詢會找出 Account 值為 7 的 Account 節點,以及 id 值為 20 的 Account 節點之間,其中一條最短路徑。id查詢會考量有一到三個 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 節點之間總運算成本最低的路徑。這項費用是根據邊緣的 amount 屬性總和計算而得。Transfers搜尋會考量有一到三個 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 圖表。詳情請參閱語法,並瞭解如何執行參數化查詢。
下列查詢會比對 Person 節點,這些節點的 id 值符合查詢參數:
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 |