排查 Spanner Graph 问题

本文档介绍了使用 Spanner Graph 时可能会遇到的错误。还提供了错误示例和建议的修复方法。

如果您在查看本问题排查指南后仍需要进一步支持,请参阅获取支持

架构错误

架构结果基于设置和查询 Spanner Graph 中使用的数据集。

元素键必须保证唯一性

错误消息

Neither the primary keys nor any unique index defined on the property graph element source table `Person` provides the uniqueness guarantee for graph element `Person` belonging to the graph `FinGraph`. You want to redefine the element key columns (`name`) based on the source table's primary keys, or create a unique index on the element's key columns.

错误示例

CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person KEY (name)
  );

对元素键列创建唯一索引,并根据源表主键重新定义元素键列。

CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person KEY (id)
  );

或者,对元素键列创建唯一索引。

CREATE UNIQUE INDEX PersonNameIndex ON Person(name);
CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person KEY (name)
  );

元素定义的名称必须是唯一的

错误消息

Account is defined more than once; use a unique name.

错误示例

CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Account,
    Person
  )
  EDGE TABLES (
    Account
      SOURCE KEY(owner_id) REFERENCES Person
      DESTINATION KEY(account_id) REFERENCES Account
  );

为边缘定义使用唯一名称。

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

标签定义对于属性必须保持一致

错误消息

The label Entity is defined with different property declarations. There is one instance of this label defined with properties of [id]. Another instance is defined with properties of [name].

错误示例

CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person LABEL Entity PROPERTIES (name),
    Account LABEL Entity PROPERTIES (id)
  );

您必须在同一标签下使用同一属性名称集。

CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person LABEL Entity PROPERTIES (id, name),
    Account LABEL Entity PROPERTIES (id, name)
  );

属性声明对于属性类型必须保持一致

错误消息

The property declaration of name has type conflicts. There is an existing declaration of type INT64. There is a conflicting one of type STRING.

错误示例

CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person PROPERTIES (name),
    Account PROPERTIES (id AS name)
  );
CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person PROPERTIES (name),
    Account PROPERTIES (CAST(id AS STRING) AS name)
  );

属性定义不得为子查询

错误消息

Property value expression of count cannot contain a subquery.

错误示例

CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person PROPERTIES ((SELECT COUNT(*) FROM Person) AS count)
  );

不适用。禁止使用此条件。

属性定义在同一元素定义中必须保持一致

错误消息

Property location has more than one definition in the element table Person

错误示例

CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person
      LABEL Person PROPERTIES (country AS location)
      LABEL Entity PROPERTIES (city AS location)
  );

使用相同的属性定义。

CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person
      LABEL Person PROPERTIES (country AS location)
      LABEL Entity PROPERTIES (country AS location)
  );

或者,分配不同的属性名称。

CREATE OR REPLACE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person
      LABEL Person PROPERTIES (country AS location)
      LABEL Entity PROPERTIES (city AS city)
  );

查询错误

查询结果基于设置和查询 Spanner Graph 中使用的数据集。

图表元素无法作为查询结果返回

错误消息

Returning expressions of type GRAPH_ELEMENT is not allowed

错误示例

GRAPH FinGraph
MATCH (n:Account)
RETURN n;
GRAPH FinGraph
MATCH (n:Account)
RETURN TO_JSON(n) AS n;

属性规范无法与 WHERE 子句搭配使用

错误消息

WHERE clause cannot be used together with property specification

错误示例

GRAPH FinGraph
MATCH (n:Account {id: 1} WHERE n.is_blocked)
RETURN n.id;

您可以尝试以下建议的修复方法之一。

GRAPH FinGraph
MATCH (n:Account {id: 1})
WHERE n.is_blocked
RETURN n.id;
GRAPH FinGraph
MATCH (n:Account WHERE n.id = 1 AND n.is_blocked )
RETURN n.id;
GRAPH FinGraph
MATCH (n:Account {id: 1, is_blocked: TRUE})
RETURN n.id;

