NebulaGraph学习:2.常用命令(nGQL)
1. 原文
原文的示例穿插在每一个小结中,完整的示例整合在文末
2. 图空间和Schema
一个 Nebula Graph 实例由一个或多个图空间组成。每个图空间都是物理隔离的,用户可以在同一个实例中使用不同的图空间存储不同的数据集。
为了在图空间中插入数据,需要为图数据库定义一个 Schema。Nebula Graph 的 Schema 是由如下几部分组成。
组成部分 | 说明 |
---|---|
点(Vertex) | 表示现实世界中的实体。一个点可以有 0 到多个标签。 |
标签(Tag) | 点的类型,定义了一组描述点类型的属性。 |
边(Edge) | 表示两个点之间有方向的关系。 |
边类型(Edge type) | 边的类型,定义了一组描述边的类型的属性。 |
更多信息,请参见数据结构。
本文将使用下图的数据集演示基础操作的语法。
2.1 异步实现创建和修改
Nebula Graph 中执行如下创建和修改操作,是异步实现的。要在下一个心跳周期之后才能生效,否则访问会报错。为确保数据同步,后续操作能顺利进行,请等待 2 个心跳周期(20 秒)。
CREATE SPACE
CREATE TAG
CREATE EDGE
ALTER TAG
ALTER EDGE
CREATE TAG INDEX
CREATE EDGE INDEX
3. 创建和选择图空间
3.1 nGQL 语法
-
创建图空间
CREATE SPACE [IF NOT EXISTS] <graph_space_name> ( [partition_num = <partition_number>,] [replica_factor = <replica_number>,] vid_type = {FIXED_STRING(<N>) | INT64} ) [COMMENT = '<comment>'];
参数详情请参见 CREATE SPACE。
-
列出创建成功的图空间
SHOW SPACES;
-
选择数据库
USE <graph_space_name>;
3.2 示例
-
执行如下语句创建名为
basketballplayer
的图空间。CREATE SPACE basketballplayer(partition_num=15, replica_factor=1, vid_type=fixed_string(30));
-
执行命令
SHOW HOSTS
检查分片的分布情况,确保平衡分布。如果 Leader distribution 分布不均匀,请执行命令
BALANCE LEADER
重新分配。更多信息,请参见 Storage 负载均衡。 -
选择图空间
basketballplayer
。USE basketballplayer;
用户可以执行命令
SHOW SPACES
查看创建的图空间。
4. 创建 Tag 和 Edge type
4.1 nGQL 语法
CREATE {TAG | EDGE} [IF NOT EXISTS] {<tag_name> | <edge_type_name>}
(
<prop_name> <data_type> [NULL | NOT NULL] [DEFAULT <default_value>] [COMMENT '<comment>']
[{, <prop_name> <data_type> [NULL | NOT NULL] [DEFAULT <default_value>] [COMMENT '<comment>']} ...]
)
[TTL_DURATION = <ttl_duration>]
[TTL_COL = <prop_name>]
[COMMENT = '<comment>'];
参数详情请参见 CREATE TAG 和 CREATE EDGE。
4.2 示例
创建 Tag:player
和team
,以及 Edge type:follow
和serve
。说明如下表。
名称 | 类型 | 属性 |
---|---|---|
player | Tag | name (string), age (int) |
team | Tag | name (string) |
follow | Edge type | degree (int) |
serve | Edge type | start_year (int), end_year (int) |
CREATE TAG player(name string, age int);
CREATE TAG team(name string);
CREATE EDGE follow(degree int);
CREATE EDGE serve(start_year int, end_year int);
5. 插入点和边
用户可以使用INSERT
语句,基于现有的 Tag 插入点,或者基于现有的 Edge type 插入边。
5.1 nGQL 语法
-
插入点
INSERT VERTEX [IF NOT EXISTS] [tag_props, [tag_props] ...] VALUES <vid>: ([prop_value_list]) tag_props: tag_name ([prop_name_list]) prop_name_list: [prop_name [, prop_name] ...] prop_value_list: [prop_value [, prop_value] ...]
vid
是 Vertex ID 的缩写,vid
在一个图空间中是唯一的。参数详情请参见 INSERT VERTEX。 -
插入边
INSERT EDGE [IF NOT EXISTS] <edge_type> ( <prop_name_list> ) VALUES <src_vid> -> <dst_vid>[@<rank>] : ( <prop_value_list> ) [, <src_vid> -> <dst_vid>[@<rank>] : ( <prop_value_list> ), ...]; <prop_name_list> ::= [ <prop_name> [, <prop_name> ] ...] <prop_value_list> ::= [ <prop_value> [, <prop_value> ] ...]
参数详情请参见 INSERT EDGE。
5.2 示例
- 插入代表球员和球队的点。
INSERT VERTEX player(name, age) VALUES "player100":("Tim Duncan", 42);
INSERT VERTEX player(name, age) VALUES "player101":("Tony Parker", 36);
INSERT VERTEX player(name, age) VALUES "player102":("LaMarcus Aldridge", 33);
INSERT VERTEX team(name) VALUES "team203":("Trail Blazers"), "team204":("Spurs");
- 插入代表球员和球队之间关系的边。
INSERT EDGE follow(degree) VALUES "player101" -> "player100":(95);
INSERT EDGE follow(degree) VALUES "player101" -> "player102":(90);
INSERT EDGE follow(degree) VALUES "player102" -> "player100":(75);
INSERT EDGE serve(start_year, end_year) VALUES "player101" -> "team204":(1999, 2018),"player102" -> "team203":(2006, 2015);
6. 查询数据
-
GO 语句可以根据指定的条件遍历数据库。
GO
语句从一个或多个点开始,沿着一条或多条边遍历,返回YIELD
子句中指定的信息。 -
FETCH 语句可以获得点或边的属性。
-
MATCH 语句是查询图数据最常用的,可以灵活的描述各种图模式,但是它依赖索引去匹配 Nebula Graph 中的数据模型,性能也还需要调优。
6.1 nGQL语法
-
GO
GO [[<M> TO] <N> 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>];
-
FETCH
-
查询 Tag 属性
FETCH PROP ON {<tag_name>[, tag_name ...] | *} <vid> [, vid ...] YIELD <return_list> [AS <alias>];
-
查询边属性
FETCH PROP ON <edge_type> <src_vid> -> <dst_vid>[@<rank>] [, <src_vid> -> <dst_vid> ...] YIELD <output>;
-
-
LOOKUP
LOOKUP ON {<vertex_tag> | <edge_type>} [WHERE <expression> [AND <expression> ...]] YIELD <return_list> [AS <alias>]; <return_list> <prop_name> [AS <col_alias>] [, <prop_name> [AS <prop_alias>] ...];
-
MATCH
MATCH <pattern> [<clause_1>] RETURN <output> [<clause_2>];
6.2 GO语句示例
-
从 VID 为
player101
的球员开始,沿着边follow
找到连接的球员。GO FROM "player101" OVER follow YIELD id($$);
-
从 VID 为
player101
的球员开始,沿着边follow
查找年龄大于或等于 35 岁的球员,并返回他们的姓名和年龄,同时重命名对应的列。GO FROM "player101" OVER follow WHERE properties($$).age >= 35 \ YIELD properties($$).name AS Teammate, properties($$).age AS Age;
子句/符号 说明 YIELD
指定该查询需要返回的值或结果。 $$
表示边的终点。 \
表示换行继续输入。 -
从 VID 为
player101
的球员开始,沿着边follow
查找连接的球员,然后检索这些球员的球队。为了合并这两个查询请求,可以使用管道符或临时变量。-
使用管道符
GO FROM "player101" OVER follow YIELD dst(edge) AS id | \ GO FROM $-.id OVER serve YIELD properties($$).name AS Team, \ properties($^).name AS Player;
-
| 子句/符号 | 说明 |
| --------- | ---------------------------------------------------------- |
| `$^` | 表示边的起点。 |
| `|` | 组合多个查询的管道符,将前一个查询的结果集用于后一个查询。 |
| `$-` | 表示管道符前面的查询输出的结果集。 |
-
使用临时变量
当复合语句作为一个整体提交给服务器时,其中的临时变量会在语句结束时被释放。
$var = GO FROM "player101" OVER follow YIELD dst(edge) AS id; \ GO FROM $var.id OVER serve YIELD properties($$).name AS Team, \ properties($^).name AS Player;
6.3 FETCH语句示例
查询 VID 为player100
的球员的属性。
FETCH PROP ON player "player100" YIELD properties(vertex);
LOOKUP
和MATCH
的示例在下文的索引 部分查看。
7. 修改点和边
用户可以使用UPDATE
语句或UPSERT
语句修改现有数据。
UPSERT
是UPDATE
和INSERT
的结合体。当使用UPSERT
更新一个点或边,如果它不存在,数据库会自动插入一个新的点或边。
每个 partition 内部,UPSERT
操作是一个串行操作,所以执行速度比执行 INSERT
或 UPDATE
慢很多。其仅在多个 partition 之间有并发。
7.1 nGQL 语法
-
UPDATE
点UPDATE VERTEX <vid> SET <properties to be updated> [WHEN <condition>] [YIELD <columns>];
-
UPDATE
边UPDATE EDGE <source vid> -> <destination vid> [@rank] OF <edge_type> SET <properties to be updated> [WHEN <condition>] [YIELD <columns to be output>];
-
UPSERT
点或边UPSERT {VERTEX <vid> | EDGE <edge_type>} SET <update_columns> [WHEN <condition>] [YIELD <columns>];
7.2 示例
-
用
UPDATE
修改 VID 为player100
的球员的name
属性,然后用FETCH
语句检查结果。UPDATE VERTEX "player100" SET player.name = "Tim";
-
用
UPDATE
修改某条边的degree
属性,然后用FETCH
检查结果.UPDATE EDGE "player101" -> "player100" OF follow SET degree = 96;
-
用
INSERT
插入一个 VID 为player111
的点,然后用UPSERT
更新它。INSERT VERTEX player(name,age) VALUES "player111":("David West", 38);
8. 删除点和边
8.1 nGQL 语法
-
删除点
DELETE VERTEX <vid1>[, <vid2>...]
-
删除边
DELETE EDGE <edge_type> <src_vid> -> <dst_vid>[@<rank>] [, <src_vi
8.2 示例
-
删除点
DELETE VERTEX "player111", "team203";
-
删除边
DELETE EDGE follow "player101" -> "team204";
9. 索引
用户可以通过 CREATE INDEX 语句为 Tag 和 Edge type 增加索引。
9.1 nGQL语法
-
创建索引
CREATE {TAG | EDGE} INDEX [IF NOT EXISTS] <index_name> ON {<tag_name> | <edge_name>} ([<prop_name_list>]) [COMMENT = '<comment>'];
-
重建索引
REBUILD {TAG | EDGE} INDEX <index_name>;
9.2 基于索引的LOOKUP
和MATCH
示例
确保LOOKUP
或MATCH
有一个索引可用。如果没有,请先创建索引。
找到 Tag 为player
的点的信息,它的name
属性值为Tony Parker
。
// 为 name 属性创建索引 player_index_1。
nebula> CREATE TAG INDEX IF NOT EXISTS player_index_1 ON player(name(20));
// 重建索引确保能对已存在数据生效。
nebula> REBUILD TAG INDEX player_index_1
+------------+
| New Job Id |
+------------+
| 31 |
+------------+
// 使用 LOOKUP 语句检索点的属性。
nebula> LOOKUP ON player WHERE player.name == "Tony Parker" \
YIELD properties(vertex).name AS name, properties(vertex).age AS age;
+---------------+-----+
| name | age |
+---------------+-----+
| "Tony Parker" | 36 |
+---------------+-----+
// 使用 MATCH 语句检索点的属性。
nebula> MATCH (v:player{name:"Tony Parker"}) RETURN v;
+-----------------------------------------------------+
| v |
+-----------------------------------------------------+
| ("player101" :player{age: 36, name: "Tony Parker"}) |
+-----------------------------------------------------+
10. 完整示例basketballplayer
-
创建图空间basketballplayer
CREATE SPACE basketballplayer(partition_num=15, replica_factor=1, vid_type=fixed_string(30));
-
创建 Tag:
player
和team
,以及 Edge type:follow
和serve
。# 进入图空间 use basketballplayer;
CREATE TAG player(name string, age int); CREATE TAG team(name string); CREATE EDGE follow(degree int); CREATE EDGE serve(start_year int, end_year int);
-
插入球员和球队的点
INSERT VERTEX player(name, age) VALUES "player100":("Tim Duncan", 42);
INSERT VERTEX player(name, age) VALUES "player101":("Tony Parker", 36);
INSERT VERTEX player(name, age) VALUES "player102":("LaMarcus Aldridge", 33);
INSERT VERTEX team(name) VALUES "team203":("Trail Blazers"), "team204":("Spurs");
-
插入代表球员和球队之间关系的边
INSERT EDGE follow(degree) VALUES "player101" -> "player100":(95); INSERT EDGE follow(degree) VALUES "player101" -> "player102":(90); INSERT EDGE follow(degree) VALUES "player102" -> "player100":(75); INSERT EDGE serve(start_year, end_year) VALUES "player101" -> "team204":(1999, 2018),"player102" -> "team203":(2006, 2015);
-
从 VID 为
player101
的球员开始,沿着边follow
找到连接的球员的id信息GO FROM "player101" OVER follow YIELD id($$);
-
从 VID 为
player101
的球员开始,沿着边follow
查找年龄大于或等于 35 岁的球员,并返回他们的姓名和年龄,同时重命名对应的列。GO FROM "player101" OVER follow WHERE properties($$).age >= 35 \ YIELD properties($$).name AS Teammate, properties($$).age AS Age;
-
从 VID 为
player101
的球员开始,沿着边follow
查找连接的球员,然后检索这些球员的球队。为了合并这两个查询请求,可以使用管道符或临时变量。GO FROM "player101" OVER follow YIELD dst(edge) AS id | \ GO FROM $-.id OVER serve YIELD properties($$).name AS Team, \ properties($^).name AS Player;
-
用
UPDATE
修改 VID 为player100
的球员的name
属性UPDATE VERTEX "player100" SET player.name = "Tim";
-
用
UPDATE
修改某条边的degree
属性,然后用FETCH
检查结果.UPDATE EDGE "player101" -> "player100" OF follow SET degree = 96;
-
用
INSERT
插入一个 VID 为player111
的点,然后用UPSERT
更新它。INSERT VERTEX player(name,age) VALUES "player111":("David West", 38);
-
删除点
nebula> DELETE VERTEX "player111", "team203";
-
删除边
DELETE EDGE follow "player101" -> "team204";