一、图空间和 Schema
上篇文章简单介绍了 Nebula Graph ,以及 Nebula Graph 的安装,本篇文章给予上篇继续使用 nGQL 操作 Nebula Graph。
一个 Nebula Graph 实例由一个或多个图空间组成。每个图空间都是物理隔离的,用户可以在同一个实例中使用不同的图空间存储不同的数据集。
- 创建空间
create space bxc(partition_num=15, replica_factor=1, vid_type=fixed_string(30));
partition_num
:指定图空间的分片数量。建议设置为5倍的集群硬盘数量。例如集群中有3个硬盘,建议设置15个分片。默认值为100。
replica_factor
:指定每个分片的副本数量。建议在生产环境中设置为3,在测试环境中设置为1。由于需要基于多数表决,副本数量必须是奇数。默认值为1。
vid_type
:必选参数。指定点ID的数据类型。可选值为FIXED_STRING(<N>)
和INT64
。INT
等同于INT64
。FIXED_STRING(<N>)
表示数据类型为字符串,最大长度为N,超出长度会报错;INT64
表示数据类型为整数。
- 查看空间
show spaces;
- 使用空间
use bxc;
二、TAG 及 EDGE 操作
- 创建 TAG
create tag team(team_name string, persion_num int);
create tag game(name string);
# 创建包含默认值的Tag
create tag if not exists team1(name string, persion_num int default 20);
# 对字段设置TTL为2秒
create tag if not exists game(name string) ttl_duration = 2, ttl_col = "name ";
#没属性
create tag if not exists game2();
- 创建关系(和创建 TAG 相同)
create edge info(num int);
- 添加 vertex 定点
insert vertex team(team_name, persion_num) values "team_1":("team_1", 42);
insert vertex game(name) values "game_1":("game_1");
- 添加关系
如果已有Edge type、起点、终点、rank都相同的边,则覆盖原边。
insert edge info(num) values "team_1" -> "game_1":(95);
insert edge info(num) values "team_2" -> "game_1":(96);
insert edge info(num) values "team_2" -> "game_1"@1:(96);
三、FETCH 查询
FETCH可以获取指定点或边的属性值。
- 根据 vid 查询点数据
fetch prop on team "team_1" yield properties(vertex);
- 获取 点的属性:
fetch prop on team "team_1" yield id(vertex),properties(vertex).team_name,properties(vertex).persion_num;
- 获取多个点的属性值
fetch prop on team "team_1","team_2" yield properties(vertex).team_name,properties(vertex).persion_num;
- 在所有标签中获取点的属性值
fetch prop on * "team_1", "team_2" yield vertex as v;
- 获取边的属性值
fetch prop on info "team_1" -> "game_1" yield properties(edge);
- 获取边的属性值,根据 rank
fetch prop on info "team_2" -> "game_1"@1 yield properties(edge);
- 获取多条边的属性值
fetch prop on info "team_2" -> "game_1"@1,"team_2" -> "game_1" yield properties(edge);
- 复合语句
GO FROM "team_1" OVER info YIELD src(edge) AS s, dst(edge) AS d \
| FETCH PROP ON info $-.s -> $-.d YIELD properties(edge);
四、GO 查询
GO从给定起始点开始遍历图。GO语句采用的路径类型是walk,即遍历时点和边都可以重复。
- 遍历图,得到边的属性
go from "team_1" over info yield properties(edge);
- 指定步长,获取2跳的点。
go 2 steps from "team_1" over info yield dst(edge);
- 条件过滤
go 2 steps from "team_1" over info where properties(edge).name == "game_1_2" yield properties(edge);
- 返回 game_1 入方向的邻居点。
go from "game_1" over info reversely yield src(edge) as destination;
- 获取 1- 2 跳的数据
go 1 to 2 steps from "team_1" over info yield dst(edge) as destination;
- 使用符号
go from "team_1" over info yield id($$),properties($$);
go from "team_1" over follow where properties($$).age >= 40 yield properties($$);
go from "team_1" over info yield properties(edge),rank(edge)
$^
: 表示边的起点。$$
: 表示边的终点。$-
: 表示管道符前面的查询输出的结果集。
- 判断非空
go from "team_1" over info where properties($$).name is not empty yield properties($$);
五、MATCH 查询
MATCH语句提供基于模式(pattern)匹配的搜索功能。一个MATCH语句定义了一个搜索模式,用该模式匹配存储在 Nebula Graph 中的数据,然后用RETURN子句检索数据。
与GO或LOOKUP等其他查询语句相比,MATCH的语法更灵活。MATCH语句采用的路径类型是trail,即遍历时只有点可以重复,边不可以重复。
注意事项
除以下三种情况之外,请确保 MATCH 语句有至少一个索引可用。
- MATCH语句中WHERE子句使用 id() 函数指定了点的 VID,不需要创建索引即可执行。
- 当遍历所有点边时,例如MATCH (v) RETURN v LIMIT N,不需要创建索引,但必须使用LIMIT限制输出结果数量。
- 当遍历指定 Tag 的点或指定 Edge Type 的边时,例如MATCH (v:player) RETURN v LIMIT N,不需要创建索引,但必须使用LIMIT限制输出结果数量。
目前 match 语句无法查询到悬挂边。
- 为 team 创建索引
create tag index if not exists team_index on team (team_name (20));
- 重建索引使其生效。
rebuild tag index team_index ;
- 查看TAG 下的点
match (v:team) return v limit 3;
- 匹配多个 Tag 的点
match (v:team),(v2:game) return v,v2 limit 3;
- 匹配点的属性
match (v:team{team_name:"team_2"}) return v limit 3;
- 使用WHERE子句,筛选
match (v:team) where v.team.team_name == "team_2" return v ;
- 匹配点 ID
match (v.team) where id(v) == "team_2" return v;
- IN 匹配多个
match (v:team) where id(v) in ["team_1","team_2"] return v;
- 匹配连接的点
可以使用--
符号表示两个方向的边,并匹配这些边连接的点。在--
符号上增加<
或>
符号指定边的方向。
获取team 中 点 team_name 为 team_1 指向 game 中所有的点:
match (v:team{team_name:"team_1"})-->(v2:game) return v2;
- 对结果进行判断 CASE
match (v:team{team_name:"team_1"})-->(v2:game) return \
case \
when v2.game.name is null then "0" \
when v2.game.name == "game_1_1" then "1" \
else "2" \
end as name;
- 查询和自己同样关联team 的点:
match (v:team{team_name:"team_2"})-->(v2:game)<--(v3:team) return v3;
- 匹配路径
match p=(v:team{team_name:"team_1"})-->(v2:game) return p;
- 查看所有的边
match ()-[e:info]->() return e limit 10;
- 同时匹配点和边的属性
match (v:team{team_name:"team_1"})-[e:info{num:95}]->() return e;
- 匹配多个 Edge
match (v:team{team_name:"team_1"})-[e:info|:info1]->() return e;
- 匹配定长路径
使用:<edge_type>*<hop>
匹配定长路径。hop
必须是一个非负整数
match (v:team{team_name:"team_1"})-[e:info*2]->() return e;
如果hop为 0,模式会匹配路径上的起始点。
- 匹配变长路径
match (v:team{team_name:"team_1"})-[e:info*1..3]->() return e;
- 使用 distinct 去除重复的数据
match (v:team{team_name:"team_1"})-[e:info*1..3]->() return distinct e;
六、索引
索引会导致写性能大幅降低(降低 90%甚至更多)。请不要随意在生产环境中使用索引,除非很清楚使用索引对业务的影响。
- 创建索引
create tag index if not exists team_index on team(team_name(20));
create tag index if not exists game_index on game(name(20));
create edge index if not exists info_index on info();
- 重建索引确保能对已存在数据生效
rebuild tag index team_index
rebuild tag index game_index
rebuild edge index info_index;
- 根据索引查询数据
lookup on team1 where team1.name == "team_1" yield properties(vertex).name AS name, properties(vertex).age AS age;
- 根据索引查询数据 match
match (v:team1{name:"team_1"}) return v;
七、LOOKUP 根据索引遍历数据
LOOKUP根据索引遍历数据。可以使用LOOKUP实现如下功能:
- 根据WHERE子句搜索特定数据。
- 通过 Tag 列出点:检索指定 Tag 的所有点 ID。
- 通过 Edge type 列出边:检索指定 Edge type 的所有边的起始点、目的点和 rank。
- 统计包含指定 Tag 的点或属于指定 Edge type 的边的数量。
请确保LOOKUP语句有至少一个索引可用。如果已经存在相关的点、边或属性,必须在新创建索引后重建索引,才能使其生效。
- 检索点
lookup on team where team.team_name == "team_1" yield id(vertex),properties(vertex);
lookup on team where team.persion_num > 42 yield id(vertex),properties(vertex);
lookup on team where team.team_name in ["team_1","team_2"] and team.persion_num > 41 yield id(vertex),properties(vertex);
- 检索边
lookup on info where info.num > 50 yield id(edge),properties(edge);
lookup on info yield id(edge),properties(edge);