不允许引用之前语句中定义的变量

错误消息

Name 'account_id', defined in the previous statement, can only be referenced in the outermost WHERE clause of MATCH

说明

不允许在 MATCH 模式中引用之前语句中定义的变量。在图表查询中,之前语句定义的名称只能在 MATCH 的最外层 WHERE 子句中使用。

错误示例
GRAPH FinGraph
LET account_id = 1
MATCH (n:Account {id: account_id})
RETURN n.id;
GRAPH FinGraph
LET account_id = 1
MATCH (n:Account)
WHERE n.id = account_id
RETURN n.id;

不允许重新定义相关图表变量

错误消息

The name account is already defined; redefining graph element variables in a subquery is not allowed. To refer to the same graph element, use a different name and add an explicit filter that checks for equality.

说明

在图表查询中,无法在内部图表子查询中重新定义图表元素名称。此场景可能被解读为引用与外部范围相同的图表元素,或是被解读为绑定到新的图表元素,这会遮盖外部范围名称。禁止重新定义。

错误示例

GRAPH FinGraph
MATCH (account:Account)
RETURN account.id AS account_id, VALUE {
  MATCH (account:Account)-[transfer:Transfers]->(:Account)
  RETURN SUM(transfer.amount) AS total_transfer
} AS total_transfer;
GRAPH FinGraph
MATCH (account:Account)
RETURN 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;

查询语义问题

查询结果基于设置和查询 Spanner Graph 中使用的数据集。

不同的 WHEREFILTER 生成不同的输出

说明

FILTER 是一个语句;WHERE 是一个子句,作为 MATCHOPTIONAL MATCH 语句的一部分。

在第一个示例中,WHERE 子句会向 OPTIONAL MATCH 语句中描述的模式添加额外限制。这不是匹配完成后的过滤条件。

在第二个示例中,FILTER 语句是匹配完成后的过滤条件。

示例问题

以下示例具有不同的输出,因为 WHEREFILTER 不同。

示例 1

GRAPH FinGraph
MATCH (n:Account {id: 7})
OPTIONAL MATCH (m:Account)
WHERE FALSE
RETURN n.id AS n_id, m.id AS m_id;
n_id m_id
7 null

示例 2

GRAPH FinGraph
MATCH (n:Account {id: 7})
OPTIONAL MATCH (m:Account)
FILTER FALSE
RETURN n.id AS n_id, m.id AS m_id;

空结果。

在语句间传播不同的变量导致不同的输出

说明

在 Graph Query Language 中,多次声明的变量在所有出现位置都引用同一图表元素。

在示例 1 中,没有任何 Account 节点的 id 同时为 716。因此,系统会返回空结果。

在示例 2 中,系统不会从之前的语句返回名称 n(只会返回 id)。因此,第二个 MATCH 会查找 id16Account 节点。

示例问题

以下示例具有不同的输出,因为不同的变量在语句间传播。

示例 1

GRAPH FinGraph
MATCH (n:Account {id: 7})
RETURN n

NEXT

MATCH (n:Account {id: 16})
RETURN n.id AS n_id;

空结果。

示例 2

GRAPH FinGraph
MATCH (n:Account {id: 7})
RETURN n.id AS id

NEXT

MATCH (n:Account {id: 16})
RETURN n.id AS n_id;
n_id
16

如果后续语句不是 LIMIT,系统会忽略 ORDER BY

说明

在 Graph Query Language 中,除非满足以下条件之一,否则系统会忽略 ORDER BY 语句:

  • ORDER BY 是最后一个语句。
  • ORDER BY 之后紧跟着 LIMIT

在示例 1 中,LIMIT 并非紧跟在 ORDER BY 之后;最后的 LIMIT 是单独的。这意味着引擎会忽略 ORDER BY

在示例 2 中,ORDER BY 适用,因为 LIMIT 紧跟在 ORDER BY 之后。

