运行 Spanner Graph 算法

本文档介绍了如何在 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 算法 中定义的输出和 YIELDCALL 语句中。

  • <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 默认 用于执行算法的机器类别。支持的值包括:defaultlarge
zone STRING (无) 执行算法的可用区。必须是接收查询的区域中的可用区之一。
max_idle_time STRING 30 分钟 指定在算法完成后,计算实例应保持活跃状态多长时间以供 重复使用。格式是一系列十进制 数字,每个数字都包含一个单位后缀,例如 4m1.5h1h45m。有效时间单位为 nsus(或 µs)、mssmh

处理算法输出

您必须先保留算法查询结果,然后才能检查这些结果。使用 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 导出数据的格式。支持的值包括:CSVPARQUETAVRO
header BOOL 如果为 true,系统会为每个数据文件的第一行打印列标题。默认值为 false。仅适用于 CSV。
overwrite BOOL 如果为 true,系统会覆盖具有相同 URI 的任何现有文件。否则,如果存在具有相同 URI 的文件,该语句会返回错误。默认值为 false
field_delimiter STRING 用于分隔字段的定界符。默认值:,(英文逗号)。仅适用于 CSV。
compression STRING 指定压缩格式。如果您未指定压缩格式,文件将保持未压缩状态。
  • 对于 CSV,支持的值为 GZIP
  • 对于 PARQUET,支持的值包括:SNAPPYGZIPZSTD
  • 对于 AVRO,支持的值包括:DEFLATESNAPPY

RETURN 子句中的列名称用于定义 Cloud Storage 输出文件中的列名称。

将数据导出到一个或多个文件

Spanner Graph 查询支持在 uri 中使用单个通配符运算符 (*)。通配符可以出现在文件名组成部分中,但不能出现在存储桶名称、文件夹名称或文件扩展名中。如果结果集较大,使用通配符运算符可指示 Spanner Graph 根据您提供的模式创建多个分片文件。系统会将通配符运算符替换为数字(从零开始),并向左填充 12 位。例如,URI gs://my-bucket/file-*.csv 会创建类似 gs://my-bucket/file-000000000000.csvgs://my-bucket/file-000000000001.csv 的文件。

如果您使用不带通配符的 uri,则结果为单个文件,例如 gs://my-bucket/file.csv

数据类型

导出数据时,Spanner 图表数据类型会根据格式进行如下转换:

CSV

所有数据类型都会转换为其字符串表示形式:

  • BOOL 值会转换为 truefalse
  • 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 要使用的写入模式。支持的值包括:
  • update_ignore_all:更新目标表中的现有行。
  • upsert_ignore_all:在目标表中插入新行或更新现有行。

在这两种模式下,Spanner 都会跳过任何会引入限制条件违规的记录(例如,更新时缺少键、唯一索引违规、外键限制条件违规)。但是,对于非限制条件违规错误(例如,列类型不匹配、NOT NULL 列缺少值),写入会失败。

要求

将算法结果保留回 Spanner 时,算法查询必须满足以下条件:

  • 目标表必须存在
  • 必须存在具有匹配类型的列RETURN子句中指定的所有列名称都必须已存在于目标表中,并且具有匹配的 数据类型。如果需要,请使用别名来匹配目标表列名称。示例:RETURN node.id AS person_id
  • 包含所有主键列RETURN子句必须包含目标表的所有 主键列。

写入语义

将结果保留回 Spanner 是一种非事务性操作。它提供行级原子性。这意味着,系统要么成功写入同一行的所有列,要么不写入任何列。它遵循“至少一次”语义。这意味着,一行可以写入多次。在执行过程中从目标表中读取数据可能会产生不完整的结果。

如果整体执行失败,系统不会回滚已提交的更改。写入过程会在第一个不可重试的错误上失败。发生写入失败时,ERROR_MESSAGEGRAPH_OPERATION_EXECUTION_STATUS 中会指示失败行的主键以及失败的具体 原因。

系统会使用 MEDIUM 优先级将算法结果写回 Spanner Graph。

运行示例算法查询

本部分展示了您可以在测试实例上运行的 Spanner Graph 算法查询示例。如需查看 Spanner Graph 支持的算法的完整列表,请参阅 Spanner Graph 算法

准备工作

如需运行示例 Spanner Graph 算法查询,您必须先完成以下操作:

  1. 按照设置和查询 Spanner Graph 中的步骤创建 Spanner Graph。
  2. 确保您拥有所需的权限
  3. (可选)如果您要将输出保留到 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 中,当此查询成功完成后,您应该会看到一个包含两列(idpage_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 估计完成百分比。该值介于 01 之间,其中 0 表示已开始,1 表示已完成。
STATUS STRING 当前执行状态。可能的值包括 PENDINGIN_PROGRESSOKCANCELLEDDEADLINE_EXCEEDEDUNKNOWN
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

后续步骤