架构概览

本文档介绍了图表架构的组成部分,并介绍了如何创建和管理图表架构。

借助图表,您可以对关联数据进行建模,该图表将信息表示为由节点和边缘组成的网络。图表架构由节点和边组成,并包含用于对节点和边进行类型分类的标签,以及用于描述节点和边的属性。您可以通过将输入表中的行映射到图表节点和边缘,并定义自定义标签和属性,来定义图表架构。如需详细了解 BigQuery Graph,请参阅 BigQuery Graph 概览。

了解图表数据模型

借助图表,您可以将关联数据建模为由节点和边缘组成的网络。节点表示数据中的实体,例如客户、产品或地点。边表示这些节点之间的连接,描述购买、关注或位置等关系。

节点和边缘可以包含以下信息:

  • 标签:对节点和边缘类型进行分类。例如,班级中的学生可能具有 Student 标签和 Person 标签。如果您未明确为节点或边定义标签,BigQuery Graph 会使用输入表名称作为默认标签。

  • 属性:用于描述节点和边。例如,表示人员的节点可能具有值为 Alex 的 name 属性和值为 1 的 id 属性。

图 1 中的示例展示了如何设计图表来对金融活动进行建模。此图表包含以下类型的以节点形式建模的实体:

  • Person:表示参与金融交易的个人。
  • Account:表示用于交易的银行账户。

这些实体通过不同类型的关系(由以下有向边缘表示)相连:

  • Owns:某人拥有一个或多个账号。
  • Transfers:资金从一个账户转到另一个账户。

每个有向边缘都表示一个单向关系,从来源节点流向目标节点。例如,Transfers 边缘将来源 Account 连接到目标 Account,从而表示资金流动。

金融图表的节点、边、标签和属性。

图 1. 包含多个节点和有向边缘的示例图表。

节点和边缘可在属性中包含其他信息。

  • Person 节点包含以下属性:

    • name (STRING)
    • id (INT64)
  • Transfers 边缘包含以下属性:

    • amount (FLOAT64)

有向边缘和无向边缘

有向边缘表示实体之间关系的特定方向。例如,某人拥有一个账号,但账号不拥有某人。不过,某些关系(例如社交网络中的好友关系)是无向的,表示相互连接。在这种情况下,您可以将无向边缘建模为两个有向边缘,每个方向一个边缘。

设计架构

借助 BigQuery Graph,您可以使用 CREATE PROPERTY GRAPH 语句通过表创建图表。用于创建图表的表称为“输入表”。

定义节点

节点由以下类型的表或视图中的行定义:

  • 标准表
  • 外部表
  • Apache Iceberg 托管表
  • Lakehouse Iceberg REST 目录表
  • 视图,包括授权视图
  • 非增量物化视图

如需定义节点,请在 NODE TABLES 子句中添加节点定义。最简单的节点定义形式包含具有主键的输入表的名称。BigQuery Graph 会将输入表中的行映射到图表节点。

在以下示例中,您使用 NODE TABLES 子句在 FinGraph 图表中定义 Account 节点。节点定义包含输入表 Account。

-- Create an Account table.
CREATE TABLE graph_db.Account (
  id           INT64 NOT NULL,
  create_time  TIMESTAMP,
  PRIMARY KEY (id) NOT ENFORCED
);

-- Use the Account table as the input table for the Account node definition.
CREATE PROPERTY GRAPH graph_db.FinGraph
  NODE TABLES (
    graph_db.Account
  );

默认情况下,BigQuery 会使用表名称作为标签,并将输入表中的所有列作为属性公开。

  • 每个 Account 节点都使用 Account 标签。
  • 每个 Account 节点都包含来自 Account 表列的 id 和 create_time 属性。

元素键

节点定义还会定义元素键,即唯一标识图表节点的一组列。默认情况下,元素键是输入表的主键。 或者,您也可以使用 KEY 子句明确定义元素键。

