跳到主要内容
版本:3.12.0

GO

GO语句是 悦数图数据库 图数据库中用于从给定起始点开始遍历图的语句。GO语句采用的路径类型是walk,即遍历时点和边都可以重复。

openCypher 兼容性

本文操作仅适用于原生 nGQL。

语法

GO [[<M> TO] <N> {STEP|STEPS} ] FROM <vertex_list>
OVER <edge_type_list> [{REVERSELY | BIDIRECT}]
[ WHERE <conditions> ]
YIELD [DISTINCT] <return_list>
[{ SAMPLE <sample_list> | <limit_by_list_clause> }]
[| GROUP BY {<col_name> | expression> | <position>} YIELD <col_name>]
[| ORDER BY <expression> [{ASC | DESC}]]
[| LIMIT [<offset>,] <number_rows>];

<vertex_list> ::=
<vid> [, <vid> ...]

<edge_type_list> ::=
<edge_type> [, <edge_type> ...]
| *

<return_list> ::=
<col_name> [AS <col_alias>] [, <col_name> [AS <col_alias>] ...]
  • <N> {STEP|STEPS}:指定跳数。如果没有指定跳数,默认值N1。如果N0悦数图数据库 不会检索任何边。

  • M TO N {STEP|STEPS}:遍历M~N跳的边。如果M0,输出结果和M1相同,即GO 0 TO 2GO 1 TO 2是相同的。

  • <vertex_list>:用逗号分隔的点 ID 列表。

  • <edge_type_list>:遍历的 Edge type 列表。

  • REVERSELY | BIDIRECT:默认情况下检索的是<vertex_list>的出边(正向),REVERSELY表示反向,即检索入边;BIDIRECT 为双向,即检索正向和反向。可通过YIELD返回<edge_type>._type字段判断方向,其正数为正向,负数为反向。

  • WHERE <conditions>:指定遍历的过滤条件。用户可以在起始点、目的点和边使用WHERE子句,还可以结合ANDORNOTXOR一起使用。详情参见 WHERE

    备注
    • 遍历多个 Edge type 时,WHERE子句有一些限制。例如不支持WHERE edge1.prop1 > edge2.prop2
    • GO 语句执行时先遍历所有的点,然后再根据过滤器条件进行过滤。

:::

  • YIELD [DISTINCT] <return_list>:定义需要返回的输出。 <return_list>建议使用 Schema 相关函数指定返回信息,当前支持src(edge)dst(edge)type(edge)等,暂不支持嵌套函数。详情参见 YIELD

  • SAMPLE <sample_list>:用于在结果集中取样。详情参见 SAMPLE

  • <limit_by_list_clause>:用于在遍历过程中逐步限制输出数量。详情参见 LIMIT

  • GROUP BY:根据指定属性的值将输出分组。详情参见 GROUP BY。分组后需要再次使用YIELD定义需要返回的输出。

  • ORDER BY:指定输出结果的排序规则。详情参见 ORDER BY

    备注

    没有指定排序规则时,输出结果的顺序不是固定的。

:::

  • LIMIT [<offset>,] <number_rows>]:限制输出结果的行数。详情参见 LIMIT

使用说明

  • GO 语句中的WHEREYIELD子句通常结合属性引用符($^$$)或函数properties($^)properties($$)指定点的属性;使用函数properties(edge)指定边的属性。用法参见属性引用符Schema 相关函数
  • GO 复合语句中如需引用子查询的结果,需要为该结果设置别名,并使用管道符|传递给下一个子查询,同时在下一个子查询中使用$-引用该结果的别名。详情参见管道符
  • 当查询属性没有值时,返回结果显示NULL

场景及示例

查询起始点的直接邻居点

场景:查询某个点的直接相邻点,例如查询一个人所属队伍。

# 返回 player102 所属队伍。
nebula> GO FROM "player102" OVER serve YIELD dst(edge);
+-----------+
| dst(EDGE) |
+-----------+
| "team203" |
| "team204" |
+-----------+

查询指定跳数内的点

场景:查询一个点在指定跳数内的所有点,例如查询一个人两跳内的朋友。

# 返回距离 player102 两跳的朋友。
nebula> GO 2 STEPS FROM "player102" OVER follow YIELD dst(edge);
+-------------+
| dst(EDGE) |
+-------------+
| "player101" |
| "player125" |
| "player100" |
| "player102" |
| "player125" |
+-------------+
# 查询 player100 1~2 跳内的朋友。
nebula> GO 1 TO 2 STEPS FROM "player100" OVER follow \
YIELD dst(edge) AS destination;
+-------------+
| destination |
+-------------+
| "player101" |
| "player125" |
...

# 该 MATCH 查询与上一个 GO 查询具有相同的语义。
nebula> MATCH (v) -[e:follow*1..2]->(v2) \
WHERE id(v) == "player100" \
RETURN id(v2) AS destination;
+-------------+
| destination |
+-------------+
| "player100" |
| "player102" |
...

添加过滤条件

场景:查询满足特定条件的点和边,例如查询起始点和目的点之间具有特定属性的边。

# 使用 WHERE 添加过滤条件。
nebula> GO FROM "player100", "player102" OVER serve \
WHERE properties(edge).start_year > 1995 \
YIELD DISTINCT properties($$).name AS team_name, properties(edge).start_year AS start_year, properties($^).name AS player_name;

