그래프 쿼리 개요
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 |
경로 패턴
경로 패턴은 대체 노드 및 에지 패턴으로부터 빌드됩니다.
경로 패턴을 사용하여 특정 노드에서 모든 경로 찾기
다음 쿼리는 id가 2와 동일한 Person이 소유하는 계정에서 시작된 모든 송금을 찾습니다.
일치하는 각 결과는 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 |
정량화된 경로 패턴
정량화된 패턴은 지정된 범위 내에서 패턴을 반복합니다.
정량화된 에지 패턴 찾기
가변 길이의 경로를 찾으려면 에지 패턴에 수량자를 적용하면 됩니다. 다음 쿼리는 id 값이 7인 소스 Account에서 1~3번 송금이 수행된 대상 계정을 찾아 이를 보여줍니다.
쿼리는 수량자 {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 |
결과의 일부 행이 반복됩니다. 이는 동일한 소스 노드와 대상 노드 사이에 패턴이 일치하는 여러 경로가 존재할 수 있으며, 쿼리에서 이러한 경로를 모두 반환하기 때문입니다.
정량화된 경로 패턴 일치
다음 쿼리는 차단된 중간 계정을 통해 1~2개의 Transfers 에지가 있는 Account 노드 사이의 경로를 찾습니다.
괄호로 묶인 경로 패턴이 정량화되고 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 노드에 도달하는 2개의 다른 경로가 있지만 쿼리에서는 하나의 경로만 반환합니다.
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 에지가 1~3개인 경로를 고려합니다.
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 속성 합계를 기반으로 합니다. 검색에서는 1~3개의 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 문
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;
결과는 다음과 비슷합니다.
| labels | 계정 | 위치 | 사람 |
|---|---|---|---|
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;
결과는 다음과 비슷합니다.
| name | 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 |
권장사항
스캔되는 데이터 양과 중간 결과 수를 최소화하도록 GQL 쿼리를 구조화하여 쿼리 성능을 최적화할 수 있습니다.
낮은 카디널리티 노드에서 경로 순회 시작
중간 결과 집합을 작게 유지하고 쿼리 실행 속도를 높이려면 경로 순회 방향에 관계없이 경로 순회가 낮은 카디널리티 노드에서 시작하도록 그래프 쿼리를 작성합니다. 다음 MATCH 문은 속성 필터를 사용하여 모든 일치 항목을 계산한 후 필터링하는 대신 가능한 시작 노드 수를 줄입니다.
MATCH (p:Person {id: 10})-[own:Owns]->(a:Account)
이는 특히 수량화된 경로 쿼리에 중요합니다.
MATCH (p:Person {id: 10})-[own:Owns]->{1,3}(a:Account)
방향 경로 순회 사용
BigQuery Graph 스키마는 방향성이 있습니다. 즉, 각 에지에는 소스 노드와 대상 노드가 있습니다. 그래프 쿼리 문법은 모든 방향(예: -[edge]-)으로 경로 순회를 허용하지만 성능을 향상시키려면 방향성 경로 순회(예: -[edge]-> 또는 <-[edge]-)를 사용하는 것이 좋습니다. 방향 경로 순회는 성능 저하를 일으킬 수 있습니다.
다음 MATCH 문은 두 개의 방향성 순회를 UNION ALL와 결합합니다.
MATCH (a1:Account {id: 7})-[t:Transfers]->(a2:Account)
...
UNION ALL
...
MATCH (a1:Account {id: 7})<-[t:Transfers]-(a2:Account)
연결 확인에 ANY 또는 ANY SHORTEST 문법 사용
수량화된 경로 쿼리는 소스 노드와 대상 노드 간에 중복 경로를 반환할 수 있습니다. 연결을 확인하는 것이 목표이고 가능한 모든 경로가 필요하지 않은 경우 ANY 또는 ANY SHORTEST를 사용하여 중복 계산을 줄이고 경로 조회 효율성을 개선합니다. 예를 들어 다음 MATCH 문은 ANY SHORTEST를 사용하여 각 노드 쌍 사이에 하나의 경로만 유지합니다.
MATCH ANY SHORTEST (a1:Account)-[t:Transfers]->{1,3}(a2:Account)
명시적으로 라벨 지정
쿼리에서 노드 또는 에지 라벨이 생략된 경우 BigQuery Graph는 적격한 모든 노드 및 에지 라벨을 열거합니다. 이 열거로 인해 필요한 것보다 많은 라벨이 스캔될 수 있습니다. 이를 방지하려면 가능하면 쿼리의 모든 노드와 에지에 라벨을 지정하세요.
예를 들어 다음 쿼리는 Account 및 Transfers 라벨을 지정합니다.
GRAPH graph_db.FinGraph
MATCH (a1:Account)-[t:Transfers]->(a2:Account)
RETURN COUNT(*) AS num_transfers;
라벨을 생략하면 노드 간의 불필요한 관계를 스캔할 수 있으므로 라벨을 생략하지 마세요. 다음 쿼리에서 a1은 계정 또는 사람을 나타낼 수 있고 t은 송금 또는 계정 소유권을 나타낼 수 있습니다.
GRAPH graph_db.FinGraph
MATCH (a1)-[t]->(a2)
RETURN COUNT(*) AS num_transfers;
단일 MATCH 문 사용
BigQuery Graph를 사용하면 단일 그래프 쿼리에 여러 MATCH 문을 포함할 수 있습니다. 이러한 문은 동일한 노드 또는 에지를 나타내는 여러 선언된 변수로 연결됩니다. 하지만 여러 MATCH 문을 사용하면 문 전체에서 카디널리티 이점이 줄어들 수 있습니다. 성능을 개선하려면 단일 MATCH 문을 사용하세요.
예를 들어 다음 쿼리는 동일하지만 첫 번째 쿼리는 단일 MATCH 문을 사용하므로 성능이 더 좋습니다.
-- Preferred syntax.
GRAPH graph_db.FinGraph
MATCH
(p:Person {id: 1})-[o:Owns]->
(a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;
-- Avoid this syntax.
GRAPH graph_db.FinGraph
MATCH (p:Person {id: 1})-[o:Owns]->(a:Account)
MATCH (a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;
카디널리티가 높은 노드에서 순회된 에지 제한
그래프를 쿼리할 때 일부 노드에는 다른 노드에 비해 들어오거나 나가는 에지 수가 훨씬 많을 수 있습니다. 이러한 카디널리티가 높은 노드를 슈퍼 노드 또는 허브 노드라고도 합니다. 슈퍼 노드를 통과하는 순회가 많은 양의 데이터 처리와 관련될 수 있으므로 슈퍼 노드로 인해 성능 문제가 발생할 수 있으며 이로 인해 데이터 왜도가 발생하고 실행 시간이 길어질 수 있습니다.
슈퍼 노드가 있는 그래프의 쿼리를 최적화하려면 MATCH의 FILTER 절 또는 WHERE 절 내에서 ROW_NUMBER() 함수를 사용하여 쿼리가 노드에서 또는 노드로 순회하는 에지 수를 제한합니다. 이 기법은 슈퍼 노드에서 또는 슈퍼 노드로의 모든 연결을 완전하게 열거할 필요가 없는 경우에 특히 유용합니다.
예를 들어 FinGraph의 일부 계정에 트랜잭션이 많은 경우 ROW_NUMBER()를 사용하여 각 Account에 대해 고려할 Transfers 에지 수를 제한하고 비효율적인 쿼리를 방지할 수 있습니다.
GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers WHERE e1 IN {
GRAPH graph_db.FinGraph
-- Sample 5 edges per source node
MATCH -[selected_e:Transfers]->
FILTER ROW_NUMBER() OVER (
PARTITION BY SOURCE_NODE_ID(selected_e)) < 5
RETURN selected_e
}]->{1,3}(a2:Account)
RETURN COUNT(*) AS cnt;
멀티홉 쿼리의 중간 노드 또는 에지 샘플링
ROW_NUMBER()를 사용하여 멀티 홉 쿼리에서 중간 노드를 샘플링해 쿼리 효율성을 향상시킬 수 있습니다. 이 기법은 쿼리에서 각 중간 노드에 고려하는 경로 수를 제한합니다. 이렇게 하려면 멀티 홉 쿼리를 NEXT로 구분된 MATCH 문 여러 개로 나누고 샘플링해야 하는 중간 지점에 ROW_NUMBER()를 적용합니다.
GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers]->(a2:Account)
-- Sample 5 destination nodes per a1 source node
FILTER ROW_NUMBER() OVER (PARTITION BY ELEMENT_ID(a1)) < 5
RETURN a1, a2
NEXT
MATCH (a2)-[e2:Transfers]->(a3:Account)
RETURN a1.id AS src_id, a2.id AS mid_id, a3.id AS dst_id;
다음 단계
- 그래프를 만들고 쿼리하는 방법 알아보기
- 그래프 스키마를 설계하는 방법 자세히 알아보기
- 쿼리 결과를 시각화하는 방법 알아보기