示例问题

以下示例具有不同的输出,因为在示例 1 中,当在没有 LIMIT 的情况下使用 ORDER BY 语句时,系统会忽略该语句。

示例 1

GRAPH FinGraph
MATCH (n:Account)
ORDER BY n.id DESC
RETURN n.id
LIMIT 3;
n_id
7

示例 2

GRAPH FinGraph
MATCH (n:Account)
ORDER BY n.id DESC
LIMIT 3
RETURN n.id;
n_id
20

不同的边缘模式会产生不同的输出

说明

在错误示例中使用的数据集中,ANY 方向的边缘模式会与图表中的每个 Transfers 边缘匹配两次。

在示例 1 中,从 Account(id=x)Account(id=y)Transfers 边缘可以匹配两次,如下所示:

  • n= Account(id=x),m= Account(id=y)
  • n= Account(id=y),m= Account(id=x)

在示例 2 中,只有一个匹配项,其中 n=Account(id=x),m=Account(id=y)

因此,示例 1 中的查询会返回 10,而示例 2 中的查询会返回 5

示例问题

以下示例具有不同的输出,因为它们使用不同的边缘模式。

示例 1

GRAPH FinGraph
MATCH (n:Account)-[:Transfers]-(m:Account)
RETURN COUNT(*) AS num_transfer_edges;
num_transfer_edges
10

示例 2

GRAPH FinGraph
MATCH (n:Account)-[:Transfers]->(m:Account)
RETURN COUNT(*) AS num_transfer_edges;
num_transfer_edges
5

变更错误

变更结果基于设置和查询 Spanner Graph 中使用的数据集。

缺少来源节点会违反外键限制条件

错误消息

Parent row for row [...] in table AccountTransferAccount is missing. Row cannot be written.

说明

AccountTransferAccount 边缘表是 INTERLEAVED INTO PARENT Account node 表。如需创建 Transfer 边缘,其父级 Account 节点必须已存在。

错误示例

INSERT INTO AccountTransferAccount (id, to_id, create_time, amount)
VALUES (100, 1, PENDING_COMMIT_TIMESTAMP(), 200);

先创建前导 Account 节点,然后创建 Transfer 边缘。

缺少目标节点会违反外键限制条件

错误消息

Foreign key constraint FK_TransferTo is violated on table AccountTransferAccount. Cannot find referenced values in Account(id)

说明

AccountTransferAccount 表通过名为 FK_TransferToForeignKey 引用 Accounttable。如需创建 Transfer 边缘,引用的尾随节点 Account 节点必须已存在。

错误示例

INSERT INTO AccountTransferAccount (id, to_id, create_time, amount)
VALUES (1, 100, PENDING_COMMIT_TIMESTAMP(), 200);

先创建尾随 Account 节点,然后创建 Transfer 边缘。

孤立的传出边缘违反了父子关系

错误消息

Integrity constraint violation during DELETE/REPLACE. Found child row [...] in table AccountTransferAccount

说明

AccountTransferAccount 边缘表是 INTERLEAVED INTO PARENT Account 节点表,而要删除的 Account 节点仍与传出边缘相连。

错误示例

DELETE FROM Account WHERE id = 1;

先删除所有传出 Transfer 边缘,然后删除 Account 节点。或者,为 INTERLEAVE 定义 ON DELETE CASCADE,让 Spanner 自动删除这些边缘。

孤立的传入边缘违反了父子关系

错误消息

Foreign key constraint violation when deleting or updating referenced row(s): referencing row(s) found in table AccountTransferAccount

说明

AccountTransferAccount 边缘表通过 ForeignKey 引用 Account 节点表,而要删除的 Account 节点仍与传入边缘相连。

错误示例

DELETE FROM Account WHERE id = 1;

先删除所有传入 Transfer 边缘,然后删除 Account 节点。或者,为 ForeignKey 定义 ON DELETE CASCADE,让 Spanner 自动删除这些边缘。