以下示例定义了一个 Account 节点和一个 Person 节点。Account 节点会使用 Account 表的主键作为其元素键。Person 节点使用 KEY 子句明确将 id 列指定为元素键。

CREATE TABLE graph_db.Person (
  id           INT64 NOT NULL,
  name         STRING
);

CREATE TABLE graph_db.Account (
  id           INT64 NOT NULL,
  create_time  TIMESTAMP,
  PRIMARY KEY (id) NOT ENFORCED
);

CREATE PROPERTY GRAPH graph_db.FinGraph
  NODE TABLES (
    graph_db.Person KEY (id),
    graph_db.Account
  );
  • 具有非 null 元素键的每一行都会映射到图表中的唯一节点(该节点由元素键标识)。
  • 系统会忽略具有 null 元素键的行。

同一输入表可在多个节点定义中使用。在这种情况下,输入表中的给定行会映射到每个节点定义的一个节点。

定义边缘

边由以下类型的表或视图中的行定义:

  • 标准表
  • 外部表
  • Apache Iceberg 托管表
  • Lakehouse Iceberg REST 目录表
  • 视图,包括授权视图
  • 非增量物化视图

如需定义边缘,请将边缘定义添加到 EDGE TABLES 子句中。最简单的边缘定义形式包含输入表的名称,并定义源节点和目标节点引用。BigQuery Graph 会使用此定义将输入表中的行映射到图表边缘。

默认情况下,BigQuery 会使用表名称作为标签,并将输入表中的所有列作为属性公开。

来源节点和目标节点引用

边缘定义使用 SOURCE KEY、DESTINATION KEY 和 REFERENCES 子句定义来源节点和目标节点引用。 您必须先定义来源节点和目标节点,然后才能在边缘定义中使用它们。

在以下示例中,您将创建一个名为 FinGraph 的图表,其中包含以下元素:

  • Person 和 Account 节点
  • PersonOwnAccount 边缘
CREATE TABLE graph_db.Person (
  id            INT64 NOT NULL,
  name          STRING,
  PRIMARY KEY (id) NOT ENFORCED
);

CREATE TABLE graph_db.Account (
  id            INT64 NOT NULL,
  create_time   TIMESTAMP,
  PRIMARY KEY (id) NOT ENFORCED
);

CREATE TABLE graph_db.PersonOwnAccount (
  id            INT64 NOT NULL,
  account_id    INT64 NOT NULL,
  create_time   TIMESTAMP,
  FOREIGN KEY (account_id) REFERENCES graph_db.Account (id) NOT ENFORCED,
  PRIMARY KEY (id, account_id) NOT ENFORCED
);

CREATE PROPERTY GRAPH graph_db.FinGraph
  NODE TABLES (
    graph_db.Person,
    graph_db.Account
  )
  EDGE TABLES (
    PersonOwnAccount
      SOURCE KEY (id) REFERENCES Person (id)
      DESTINATION KEY (account_id) REFERENCES Account (id)
  );

每个 PersonOwnAccount 边缘都将一个 Person(来源)节点连接到一个 Account(目标)节点。

  • 边缘的来源节点是 Person 节点,其中 id 属性与边缘 id 属性相同。
  • 边缘的目标节点是 Account 节点,其中 id 属性与边缘 account_id 属性相同。
  • 元素键是 PersonOwnAccount 表的主键,即 (id, account_id)。
  • 每个边缘都具有与 PersonOwnAccount 表中的列相同的属性集。
  • 每个边缘都具有默认的 PersonOwnAccount 标签。

将行映射到边缘

边缘输入表中具有非 null 元素键的每一行通常都会映射到图表中的单个边缘。不过,如果来源或目标节点引用与来源或目标节点表中的零个或多个节点匹配,则边缘输入表中的行可能会导致图表中出现零个或多个边缘。

在单个表中定义节点和边

如果表的列定义了与另一个表的关系,您可以在单个表中定义节点及其传入或传出边缘。这种方法可以减少表的数量、简化数据管理,并且无需与单独的边缘表进行联接,从而提高查询性能。