+-----------------+------------+---------------------+
| team_name | start_year | player_name |
+-----------------+------------+---------------------+
| "Spurs" | 1997 | "Tim Duncan" |
| "Trail Blazers" | 2006 | "LaMarcus Aldridge" |
| "Spurs" | 2015 | "LaMarcus Aldridge" |
+-----------------+------------+---------------------+

查询所有边

场景:查询起始点关联的所有边。

# 返回 player102 关联的所有边。
nebula> GO FROM "player102" OVER * BIDIRECT YIELD edge AS e;
+-----------------------------------------------------------------------+
| e |
+-----------------------------------------------------------------------+
| [:follow "player101"->"player102" @0 {degree: 90}] |
| [:follow "player103"->"player102" @0 {degree: 70}] |
| [:follow "player135"->"player102" @0 {degree: 80}] |
| [:follow "player102"->"player100" @0 {degree: 75}] |
| [:follow "player102"->"player101" @0 {degree: 75}] |
| [:serve "player102"->"team203" @0 {end_year: 2015, start_year: 2006}] |
| [:serve "player102"->"team204" @0 {end_year: 2019, start_year: 2015}] |
+-----------------------------------------------------------------------+

查询多个 Edge type

场景:查询起始点关联的多个边类型可以通过设置多个Edge Type实现,也可以通过设置*关联所有的边类型。

# 遍历多个 Edge type。
nebula> GO FROM "player100" OVER follow, serve \
YIELD properties(edge).degree, properties(edge).start_year;
+-------------------------+-----------------------------+
| properties(EDGE).degree | properties(EDGE).start_year |
+-------------------------+-----------------------------+
| 95 | __NULL__ |
| 95 | __NULL__ |
| __NULL__ | 1997 |
+-------------------------+-----------------------------+

查询入边方向的点

# 返回关注 player100 的邻居点。
nebula> GO FROM "player100" OVER follow REVERSELY \
YIELD src(edge) AS destination;
+-------------+
| destination |
+-------------+
| "player101" |
| "player102" |
...

# 该 MATCH 查询与上一个 GO 查询具有相同的语义。
nebula> MATCH (v)<-[e:follow]- (v2) WHERE id(v) == 'player100' \
RETURN id(v2) AS destination;
+-------------+
| destination |
+-------------+
| "player101" |
| "player102" |
...

子查询作为起始点

场景:使用子查询的结果作为图遍历的起始点。

# 查询 player100 年龄大于 20 的朋友和这些朋友所属队伍。
nebula> GO FROM "player100" OVER follow \
YIELD dst(edge) AS id | \
GO FROM $-.id OVER serve \
WHERE properties($^).age > 20 \
YIELD properties($^).name AS Friend, properties($$).name AS Team;
+---------------------+-----------------+
| Friend | Team |
+---------------------+-----------------+
| "Tony Parker" | "Spurs" |
| "Tony Parker" | "Hornets" |
| "Manu Ginobili" | "Spurs" |
+---------------------+-----------------+

# 该 MATCH 查询与上一个 GO 查询具有相同的语义。
nebula> MATCH (v)-[e:follow]-> (v2)-[e2:serve]->(v3)  \
WHERE id(v) == 'player100' \
AND properties(v2).age > 20 \
RETURN v2.player.name AS Friend, v3.team.name AS Team;
+---------------------+-----------------+
| Friend | Team |
+---------------------+-----------------+
| "Tony Parker" | "Spurs" |
| "Tony Parker" | "Hornets" |
| "Manu Ginobili" | "Spurs" |
+---------------------+-----------------+

使用 GROUP BY 分组

场景:使用GROUP BY分组,然后使用YIELD返回分组后的结果。

# 根据年龄分组。
nebula> GO 2 STEPS FROM "player100" OVER follow \
YIELD src(edge) AS src, dst(edge) AS dst, properties($$).age AS age \
| GROUP BY $-.dst \
YIELD $-.dst AS dst, collect_set($-.src) AS src, collect($-.age) AS age;
+-------------+----------------------------+----------+
| dst | src | age |
+-------------+----------------------------+----------+
| "player125" | {"player101"} | [41] |
| "player100" | {"player125", "player101"} | [42, 42] |
| "player102" | {"player101"} | [33] |
+-------------+----------------------------+----------+

使用 ORDER BY 和 LIMIT 排序和限制输出结果

# 分组并限制输出结果的行数。
nebula> $a = GO FROM "player100" OVER follow YIELD src(edge) AS src, dst(edge) AS dst; \
GO 2 STEPS FROM $a.dst OVER follow \
YIELD $a.src AS src, $a.dst, src(edge), dst(edge) \
| ORDER BY $-.src | OFFSET 1 LIMIT 2;
+-------------+-------------+-------------+-------------+
| src | $a.dst | src(EDGE) | dst(EDGE) |
+-------------+-------------+-------------+-------------+
| "player100" | "player101" | "player100" | "player101" |
| "player100" | "player125" | "player100" | "player125" |
+-------------+-------------+-------------+-------------+

其他用法

# 在多个边上通过 IS NOT EMPTY 进行判断。
nebula> GO FROM "player100" OVER follow WHERE properties($$).name IS NOT EMPTY YIELD dst(edge);
+-------------+
| dst(EDGE) |
+-------------+
| "player125" |
| "player101" |
+-------------+