跳转至

GO

GO语句是 NebulaGraph 图数据库中用于从给定起始点开始遍历图的语句。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,NebulaGraph 不会检索任何边。
  • 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

    Note

    • 遍历多个 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

    Note

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

  • 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 src(edge) AS id | \
        GO FROM $-.id OVER serve \
        WHERE properties($^).age > 20 \
        YIELD properties($^).name AS Friend, properties($$).name AS Team;
+---------------------+-----------------+
| Friend              | Team            |
+---------------------+-----------------+
| "Tim Duncan"        | "Spurs"         |
| "Tim Duncan"        | "Spurs"         |
+---------------------+-----------------+

# 该 MATCH 查询与上一个 GO 查询具有相同的语义。
nebula> MATCH (v)<-[e:follow]- (v2)-[e2:serve]->(v3)  \
        WHERE id(v) == 'player100' \
        RETURN v2.player.name AS FriendOf, v3.team.name AS Team;
+---------------------+-----------------+
| FriendOf            | Team            |
+---------------------+-----------------+
| "Boris Diaw"        | "Spurs"         |
| "Boris Diaw"        | "Jazz"          |
| "Boris Diaw"        | "Suns"          |
...

使用 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" |
+-------------+

最后更新: June 19, 2024