本文档介绍了如何在 Spanner Graph 中查询属性图。通过 本部分中的示例将使用您在 设置和查询 Spanner Graph, 如下图所示:
运行 Spanner Graph 查询
您可以通过以下方式运行 Spanner 图查询:
Google Cloud 控制台
在 Spanner Studio 页面上提交查询。 如需访问 Spanner Studio 页面,请在数据库概览页面或表概览页面中点击 Spanner Studio。如需详细了解如何访问 Spanner Studio,请参阅使用 Google Cloud 控制台管理数据。
gcloud spanner
命令行工具使用
gcloud spanner databases execute-sql
命令提交命令。通过
executeSql
和executeStreamingSql
REST API通过
ExecuteSql
和ExecuteStreamingSql
RPC API
Spanner 图查询结构
本部分详细介绍了每个查询组成部分。
以下示例展示了 Spanner 图的基本结构 查询。
借助 Spanner Graph,您可以在数据库中创建多个图表。
该查询首先使用 GRAPH
子句指定目标图 FinGraph
。
图表模式匹配
图表模式匹配可在图表中查找特定模式。最基本的模式是元素模式(节点模式和边模式),用于匹配图元素(分别是节点和边)。元素模式可以组合成路径模式和更复杂的模式。
节点模式
节点模式是与图中的节点匹配的模式。此模式 包含一对匹配的圆括号, 包含图表模式变量、标签表达式和属性过滤条件。
查找所有节点
以下查询会返回图中的所有节点。变量 n
(称为图模式变量)会绑定到匹配的节点。在此例中,节点
模式匹配图中的所有节点。
GRAPH FinGraph
MATCH (n)
RETURN LABELS(n) AS label, n.id;
结果
该查询会返回 label
和 id
,如下所示:
标签 | id |
---|---|
账号 | 7 |
账号 | 16 |
账号 | 20 |
人物 | 1 |
人物 | 2 |
人物 | 3 |
查找具有特定标签的所有节点
以下查询会匹配图中具有 Person
label 的所有节点。查询返回匹配节点的 label
和 id
以及 name
属性。
GRAPH FinGraph
MATCH (p:Person)
RETURN LABELS(p) AS label, p.id, p.name;
结果
标签 | id | name |
---|---|---|
人物 | 1 | Alex |
人物 | 2 | Dana |
人物 | 3 | Lee |
查找与标签表达式匹配的所有节点
您可以使用一个或多个逻辑运算符创建标签表达式。
以下查询将匹配图表中具有
Person
或 Account
标签。属性的集合
图表模式变量 n
是由
具有 Person
或 Account
标签的节点。
GRAPH 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
属性。
结果
标签 | id | 生日 | create_time |
---|---|---|---|
账号 | 7 | NULL | 2020-01-10T14:22:20.222Z |
账号 | 16 | NULL | 2020-01-28T01:55:09.206Z |
账号 | 20 | NULL | 2020-02-18T13:44:20.655Z |
人物 | 1 | 1991-12-21T08:00:00Z | NULL |
人物 | 2 | 1980-10-31T08:00:00Z | NULL |
人物 | 3 | 1986-12-07T08:00:00Z | NULL |
如需详细了解标签表达式规则,请参阅标签表达式。
查找与标签表达式和属性过滤条件匹配的所有节点
以下查询匹配图中具有 Person
标签的所有节点,
其中属性 id
等于 1
。
GRAPH FinGraph
MATCH (p:Person {id: 1})
RETURN LABELS(p) AS label, p.id, p.name, p.birthday;
结果
标签 | id | name | 生日 |
---|---|---|---|
人物 | 1 | Alex | 1991-12-21T08:00:00Z |
您可以使用 WHERE
子句针对标签和属性构建更复杂的过滤条件。
以下查询与图表中具有 Person
的所有节点匹配
标签,且属性 birthday
早于 1990-01-10
。
GRAPH FinGraph
MATCH (p:Person WHERE p.birthday < '1990-01-10')
RETURN LABELS(p) AS label, p.name, p.birthday;
结果
标签 | name | 生日 |
---|---|---|
人物 | Dana | 1980-10-31T08:00:00Z |
人物 | Lee | 1986-12-07T08:00:00Z |
边缘图案
边缘模式用于匹配节点之间的边缘或关系。边缘模式用方括号 []
括起来,并用符号 -
、->
或 <-
来指示方向。
与节点模式类似,图表模式变量用于绑定到匹配的边缘 元素。
查找具有匹配标签的所有边
以下查询会返回图中具有 Owns
标签的所有边。图模式变量 e
会绑定到匹配的边。
GRAPH FinGraph
MATCH -[e:Owns]->
RETURN e.id AS owner_id, e.account_id;
结果
owner_id | account_id |
---|---|
1 | 7 |
3 | 16 |
2 | 20 |
查找与标签表达式和属性过滤条件匹配的所有边
与节点模式类似,边缘模式可以使用
标签表达式、属性规范和 WHERE
子句,如
。查询会查找所有标有 Owns
且具有
属性create_time
。
GRAPH FinGraph
MATCH -[e:Owns WHERE e.create_time > '2020-01-14'
AND e.create_time < '2020-05-14']->
RETURN e.id AS owner_id, e.create_time, e.account_id;
结果
owner_id | create_time | account_id |
---|---|---|
2 | 2020-01-28T01:55:09.206Z | 20 |
3 | 2020-02-18T13:44:20.655Z | 16 |
使用任意方向边缘图案找到所有边
虽然 Spanner 图中的所有边都是有向的,但您可以在查询中使用 any direction
边模式 -[]-
来匹配任意方向的边。
以下查询会查找涉及已屏蔽账号的所有转账。
GRAPH FinGraph
MATCH (account:Account)-[transfer:Transfers]-(:Account)
WHERE account.is_blocked
RETURN transfer.order_number, transfer.amount;
结果
order_number | 金额 |
---|---|
304330008004315 | 300 |
304120005529714 | 100 |
103650009791820 | 300 |
302290001255747 | 200 |
路径模式
路径模式由交替的节点模式和边模式构建而成。
使用路径模式查找具有指定标签和属性过滤条件的节点的所有路径
以下查询可查找从某个账号发起到该账号的所有转账
所有者为 Person
,id
等于 2
。
每个匹配结果都表示从 Person
{id: 2}
通过连接的 Account
(使用 Owns
边)到另一个 Account
(使用 Transfers
边)的路径。
GRAPH 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}
后缀的边模式。
GRAPH 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 | 1 | 16 |
7 | 3 | 16 |
7 | 3 | 16 |
7 | 2 | 20 |
7 | 2 | 20 |
前面的示例使用 ARRAY_LENGTH
函数访问
group variable
e
。对于
如需了解详情,请参阅访问权限组变量。
示例结果中的某些行会重复,因为同一对 src
和 dst
账号之间可能存在多个匹配该模式的路径。
匹配量化路径模式
以下查询查找 Account
节点之间具有一到两个的路径
Transfers
边缘通过被屏蔽的中间账号。
括号中的路径模式会被量化,并且括号中会使用 WHERE
子句来指定重复模式的条件。
GRAPH FinGraph
MATCH
(src:Account)
((:Account)-[:Transfers]->(interm:Account) WHERE interm.is_blocked){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
(在量化模式内)中的单个边。 - 绑定到
ARRAY_LENGTH(e)
中边缘元素数组的组变量 在RETURN
语句中(量化模式之外)。 - 绑定到边缘元素数组的组变量,该数组由量化模式之外的
SUM(e.amount)
进行汇总。这是一个 横向聚合。
GRAPH 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 进行匹配
以下查询可查找符合查询条件(只有 1-2 个)的所有唯一账号
距离给定 Account
节点 Transfers
。
ANY
路径搜索前缀可确保仅返回一对唯一的 src
和 dst
Account
节点之间的一条路径。在以下示例中,虽然您可以通过从源 Account
节点出发的两条不同路径使用 {id: 16}
到达 Account
节点,但结果中仅包含一条路径。
GRAPH FinGraph
MATCH ANY (src:Account {id: 7})-[e:Transfers]->{1,2}(dst:Account)
LET ids_in_path = ARRAY(SELECT e.to_id FROM UNNEST(e) AS e)
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 | 16 |
7 | 20 | 16,20 |
图表模式
图模式由一个或多个路径模式组成,以英文逗号 ,
分隔。图模式可以包含 WHERE
子句,让您可以访问路径模式中的所有图模式变量,以形成过滤条件。每条路径
都会生成一组路径。
使用图表模式进行匹配
以下查询确定了所涉及的中转账号及其所有者 金额超过 200 的交易,用于转出资金 从源账号转移到已屏蔽的账号。
图表模式由以下路径模式构成:
- 第一个模式会查找从单个服务器进行的传输 关联到使用中间账号屏蔽的账号。
- 第二种模式用于查找账号与其所有者之间的路径。
变量 interm
充当两个路径模式之间的通用链接,这要求 interm
引用两个路径模式中相同的元素节点。这个
根据 interm
变量创建等联接操作。
GRAPH 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 FinGraph
MATCH (src_account:Account)-[transfer:Transfers]->(dst_account:Account)
WHERE dst_account.is_blocked
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) WHERE dst_account.is_blocked |
|
||||||||||||
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)。请参阅 RETURN
语句。
请注意,Spanner Graph 不支持以查询的形式返回图元素
结果。如需返回整个图表元素,请使用 TO_JSON
函数。
以 JSON 格式返回图元素
GRAPH 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
将多个线性图表查询语句连在一起
关键字。第一个线性查询语句的输入为空。每个线性查询语句的输出都会成为下一个线性查询语句的输入。
以下示例将查找收到最多来电的账号的所有者
将多个线性图语句链接在一起进行传输。请注意,您可以在多个线性语句中使用相同的变量(在此示例中为 account
)来引用同一图表元素。
GRAPH 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 中的所有函数、运算符和条件, 包括聚合函数 和其他标量函数。
Spanner Graph 还支持图元素的内置函数和运算符。
内置函数和运算符
PROPERTY_EXISTS(n, birthday)
:返回n
是否公开了birthday
属性。LABELS(n)
:返回图表架构中定义的n
的标签。PROPERTY_NAMES(n)
:返回n
的属性名称。TO_JSON(n)
:以 JSON 格式返回n
。有关详情,请参阅TO_JSON
函数。
以下查询展示了 PROPERTY_EXISTS
谓词、LABELS
函数和
TO_JSON
函数,以及 ARRAY_AGG
和
CONCAT
。
GRAPH FinGraph
MATCH (person:Person)-[:Owns]->(account:Account)
RETURN person, ARRAY_AGG(account.nick_name) AS accounts
GROUP BY person
NEXT
RETURN
LABELS(person) AS labels,
TO_JSON(person) AS person,
accounts,
CONCAT(person.city, ", ", person.country) AS location,
PROPERTY_EXISTS(person, is_blocked) AS is_blocked_property_exists,
PROPERTY_EXISTS(person, name) AS name_property_exists
LIMIT 1;
结果
is_blocked_property_exists | name_property_exists | 标签 | 账号 | 位置 | 个人 |
---|---|---|---|---|---|
false | true | 人物 | ["Vacation Fund"] | 澳大利亚阿德莱德 | {"identifier":"mUZpbkdyYXBoLlBlcnNvbgB4kQI=","kind":"node","labels":["Person"],"properties":{"birthday":"1991-12-21T08:00:00Z","city":"Adelaide","country":"Australia","id":1,"name":"Alex"}} |
子查询
子查询是嵌套在另一个查询中的查询。以下列出了 Spanner 图子查询规则:
- 子查询包含在一对大括号
{}
中。 - 子查询可能以前导
GRAPH
子句开头,以指定范围内的图。指定的图表不需要与图表相同 用于外部查询中。 - 在子查询中省略
GRAPH
子句时,会发生以下情况:- 范围内的图表是根据最接近的外部查询上下文推断出来的。
- 子查询必须从图表模式匹配语句开始
使用
MATCH.
- 在子查询范围之外声明的图表模式变量不能 但可以在子查询内 子查询中的表达式或函数。
使用子查询查找每个账号的转账总数
以下查询说明了如何使用 VALUE
子查询。子查询用前缀为 VALUE
关键字的花括号 {}
括起来。该查询会返回从某个账号发起的转账总金额。
GRAPH FinGraph
MATCH (p:Person)-[:Owns]->(account:Account)
RETURN p.name, account.id AS account_id, VALUE {
MATCH (a:Account)-[transfer:Transfers]->(:Account)
WHERE a = account
RETURN SUM(transfer.amount) AS total_transfer
} AS total_transfer;
结果
name | account_id | total_transfer |
---|---|---|
Alex | 7 | 400 |
Dana | 20 | 700 |
Lee | 16 | 300 |
如需查看支持的子查询表达式列表,请参阅 Spanner 图子查询。
查询参数
您可以使用参数查询 Spanner 图。如需了解详情,请参阅语法,并了解如何在 Spanner 客户端库中使用参数查询数据。
以下查询展示了查询参数的用法。
GRAPH FinGraph
MATCH (person:Person {id: @id})
RETURN person.name;
同时查询图表和表格
可以将图查询与 SQL 结合使用,从 将图表和表格放在一个语句中。
GRAPH_TABLE
GRAPH_TABLE
运算符接受线性图表查询,并以表格形式返回其结果,该结果可无缝集成到 SQL 查询中。这个
借助互操作性,您可以使用非图内容丰富图查询结果,
反过来。
例如,您可以创建一个CreditReports
表并插入一些功劳
如下例所示:
CREATE TABLE CreditReports (
person_id INT64 NOT NULL,
create_time TIMESTAMP NOT NULL,
score INT64 NOT NULL,
) PRIMARY KEY (person_id, create_time);
INSERT INTO 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(
FinGraph
MATCH (person:Person)-[:Owns]->(:Account)-[:Transfers]->(account:Account)
WHERE account.is_blocked
RETURN DISTINCT person
) AS gt
JOIN CreditReports AS credit
ON gt.person.id = credit.person_id
ORDER BY credit.create_time;
结果:
person_id | latest_credit_score |
---|---|
1 | 700 |
2 | 800 |
后续步骤
了解调整查询的最佳实践。