例如,如果以下 Account 表具有复合主键 (owner_id, account_id),则 owner_id 列可以是引用 Person 表的外键。此结构允许 Account 表同时表示 Account 节点和来自 Person 节点的传入边缘。

CREATE TABLE graph_db.Person (
  id INT64 NOT NULL,
  PRIMARY KEY (id) NOT ENFORCED
);

-- Assume each account has exactly one owner.
CREATE TABLE graph_db.Account (
  owner_id INT64 NOT NULL,
  account_id INT64 NOT NULL,
  FOREIGN KEY (owner_id) REFERENCES graph_db.Person(id) NOT ENFORCED,
  PRIMARY KEY (owner_id, account_id) NOT ENFORCED
);

您可以使用 Account 表来定义 Account 节点及其传入 Owns 边缘。具体可见以下CREATE PROPERTY GRAPH语句。在 EDGE TABLES 子句中,您为 Account 表指定别名 Owns。这是因为图架构中的每个元素都必须具有唯一的名称。

CREATE PROPERTY GRAPH graph_db.FinGraph
  NODE TABLES (
    graph_db.Person,
    graph_db.Account
  )
  EDGE TABLES (
    graph_db.Account AS Owns
      SOURCE KEY (owner_id) REFERENCES Person
      DESTINATION KEY (owner_id, account_id) REFERENCES Account
  );

自定义标签和属性

您可以使用 LABEL 和 PROPERTIES 子句自定义标签和属性。

以下示例定义了一个具有自定义属性的 Person 节点和一个具有多个标签的 Account 节点:

CREATE TABLE graph_db.Person (
  id               INT64 NOT NULL,
  name             STRING,
  birthday         TIMESTAMP,
  country          STRING,
  city             STRING,
  PRIMARY KEY (id) NOT ENFORCED
);

CREATE TABLE graph_db.Account (
  id               INT64 NOT NULL,
  create_time      TIMESTAMP,
  is_blocked       BOOL,
  nick_name        STRING,
  PRIMARY KEY (id) NOT ENFORCED
);

CREATE PROPERTY GRAPH graph_db.FinGraph
  NODE TABLES (
    graph_db.Person KEY (id)
      LABEL Customer
      PROPERTIES (CONCAT(city, ", ", country) AS address)
      LABEL Entity PROPERTIES (id, name),
    graph_db.Account KEY (id)
      DEFAULT LABEL OPTIONS(description = 'A checking or savings account')
      PROPERTIES (id, create_time)
      LABEL Entity
      PROPERTIES (
        id,
        nick_name AS name OPTIONS(description = 'A user-defined account name',
                                  synonyms = ['friendly name', 'display name'],
                                  extensions = [('data_classification', 'user'), ('currency', 'USD')])
      )
  );
  • Person 节点使用 Customer 标签公开 address 属性。address 属性由表达式 CONCAT(city, ", ", country), 定义,该表达式引用输入表 Person 中的 city 和 country 列。

  • Account 节点使用 Account 标签公开 id 和 create_time 属性。

Person 和 Account 节点都具有 Entity 标签,其中包含属性 id 和 name。

  • 在 Person 节点中,id 和 name 属性来自输入表列。
  • 在 Account 节点中,name 属性引用输入表的 nick_name 列。
  • 在 Account 节点中,name 属性使用 OPTIONS 子句提供属性说明、同义词列表和元数据键值对列表。

指定选项

您可以在标签或属性定义(包括测量定义)的 OPTIONS() 子句中指定自定义的用户定义元数据。支持的选项如下:

  • description:标签或属性的人类可读字符串说明。
  • synonyms:一个字符串数组,表示标签或属性的同义词。
  • extensions:表示其他元数据的字符串对 (ARRAY<STRUCT<STRING, STRING>>) 数组。您可以使用扩展程序提供自定义元数据、单位或格式设置规则,例如 [('currency', 'USD')]。

