Source: https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/variable-definition/graph-variable/ Documentation version: v5.3.2 # 图变量 图变量用于存储子图以进行查询和计算。关键字`GRAPH`用于定义图变量。 定义图变量有两种方式: - 基于图查询:使用 MATCH 语句从现有图中检索子图,并将其存储在图变量中。 - 基于图类型:使用预定义的图类型声明一个图变量,然后使用 [IMPORT](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/in-out/import/) 语句向其中导入数据。 ## 前提条件 - 已创建图。更多信息,请参见 [CREATE GRAPH](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/ddl/graph/create/)。 - 具备在当前 Schema 执行`MATCH ANY GRAPH`操作的权限,或具备在所查询的图上执行`MATCH`操作的权限。更多信息,请参见[角色与权限](https://dev-docs.yueshu.com.cn/v5.3.2/server-admin/authorization/)。 ## 使用说明 - 不支持通过 DML 修改其中的图数据(如对点、边进行`INSERT`、`DELETE`,或使用`SET`修改点、边属性)。 - 不能在其上创建索引等结构。 - 允许执行`SET .clear()`用于清空图变量后重新导入数据。 ## 语法 ### 基于查询定义图变量 语法图源码 graph_variable_definition_from_query ```` graph_variable_definition_from_query ::= 'PROPERTY'? 'GRAPH' graph_variable ( 'TYPED'? 'GRAPH' '{' ( (('NODE' | 'VERTEX') 'TYPE'? node_type_name '(' node_type_filler ')') | (('EDGE' | 'RELATIONSHIP') 'TYPE'? edge_type_name ( '(' source_node_type_name ')' '-[' edge_type_filler ']->' '(' destination_node_type_name ')' | '(' destination_node_type_name ')' '<-[' edge_type_filler ']-' '(' source_node_type_name ')' | '(' source_node_type_name ')' '~[' edge_type_filler ']~' '(' destination_node_type_name ')' ) ) ) ( ',' ( (('NODE' | 'VERTEX') 'TYPE'? node_type_name '(' node_type_filler ')') | (('EDGE' | 'RELATIONSHIP') 'TYPE'? edge_type_name ( '(' source_node_type_name ')' '-[' edge_type_filler ']->' '(' destination_node_type_name ')' | '(' destination_node_type_name ')' '<-[' edge_type_filler ']-' '(' source_node_type_name ')' | '(' source_node_type_name ')' '~[' edge_type_filler ']~' '(' destination_node_type_name ')' ) ) ) )* '}' )? '=' 'GRAPH' '{' use_clause? match_statement return_statement '}' ```` ### 基于图类型定义图变量 语法图源码 graph_variable_definition_from_type ```` graph_variable_definition_from_type ::= 'PROPERTY'? 'GRAPH' graph_variable 'TYPED' graph_type_name ```` ### 清除图变量 语法图源码 graph_variable_clear ```` graph_variable_clear ::= 'SET' graph_variable '.clear()' ```` ## 参数 ### `graph_variable` 要定义的图变量的名称。`graph_variable`可以是常规标识符或使用反引号(```)包围的分隔标识符。有关标识符的更多信息,请参见[标识符命名规则](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/overview/keywords-identifiers/)。 ### `node_type_name` 待定义的图变量中的点类型的名称。此处指定的点类型必须在后续的 MATCH 及 RETURN 语句中指定。 ### `node_type_filler` 待定义的图变量中的点类型的属性与标签。 此处指定的属性与标签必须与后续 MATCH 及 RETURN 语句中指定的相应点类型的属性与标签保持一致。 关于此参数的更多信息,请参见 [CREATE GRAPH TYPE](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/ddl/graph-type/create/#_3) 中的语法图。 ### `edge_type_name` 待定义的图变量中的边类型的名称。此处指定的边类型必须在后续的 MATCH 及 RETURN 语句中指定。 ### `source_node_type_name` 待定义的图变量中边类型的起始点类型的名称。此处指定的点类型必须在后续的 MATCH 及 RETURN 语句中指定。 ### `destination_node_type_name` 待定义的图变量中边类型的目标点类型的名称。此处指定的点类型必须在后续的 MATCH 及 RETURN 语句中指定。 ### `edge_type_filler` 待定义的图变量中边类型的属性与标签。 此处指定的属性与标签必须与后续 MATCH 及 RETURN 语句中指定的相应边类型的属性与标签保持一致。 关于此参数的更多信息,请参见 [CREATE GRAPH TYPE](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/ddl/graph-type/create/#_3) 中的语法图。 ### `use_clause` USE 子句指定在 MATCH 语句中使用的图。若要使用的图已设置为主图,则可省略该子句。更多信息,请参见 [USE](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/dql/clauses/use-graph/)。 ### `match_statement` MATCH 语句检索将存储在图变量中的子图,该子图必须至少包含一个点。 如果指定了`node_type_name`或`edge_type_name`,则相应的点类型或边类型必须在 MATCH 语句中指定。 更多信息,请参见 [MATCH](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/dql/match/)。 ### `return_statement` RETURN 语句指定将存储在图变量中的子图,该子图必须至少包含一个点。 如果指定了`node_type_name`或`edge_type_name`,则相应的点类型或边类型必须在 RETURN 语句中指定。 更多信息,请参见 [RETURN](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/dql/return/)。 ### `graph_type_name` 现有图类型的名称。图变量将使用该图类型定义的结构创建,但不包含数据。之后可以使用 [IMPORT](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/in-out/import/) 语句导入数据。 ## 行为 ### 向图变量导入数据 基于图类型定义图变量后,可以使用`USE`子句切换到该图变量,然后使用 [IMPORT](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/in-out/import/) 语句填充数据。不允许向非空图变量导入数据。若要重新导入数据,必须先使用`SET .clear()`清除图变量。 ### 清除图变量 `SET .clear()`语句从图变量中移除所有点和边。图变量本身及其类型定义保留。清除后,可以向图变量导入新数据。 ### 在图变量上运行过程 向图变量填充数据后,可以使用`USE`子句切换到该图变量并在其上运行过程。 ## 示例 以下示例基于[示例数据集](https://dev-docs.yueshu.com.cn/v5.3.2/database-gql-reference/overview/example-dataset/)。 ### 基于查询定义图变量 ```` ''' GRAPH g = GRAPH { USE movie MATCH (a@Actor) RETURN a } USE g MATCH (v) RETURN v.id, v.name AS name ORDER BY v.id LIMIT 3 ''' ```` 上述语句定义了一个图变量 g,用于存储所有 Actor 点,然后查询该变量以按 ID 顺序检索三个点。 返回: ```` +------+---------------+ | v.id | name | +------+---------------+ | 2 | Mark Hamill | | 3 | Harrison Ford | | 4 | Carrie Fisher | +------+---------------+ ```` ### 基于查询定义图变量(内联图类型定义) Note 使用内联图类型定义的图变量必须指定初始值(即`= GRAPH { query }`部分不可省略)。如需定义空图变量,请使用预定义的具名图类型,请参见下文示例基于图类型定义图变量。 ```` ''' GRAPH g TYPED GRAPH { NODE TYPE Actor (LABEL Person {id INT64 PRIMARY KEY, name STRING, birthDate DATE } ), NODE TYPE Movie (LABEL Movie {id INT64 PRIMARY KEY, name STRING }), EDGE TYPE Act (Actor)-[LABEL Act{}]->(Movie) } = GRAPH { USE movie MATCH (n@Actor)-[r@Act]->(m@Movie) RETURN n, m, r } USE g MATCH (v1@Actor) -[e]-> (v2@Movie) RETURN v1.name AS name ORDER BY name LIMIT 3 ''' ```` 上述语句定义了一个图变量`g`,其中预定义了点类型`Actor`和`Movie`以及边类型`Act`。图变量`g`存储了 MATCH 语句中检索得到的`Actor`和`Movie`类型的点以及`Act`类型的边。 返回: ```` +------------------+ | name | +------------------+ | Aaron Eckhart | | Ada Lonati | | Adam Alexi-Malle | +------------------+ ```` ### 基于图类型定义图变量 以下示例定义了一个具有预定义图类型的空图变量,并从表变量导入数据。 ```` ''' -- 创建图类型 CREATE GRAPH TYPE IF NOT EXISTS empty_typed_gt AS { NODE Person ( LABEL Person { id INT PRIMARY KEY, name STRING } ), EDGE Knows (Person)-[:Knows{ id INT, MULTIEDGE KEY() }]->(Person) } ''' ```` ```` ''' GRAPH g TYPED empty_typed_gt USE g { TABLE persons TYPED TABLE {id INT, name STRING} = {id: 1, name: "Alice"}, {id: 2, name: "Bob"} TABLE edges TYPED TABLE {src_id INT, dst_id INT, id INT} = {src_id: 1, dst_id: 2, id: 10} IMPORT INTO GRAPH { NODE (p@Person{ id: id, name: name }) FROM persons, EDGE (id:src_id)-[e@Knows{ id: id }]->(id:dst_id) FROM edges } MATCH (p@Person)-[e@Knows]->(q@Person) RETURN p.id, p.name, q.id, q.name, e.id ORDER BY e.id } ''' ```` 返回: ```` +------+--------+------+--------+------+ | p.id | p.name | q.id | q.name | e.id | +------+--------+------+--------+------+ | 1 | Alice | 2 | Bob | 10 | +------+--------+------+--------+------+ ```` ### 清除图变量 以下示例展示如何清除图变量并在之后查询它。 ```` ''' GRAPH g = GRAPH{ USE movie MATCH (a@Actor) RETURN a } SET g.clear() USE g MATCH (v) RETURN v.id, v.name ''' ```` 清除后,图变量不包含数据,因此查询返回空结果: ```` +------+--------+ | v.id | v.name | +------+--------+ +------+--------+ ```` ### 在图变量上运行过程 以下示例定义了一个图变量,填充数据,然后在其上运行一个使用活跃集和聚合的过程。 ```` ''' -- 创建过程 CREATE OR REPLACE PROCEDURE proc_graph_active_set_agg() RETURNS (cnt INT) AS { VALUE active_set ACTIVE_SET VALUE cnt SumAgg = 0 MATCH (s@Actor) WHERE s.id < 5 FINALLY { SET active_set = s } MATCH (v@Actor) WHERE v IN active_set PER NODE (v) { SET @cnt += 1 } RETURN @cnt } ''' ```` ```` ''' -- 在图变量上运行过程 GRAPH g = GRAPH{ USE movie MATCH (a@Actor) RETURN a } USE g CALL proc_graph_active_set_agg() RETURN cnt ''' ```` 返回: ```` +-----+ | cnt | +-----+ | 3 | +-----+ ```` ### 图变量上的迭代计算 以下示例展示了图变量上的迭代计算模式。每轮迭代中,一个点(由迭代索引标识)被"激活",其`val`属性值加 1。计算结果导出到表变量后,清空图变量并重新导入更新后的数据,进入下一轮迭代。 1. 创建图类型。 ```` ''' CREATE GRAPH TYPE IF NOT EXISTS gv_iter_gt AS { NODE Person ( LABEL Person { id INT PRIMARY KEY, val INT } ), EDGE Link (Person)-[:Link{ id INT, MULTIEDGE KEY() }]->(Person) } ''' ```` 2. 创建临时图并导入数据。 创建一个临时图,导入 6 个点(ID 为 0–5,初始`val`均为 0)和 5 条边,构成一条链式结构(0→1→2→3→4→5)。 ```` ''' CREATE TEMPORARY GRAPH IF NOT EXISTS #gv_iter_base TYPED gv_iter_gt ''' ''' USE #gv_iter_base { TABLE nodes TYPED TABLE {id INT, val INT} = {id: 0, val: 0}, {id: 1, val: 0}, {id: 2, val: 0}, {id: 3, val: 0}, {id: 4, val: 0}, {id: 5, val: 0} TABLE edges TYPED TABLE {src INT, dst INT, eid INT} = {src: 0, dst: 1, eid: 1}, {src: 1, dst: 2, eid: 2}, {src: 2, dst: 3, eid: 3}, {src: 3, dst: 4, eid: 4}, {src: 4, dst: 5, eid: 5} IMPORT INTO GRAPH { NODE (p@Person{ id: id, val: val }) FROM nodes, EDGE (id: src)-[e@Link{ id: eid }]->(id: dst) FROM edges } } ''' ```` 导入后的图结构如下: ```` (0)--1-->(1)--2-->(2)--3-->(3)--4-->(4)--5-->(5) ```` 所有点的`val`初始值均为 0。 3. 创建过程。 本示例需要三个过程:一个用于将数据导入图变量,一个用于执行单步计算,一个用于驱动外层迭代循环。 导入过程:将表变量中的点和边数据导入图变量。 ```` ''' CREATE OR REPLACE PROCEDURE gv_iter_import(nodes TABLE, edges TABLE) AS { IMPORT INTO GRAPH { NODE (p@Person{ id: id, val: val }) FROM nodes, EDGE (id: src)-[e@Link{ id: eid }]->(id: dst) FROM edges } } ''' ```` 单步计算过程:执行一步计算。将当前`val`值复制到临时聚合变量中,激活 ID 等于迭代索引的点并将其值加 1,最后将所有点和边导出到表变量,供下一轮迭代使用。 ```` ''' CREATE OR REPLACE PROCEDURE gv_iter_step(iter INT, nodes TABLE, edges TABLE) AS { VALUE active_set ACTIVE_SET VALUE active_cnt SumAgg = 0 NODE VALUE next_val SumAgg = 0 -- 将当前 val 值复制到聚合变量 MATCH (v@Person) PER NODE (v) { SET v.@next_val = v.val } -- 激活 ID 等于迭代索引的点 MATCH (v@Person) WHERE v.id = iter FINALLY { SET active_set = v } -- 将被激活点的值加 1 MATCH (v@Person) WHERE v IN active_set PER NODE (v) { SET v.@next_val = v.val + 1 SET @active_cnt += 1 } -- 导出所有点和边,供下一轮迭代使用 MATCH (v@Person) PER NODE (v) { EXPORT v.id AS id, v.@next_val AS val INTO nodes } MATCH (s@Person)-[e@Link]->(t@Person) PER PATH { EXPORT s.id AS src, t.id AS dst, e.id AS eid INTO edges } LOG_INFO("gv_iter_step iter=", iter, " active_cnt=", @active_cnt) } ''' ```` 外层迭代过程:驱动整个迭代循环。首先将源临时图中的初始数据导出到表变量并导入图变量,然后在每轮迭代中执行计算、清空图变量、重新导入更新后的数据。 ```` ''' CREATE OR REPLACE PROCEDURE gv_iter_outer(max_iter INT) RETURNS (id INT, val INT) AS { GRAPH g TYPED gv_iter_gt TABLE nodes TYPED TABLE {id INT, val INT} TABLE edges TYPED TABLE {src INT, dst INT, eid INT} VALUE iter = 0 -- 从源临时图导出初始数据 MATCH (v@Person) PER NODE (v) { EXPORT v.id AS id, v.val AS val INTO nodes } MATCH (s@Person)-[e@Link]->(t@Person) PER PATH { EXPORT s.id AS src, t.id AS dst, e.id AS eid INTO edges } -- 将初始数据导入图变量 USE g CALL gv_iter_import(nodes, edges) FINISH SET nodes.clear() SET edges.clear() -- 迭代循环 WHILE (iter < max_iter) THEN { USE g CALL gv_iter_step(iter, nodes, edges) FINISH IF (iter <> max_iter - 1) THEN { SET g.clear() USE g CALL gv_iter_import(nodes, edges) FINISH SET nodes.clear() SET edges.clear() } SET iter = iter + 1 } FOR r IN nodes RETURN r.id AS id, r.val AS val ORDER BY r.id } ''' ```` 4. 执行迭代计算。 在源临时图上调用外层过程,执行 3 轮迭代: ```` ''' USE #gv_iter_base CALL gv_iter_outer(3) RETURN id, val ''' ```` 返回结果: ```` +----+-----+ | id | val | +----+-----+ | 0 | 1 | | 1 | 1 | | 2 | 1 | | 3 | 0 | | 4 | 0 | | 5 | 0 | +----+-----+ Log: 2026-03-16T10:14:11.570209 INFO - gv_iter_step iter=0 active_cnt=1 2026-03-16T10:14:11.606670 INFO - gv_iter_step iter=1 active_cnt=1 2026-03-16T10:14:11.634837 INFO - gv_iter_step iter=2 active_cnt=1 ```` 经过 3 轮迭代,点 0、1、2 分别在第 0、1、2 轮被激活,其`val`值从 0 增加到 1。点 3、4、5 未被激活,`val`值保持为 0。