本文档介绍了如何在 Spanner Graph 上运行算法。
Spanner Graph 算法查询结构
Spanner Graph 算法查询的结构如下:
EXPORT DATA OPTIONS (<export_option_list>) AS
GRAPH graph_name
<match_clause>
<call_statement> algorithm_name(<common_input>, <algorithm_specific_input>)
YIELD <algorithm_specific_output>
RETURN <results>
<export_option_list>:用于定义如何保留算法查询结果的选项。请参阅 Cloud Storage 选项和 Spanner 选项。graph_name:图表的名称。<match_clause>:用于定义算法输入元素的可选 MATCH 语句。<call_statement>:如果您省略了<match_clause>并希望对整个图表执行操作,请使用CALL。如果存在<match_clause>并且您希望对 工作表 执行操作,请使用CALL PER()。如需了解详情,请参阅 GQL CALL。algorithm_name:要运行的算法的名称。如需查看可用算法,请参阅 Spanner Graph 算法。<common_input>:所有算法查询共用的命名输入参数。如需了解详情,请参阅常用算法输入参数。<algorithm_specific_input>:算法的命名输入参数。如需了解详情,请参阅 Spanner Graph 算法中定义的输入参数。<algorithm_specific_output>:算法调用的输出。如需了解详情,请参阅 Spanner Graph 算法 中定义的输出和YIELD在 CALL 语句中。<results>:用于定义在查询结果中返回的内容。
该查询由 EXPORT DATA 语句(用于定义如何保留结果)和生成算法查询结果的 GRAPH CLAUSE 组成。
最简单的形式是,图子句用于标识图,CALL 会调用生成预定义输出的算法,然后指定要从算法的输出中 RETURN 的内容。
(可选)图表子句可以使用受支持的 MATCH 语句来选择感兴趣的元素。在这种情况下,请使用 PER () 子句将 MATCH 返回的所有行分组为算法的输入。该算法对由所选的唯一节点和边集组成的逻辑子图执行操作。
该查询不会返回任何数据。结果会根据 export_option_list 保留。
如需详细了解 Spanner Graph 算法查询,请参阅本文档中的以下部分:
常用算法输入参数
请按以下格式指定这些命名输入参数:NAME => VALUE, ...。
| 名称 | 值类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
node_labels |
ARRAY |
否 | (无) | 仅在使用 CALL 时受支持。要包含在
算法输入中的节点标签列表。如果指定了此参数,则仅包含至少有一个匹配
标签的节点。
|
edge_labels |
ARRAY |
否 | (无) | 仅在使用 CALL 时受支持。要包含在
算法输入中的边标签列表。如果指定了此参数,则仅包含至少有一个匹配
标签的边。
|
edge_weight_property |
STRING |
否 | (无) | 包含权重的边属性的名称。 如果未定义,系统会为所有边分配默认权重 1。 属性值类型必须为数字。 |
machine_category |
STRING |
否 | 默认 | 用于执行算法的机器类别。支持的值包括:default、large |
zone |
STRING |
否 | (无) | 执行算法的可用区。必须是接收查询的区域中的可用区之一。 |
max_idle_time |
STRING |
否 | 30 分钟 | 指定在算法完成后,计算实例应保持活跃状态多长时间以供
重复使用。格式是一系列十进制
数字,每个数字都包含一个单位后缀,例如 4m、1.5h
或 1h45m。有效时间单位为 ns、
us(或 µs)、ms、s、
m、h。 |
处理算法输出
您必须先保留算法查询结果,然后才能检查这些结果。使用 export_data_option 描述如何保留结果。您可以将结果保留到 Cloud Storage,也可以保留回查询来源的同一 Spanner 实例。
将结果保留到 Cloud Storage
如需使用此选项,请确保向 Google 管理的
Spanner 服务账号
service-PROJECT_NUMBER@gcp-sa-spanner.iam.gserviceaccount.com授予Storage Object Admin (roles/storage.objectAdmin)
角色。
将结果保留到 Cloud Storage 时,系统支持以下 EXPORT DATA 选项。请按以下格式指定选项:NAME=VALUE, ...。
| 名称 | 值类型 | 必需 | 说明 |
|---|---|---|---|
uri |
STRING |
是 | 导出的目标 URI,格式为 gs://bucket/path/file。如果要导出大量数据,请在 uri 中使用通配符将数据导出到多个文件。例如,gs://bucket/path/file_*.csv。 |
format |
STRING |
是 | 导出数据的格式。支持的值包括:CSV、PARQUET、AVRO。 |
header |
BOOL |
否 | 如果为 true,系统会为每个数据文件的第一行打印列标题。默认值为 false。仅适用于 CSV。 |
overwrite |
BOOL |
否 | 如果为 true,系统会覆盖具有相同 URI 的任何现有文件。否则,如果存在具有相同 URI 的文件,该语句会返回错误。默认值为 false。 |
field_delimiter |
STRING |
否 | 用于分隔字段的定界符。默认值:,(英文逗号)。仅适用于 CSV。 |
compression |
STRING |
否 | 指定压缩格式。如果您未指定压缩格式,文件将保持未压缩状态。
|
RETURN 子句中的列名称用于定义 Cloud Storage 输出文件中的列名称。
将数据导出到一个或多个文件
Spanner Graph 查询支持在 uri 中使用单个通配符运算符 (*)。通配符可以出现在文件名组成部分中,但不能出现在存储桶名称、文件夹名称或文件扩展名中。如果结果集较大,使用通配符运算符可指示 Spanner Graph 根据您提供的模式创建多个分片文件。系统会将通配符运算符替换为数字(从零开始),并向左填充 12 位。例如,URI gs://my-bucket/file-*.csv 会创建类似 gs://my-bucket/file-000000000000.csv、gs://my-bucket/file-000000000001.csv 的文件。
如果您使用不带通配符的 uri,则结果为单个文件,例如 gs://my-bucket/file.csv。
数据类型
导出数据时,Spanner 图表数据类型会根据格式进行如下转换:
CSV
所有数据类型都会转换为其字符串表示形式:
BOOL值会转换为true或false。BYTES值会采用 base64 编码。TIMESTAMP值会格式化为YYYY-MM-DD HH:MM:SS.ffffff UTC。NULL值会显示为空字符串。
您不能使用 CSV 格式导出嵌套数据和重复数据。
Avro
| Spanner 数据类型 | Avro 数据类型 |
|---|---|
BOOL |
BOOLEAN |
INT64 |
LONG |
FLOAT |
FLOAT |
DOUBLE |
DOUBLE |
NUMERIC |
BYTES(具有逻辑类型 DECIMAL(38,9)) |
STRING |
STRING |
BYTES |
BYTES |
TIMESTAMP |
LONG(自纪元以来的微秒数) |
NULL |
null |
Parquet
| Spanner 数据类型 | Parquet 数据类型 |
|---|---|
BOOL |
BOOLEAN |
INT64 |
INT64 |
FLOAT |
FLOAT |
DOUBLE |
DOUBLE |
NUMERIC |
DECIMAL(38,9) |
STRING |
STRING |
BYTES |
BYTE_ARRAY |
TIMESTAMP |
TIMESTAMP_MICROS |
NULL |
null |
将结果保留到 Spanner
将结果保留回源 Spanner 实例时,系统支持以下 EXPORT DATA 选项。请按以下格式指定选项:NAME=VALUE, ...。
| 名称 | 值类型 | 必需 | 说明 |
|---|---|---|---|
format |
STRING |
是 | 导出数据的格式。必须为 CLOUD_SPANNER。 |
table |
STRING |
是 | 用于写入结果的目标 Spanner 表的名称。 这可以是 Spanner 实例中的任何表。 |
write_mode |
STRING |
是 | 要使用的写入模式。支持的值包括:
在这两种模式下,Spanner 都会跳过任何会引入限制条件违规的记录(例如,更新时缺少键、唯一索引违规、外键限制条件违规)。但是,对于非限制条件违规错误(例如,列类型不匹配、NOT NULL 列缺少值),写入会失败。 |
要求
将算法结果保留回 Spanner 时,算法查询必须满足以下条件:
- 目标表必须存在 。
- 必须存在具有匹配类型的列:
RETURN子句中指定的所有列名称都必须已存在于目标表中,并且具有匹配的 数据类型。如果需要,请使用别名来匹配目标表列名称。示例:RETURN node.id AS person_id。 - 包含所有主键列:
RETURN子句必须包含目标表的所有 主键列。
写入语义
将结果保留回 Spanner 是一种非事务性操作。它提供行级原子性。这意味着,系统要么成功写入同一行的所有列,要么不写入任何列。它遵循“至少一次”语义。这意味着,一行可以写入多次。在执行过程中从目标表中读取数据可能会产生不完整的结果。
如果整体执行失败,系统不会回滚已提交的更改。写入过程会在第一个不可重试的错误上失败。发生写入失败时,ERROR_MESSAGE 在
GRAPH_OPERATION_EXECUTION_STATUS
中会指示失败行的主键以及失败的具体
原因。
系统会使用
MEDIUM 优先级将算法结果写回 Spanner Graph。
运行示例算法查询
本部分展示了您可以在测试实例上运行的 Spanner Graph 算法查询示例。如需查看 Spanner Graph 支持的算法的完整列表,请参阅 Spanner Graph 算法。
准备工作
如需运行示例 Spanner Graph 算法查询,您必须先完成以下操作:
- 按照设置和查询 Spanner Graph 中的步骤创建 Spanner Graph。
- 确保您拥有所需的权限。
- (可选)如果您要将输出保留到 Spanner,请扩充 Spanner Graph 架构。
向 Account 表添加名为 page_rank 的新列。Spanner 会将算法结果写入此新列。然后,刷新图表定义,以便您可以将 page_rank 作为节点属性进行访问。
-- Add `page_rank` as a column. Data type of this column matches the data type defined in `PageRank` output signature.
ALTER TABLE Account ADD COLUMN page_rank FLOAT64;
-- Rerun the graph definition DDL to pickup `page_rank` as a new property.
CREATE OR REPLACE PROPERTY GRAPH FinGraph
NODE TABLES (`Account`, `Person`)
EDGE TABLES (
`PersonOwnAccount`
SOURCE KEY (id) REFERENCES `Person` (id)
DESTINATION KEY (account_id) REFERENCES `Account` (id)
LABEL `Owns`,
`AccountTransferAccount`
SOURCE KEY (id) REFERENCES `Account` (id)
DESTINATION KEY (to_id) REFERENCES `Account` (id)
LABEL `Transfers`
);
对完整图表运行算法并使用标签过滤条件,然后将结果保留到 Cloud Storage
此示例运行 PageRank,根据 Account 参与的 Transactions 对其进行排名,并将结果以 CSV 格式保留到 Cloud Storage,文件名为“my-bucket-name/my-output.csv”
EXPORT DATA OPTIONS (
uri = "gs://my-bucket-name/my-output.csv",
format = "csv"
) AS
GRAPH FinGraph
CALL PageRank(node_labels => ['Account'], edge_labels => ['Transfers']) YIELD node, score
RETURN node.id, score AS page_rank
在 Cloud Storage 中,当此查询成功完成后,您应该会看到一个包含两列(id 和 page_rank)的 CSV 文件。
对由 MATCH 定义的子图运行算法,并将结果保留到图表
此示例使用 MATCH 模式动态匹配包含所有 Account 节点且仅包含金额小于 500 的 Transfer 边的逻辑子图。此逻辑子图是 PageRank 算法的输入。
Spanner 会将算法结果保留回 Account 表。
EXPORT DATA OPTIONS (
format = "CLOUD_SPANNER",
table = "Account",
write_mode = 'update_ignore_all'
) AS
GRAPH FinGraph
MATCH (n:Account)
RETURN n
FULL UNION ALL
MATCH -[e:Transfers WHERE e.amount < 500]->
RETURN e
NEXT
CALL PER () PageRank() YIELD node, score
RETURN node.id, score AS page_rank
查询成功完成后,运行以下查询:
GRAPH FinGraph
MATCH (n:Account)
RETURN n.id, ROUND(n.page_rank, 2) AS page_rank
ORDER BY page_rank DESC, id ASC
您应该会看到如下所示的结果:
| id | page_rank |
|---|---|
| 20 | 0.49 |
| 16 | 0.46 |
| 7 | 0.05 |
检查算法执行状态
图表算法查询成功完成后,会返回零行和 Success 状态。根据输入图表的大小和具体的算法配置,算法执行可能需要一段时间才能完成。您可以在 SPANNER_SYS.GRAPH_OPERATION_EXECUTION_STATUS 表中检查图表算法查询的进度和执行状态。此表会保留 30 天的信息。
GRAPH_OPERATION_EXECUTION_STATUS 架构
| 列名 | 类型 | 说明 |
|---|---|---|
QUERY_ID |
STRING |
图表算法查询的 ID。 |
QUERY_TEXT |
STRING |
查询语句文本。 |
START_TIMESTAMP |
TIMESTAMP |
查询开始执行的时间。 |
LAST_UPDATE_TIMESTAMP |
TIMESTAMP |
状态上次更新的时间。 |
PROGRESS |
FLOAT |
估计完成百分比。该值介于 0 和 1 之间,其中 0 表示已开始,1 表示已完成。 |
STATUS |
STRING |
当前执行状态。可能的值包括 PENDING、IN_PROGRESS、OK、CANCELLED、DEADLINE_EXCEEDED、UNKNOWN。 |
ERROR_MESSAGE |
STRING |
查询执行失败时的错误消息。 |
以下示例查询列出了尚未成功完成的图表查询:
SELECT
query_id,
query_text,
start_timestamp,
last_update_timestamp,
progress,
status,
error_message
FROM
SPANNER_SYS.GRAPH_OPERATION_EXECUTION_STATUS
WHERE
status != "OK"
ORDER BY
start_timestamp DESC;
取消算法执行
如需取消正在运行的图表算法查询,请从
SPANNER_SYS.GRAPH_OPERATION_EXECUTION_STATUS表中找到query_id,然后针对该query_id调用
cancel_query
。