图表查询概览
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 节点之间经过被屏蔽的中间账号且包含 1 到 2 条 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 节点相距 1 个或 2 个 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 节点之间最短的一条路径。该查询会考虑包含 1 到 3 条 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 属性之和。该搜索会考虑包含 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;
下表展示了此过程,其中显示了在每个语句之间传递的中间结果。为简洁起见,仅显示部分属性。
| Statement | 中间结果(缩写) | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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;
结果类似于以下内容:
| 标签 | 账号 | 地理位置 | 人 |
|---|---|---|---|
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 图架构是有向的,这意味着每条边都有一个源节点和一个目标节点。虽然图查询语法允许在任何方向上进行路径遍历(例如 -[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;