这些选项可为自然语言查询界面提供上下文并提高可检测性。您无法在图表查询中直接访问这些字段,并且它们不会以任何方式更改 GQL 查询结果。

标签和属性一致性

在图表中,标签和属性通过其名称进行唯一标识。 您可以在多个节点或边缘定义中使用具有相同名称的标签和属性。不过,具有相同名称的标签和属性必须遵循以下规则:

  • 具有相同名称的属性必须使用相同的值类型。
  • 具有相同名称的标签必须公开相同的属性列表。

在前面的示例中,Person 和 Account 节点中都定义了 Entity 标签。这两个定义都包含具有相同值类型的相同属性名称集 id 和 name。

管理架构依赖项

图表依赖于节点和边缘定义的输入表的架构,以及属性引用的表列。BigQuery Graph 不会检查删除或更改表或列是否会使现有图架构失效。

您有责任避免破坏性架构更改。请遵循以下最佳实践:

  • 在删除图节点定义中使用的表之前,请先从图中移除该节点定义。
  • 在从作为图表中的属性公开的表中移除列之前,请先从相应的节点或边缘定义中移除该属性。

查看图表架构

如需查看用于构建现有图的 CREATE PROPERTY GRAPH 语句,请查询 INFORMATION_SCHEMA.PROPERTY_GRAPHS 视图:

SELECT
  property_graph_name,
  ddl
FROM
  `region-REGION`.INFORMATION_SCHEMA.PROPERTY_GRAPHS;

将 REGION 替换为包含图的数据集的区域。

或者,您也可以在笔记本中直观呈现图表架构。

更新图表架构

如需对现有图的架构进行任何更改,您必须使用 CREATE PROPERTY GRAPH 语句重新定义图架构。

删除图表架构

如需删除图,请使用 DROP PROPERTY GRAPH 语句。

最佳做法

以下部分介绍了定义图架构以提高图查询性能的最佳实践。

确定属性定义的范围

属性是键值对,用于提供附加到节点或边缘的其他信息。我们建议您仅在节点或边中包含必要的属性,并避免使用 PROPERTIES ALL COLUMNS 语法或默认语法,因为这些语法会将节点或边表中的所有列附加到属性列表中。节点或边缘中包含许多属性可能会导致图表查询中出现不必要的列扫描,从而降低性能。

如需限制节点或边缘定义中包含的属性,请在 CREATE PROPERTY GRAPH 语句中定义元素属性时使用 PROPERTIES 关键字。

以下节点表定义将 Person 节点表的属性限制为 id 和 name:

NODE TABLES (
  graph_db.Person PROPERTIES (id, name)
)

在图节点和边缘上定义主键和外键约束

BigQuery 可以使用节点表和边表上的主键和外键约束条件,通过减少不必要的表扫描来优化图查询。不过,BigQuery 不会强制执行表的主键或外键限制条件。如果您的应用无法保证主键的引用完整性或唯一性,那么使用主键或外键进行查询优化可能会导致查询结果不正确。

以下示例在节点表 Person 和 Account 以及边表 PersonOwnAccount 上定义了主键和外键约束:

CREATE OR REPLACE TABLE graph_db.Person (
  id               INT64,
  name             STRING,
  birthday         TIMESTAMP,
  country          STRING,
  city             STRING,
  PRIMARY KEY (id) NOT ENFORCED
);

CREATE OR REPLACE TABLE graph_db.Account (
  id               INT64,
  create_time      TIMESTAMP,
  is_blocked       BOOL,
  nick_name        STRING,
  PRIMARY KEY (id) NOT ENFORCED
);

CREATE OR REPLACE TABLE graph_db.PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
  PRIMARY KEY (id, account_id) NOT ENFORCED,
  FOREIGN KEY (id) references graph_db.Person(id) NOT ENFORCED,
  FOREIGN KEY (account_id) references graph_db.Account(id) NOT ENFORCED
);

后续步骤