nGQL简介

nGQL(Nebula Graph Query Language)是Nebula Graph使用的的声明式图查询语言,支持灵活高效的图模式。

nGQL可以做什么
• 支持图遍历
• 支持模式匹配
• 支持聚合
• 支持修改图
• 支持访问控制
• 支持聚合查询
• 支持索引
• 支持大部分openCypher 9图查询语法

图模式

单点模式

点用一对括号来描述,通常包含一个名称。例如:(a)
示例为一个简单的模式,描述了单个点,并使用变量a命名该点。

多点关联模式

多个点通过边相连是常见的结构,模式用箭头来描述两个点之间的边。例如:(a)-[]->(b)
示例为一个简单的数据结构:两个点和一条连接两个点的边,两个点分别为a和b,边是有方向的,从a到b。

这种描述点和边的方式可以扩展到任意数量的点和边,例如:
(a)-[]->(b)<-[]-©
这样的一系列点和边称为路径(path)。
只有在涉及某个点时,才需要命名这个点。如果不涉及这个点,则可以省略名称,例如:(a)-[]->()<-[]-©

Tag模式

模式除了简单地描述图中的点之外,还可以描述点的Tag。例如:(a:User)-[]->(b)
模式也可以描述有多个Tag的点,例如:(a:User:Admin)-[]->(b)
openCypher兼容性
nGQL中的MATCH语句不支持用(a:User:Admin)匹配多个标签。如需匹配多标签可使用过滤条件,如WHERE “User” IN tags(n) AND “Admin” IN tags(n)。

属性模式

点和边是图的基本结构。nGQL在这两种结构上都可以增加属性,方便实现更丰富的模型。
在模式中,属性的表示方式为:用花括号括起一些键值对,用英文逗号分隔。例如一个点有两个属性:
(a {name: ‘Andres’, sport: ‘Brazilian Ju-Jitsu’})
在这个点上可以有一条边是:(a)-[{blocked: false}]->(b)

边模式

描述一条边最简单的方法是使用箭头连接两个点。
可以用以下方式描述边以及它的方向性。如果不关心边的方向,可以省略箭头,例如:(a)-[]-(b)
和点一样,边也可以命名。一对方括号用于分隔箭头,变量放在两者之间。例如:(a)-[r]->(b)
和点上的Tag一样,边也可以有类型。描述边的类型,例如:(a)-[r:REL_TYPE]->(b)
和点上的Tag不同,一条边只能有一种Edge type。但是如果我们想描述多个可选Edge type,可以用管道符号(|)将可选值分开,例如:(a)-[r:TYPE1|TYPE2]->(b)
和点一样,边的名称可以省略,例如:(a)-[:REL_TYPE]->(b)

变长模式

在图中指定边的长度来描述多条边(以及中间的点)组成的一条长路径,不需要使用多个点和边来描述。例如:(a)-[*2]->(b)
该模式描述了3点2边组成的图,它们都在一条路径上(长度为2),等价于: (a)-[]->()-[]->(b)

也可以指定长度范围,这样的边模式称为variable-length edges,例如:(a)-[*3…5]->(b)
3…5表示最小长度为3,最大长度为5。
该模式描述了4点3边、5点4边或6点5边组成的图。
也可以忽略最小长度,只指定最大长度,例如:(a)-[
…5]->(b)
ps.必须指定最大长度,不支持仅指定最小长度((a)-[3…]->(b))或都不指定((a)-[]->(b))。

路径变量

一系列连接的点和边称为路径。nGQL允许使用变量来命名路径,例如:p = (a)-[*3…5]->(b)
可以在MATCH语句中使用路径变量。

索引创建

在Tag player的name属性和Edge type follow上创建索引 :

CREATE TAG INDEX name ON player(name(20));
CREATE EDGE INDEX follow_index ON follow();

重建索引使其生效:

REBUILD TAG INDEX name;
REBUILD EDGE INDEX follow_index

检索操作

检索点或边的信息

使用RETURN {<vertex_name> | <edge_name>}检索点或边的所有信息:

MATCH (v:player{name:"Tim Duncan"}) \
RETURN v;
MATCH (v:player{name:"Tim Duncan"})-[e]->(v2) \
RETURN e;

检索点ID

使用id()函数检索点ID:

MATCH (v:player{name:"Tim Duncan"}) \
RETURN id(v);

检索点Tag

使用labels()函数检索点上的Tag列表:

MATCH (v:player{name:"Tim Duncan"}) \
RETURN labels(v);

使用labels(v)[0]检索第一个元素:

MATCH (v:player{name:"Tim Duncan"}) \
RETURN labels(v)[0];

检索点或边的单个属性

使用RETURN {<vertex_name> | <edge_name>}.检索单个属性:

MATCH (v:player{name:"Tim Duncan"}) \
RETURN v.age;

使用AS设置属性的别名:

MATCH (v:player{name:"Tim Duncan"}) \
RETURN v.age AS Age;

检索点或边的所有属性

使用properties()函数检索点或边的所有属性:

MATCH p=(v:player{name:"Tim Duncan"})-[]->(v2) \
RETURN properties(v2);

检索Edge type

使用type()函数检索匹配的Edge type:

MATCH p=(v:player{name:"Tim Duncan"})-[e]->() \
RETURN DISTINCT type(e);

检索路径

使用RETURN <path_name>检索匹配路径的所有信息:

MATCH p=(v:player{name:"Tim Duncan"})-[*3]->() \
RETURN p;

使用nodes()函数检索路径中的所有点:

MATCH p=(v:player{name:"Tim Duncan"})-[]->(v2) \
RETURN nodes(p);

使用relationships()函数检索路径中的所有边:

MATCH p=(v:player{name:"Tim Duncan"})-[]->(v2) \
RETURN relationships(p);

使用length()函数检索路径的长度:

MATCH p=(v:player{name:"Tim Duncan"})-[*..2]->(v2) \
RETURN p AS Paths, length(p) AS Length;

引用符

nGQL提供引用符来表示WHERE和YIELD子句中的属性,或者复合查询中管道符之前的语句数据结果。

引用符列表:

• $^: 引用起始点。
• $$: 引用目的点。
• $-: 引用复合查询中管道符之前的语句输出结果。

引用符示例:

i) 返回起始点和目的点的年龄:
GO FROM "player100" OVER follow YIELD $^.player.age AS SrcAge, $$.player.age AS DestAge;
ii) 返回player100 follow的player的名称和团队:
GO FROM "player100" OVER follow \
YIELD follow._dst AS id | \
GO FROM $-.id OVER serve \
YIELD $^.player.name AS Player, $$.team.name AS Team;

MATCH

MATCH语句提供基于模式(pattern)匹配的搜索功能。MATCH语句在模式中搜索,寻找匹配的边或点。
一个MATCH语句定义了一个搜索模式,用该模式匹配存储在Nebula Graph中的数据,然后用RETURN子句检索数据。
MATCH语句使用原生索引查找起始点或边,起始点或边可以在模式的任何位置。即一个有效的MATCH语句,必须有一个属性、Tag或Edge type已经创建索引,或者在WHERE子句中用id()函数指定了特定点的VID。

语法:MATCH [] RETURN

匹配点

在一对括号中使用自定义变量来表示模式中的点。例如:(v)

匹配Tag

在点的右侧用:<tag_name>表示模式中的Tag:MATCH (v:player) RETURN v;

匹配点的属性

方法一.在Tag的右侧用{<prop_name>: <prop_value>}表示模式中点的属性:

MATCH (v:player{name:"Tim Duncan"}) RETURN v;

方法二.使用WHERE子句实现相同的操作:

MATCH (v:player) WHERE v.name == "Tim Duncan" RETURN v;

匹配点ID

使用点ID去匹配点。id()函数可以检索点的ID:

MATCH (v) WHERE id(v) == 'player101' RETURN v;

要匹配多个点的ID,可以用WHERE id(v) IN [vid_list]:

MATCH (v:player { name: 'Tim Duncan' })--(v2) \
WHERE id(v2) IN ["player101", "player102"] RETURN v2;

匹配连接的点

使用–/-->/<–符号表示有边连接,并匹配这些边连接的点:

MATCH (v:player{name:"Tim Duncan"})--(v2) \
RETURN v2.name AS Name;
MATCH (v:player{name:"Tim Duncan"})-->(v2) \
RETURN v2.name AS Name;

扩展到更多的点和边:

MATCH (v:player{name:"Tim Duncan"})-->(v2)<--(v3) \
RETURN v3.name AS Name;

匹配路径

连接起来的点和边构成了路径,可以使用自定义变量命名路径:

MATCH p=(v:player{name:"Tim Duncan"})-->(v2) \
RETURN p;

匹配边

除了用–、-->、<–表示未命名的边之外,还可以在方括号中使用自定义变量命名边。例如-[e]-:

MATCH (v:player{name:"Tim Duncan"})-[e]-(v2) \
RETURN e;

可以扩展模式,匹配路径中的多条边:

MATCH (v:player{name:"Tim Duncan"})-[]->(v2)<-[e:serve]-(v3) \
RETURN v2, v3;

匹配Edge type

和点一样,可以用:<edge_type>表示模式中的Edge type,例如-[e:follow]-:

MATCH ()-[e:follow]-() \
RETURN e;

使用|可以匹配多个Edge type:

MATCH (v:player{name:"Tim Duncan"})-[e:follow|:serve]->(v2) \
RETURN e;

匹配边的属性

用{<prop_name>: <prop_value>}表示模式中Edge type的属性,例如[e:follow{likeness:95}]

MATCH (v:player{name:"Tim Duncan"})-[e:follow{degree:95}]->(v2) \
RETURN e;

匹配定长路径

可以在模式中使用:<edge_type>*匹配定长路径。hop必须是一个非负整数:

MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*2]->(v2) \
RETURN DISTINCT v2 AS Friends;

匹配变长路径

可以在模式中使用:<edge_type>*…匹配变长路径:

MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*1..3]->(v2) \
RETURN v2 AS Friends;

可以使用DISTINCT关键字聚合重复结果:

MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*1..3]->(v2:player) \
RETURN DISTINCT v2 AS Friends, count(v2);

可以在变长或定长模式中指定多个Edge type。hop、minHop和maxHop对所有Edge type都生效:

MATCH p=(v:player{name:"Tim Duncan"})-[e:follow|serve*2]->(v2) \
RETURN DISTINCT v2;

LOOKUP

LOOKUP根据索引遍历数据。可以使用LOOKUP实现如下功能:

• 根据WHERE子句搜索特定数据。
• 通过Tag列出点:检索指定Tag的所有点ID。
• 通过Edge type列出边:检索指定Edge type的所有边的起始点、目的点和rank。
• 统计包含指定Tag的点或属于指定Edge type的边的数量。

语法:

LOOKUP ON {<vertex_tag> | <edge_type>} 
[WHERE <expression> [AND <expression> ...]] 
[YIELD <return_list>];

检索点

返回Tag为player且name为Tony Parker的点:

CREATE TAG INDEX index_player ON player(name(30), age);
REBUILD TAG INDEX index_player;
LOOKUP ON player \
WHERE player.name == "Tony Parker" \
YIELD player.name, player.age;

检索边

返回Edge type为follow且degree为90的边:

CREATE EDGE INDEX index_follow ON follow(degree);
REBUILD EDGE INDEX index_follow;
LOOKUP ON follow \
WHERE follow.degree == 90 \
YIELD follow.degree;

通过Tag列出所有的对应的点/通过Edge type列出边

如果需要通过Tag列出所有的点,或通过Edge type列出边,则Tag、Edge type或属性上必须有至少一个索引。例如一个Tag player有属性name和age,为了遍历所有包含Tag player的点ID,Tag player、属性name或属性age中必须有一个已经创建索引。

查找所有Tag为player的点 VID:

CREATE TAG player(name string,age int);
CREATE TAG INDEX player_index on player();
REBUILD TAG INDEX player_index;
INSERT VERTEX player(name,age) \
VALUES "player100":("Tim Duncan", 42), "player101":("Tony Parker", 36);
LOOKUP ON player;

查找Edge type为like的所有边的信息:

CREATE EDGE like(likeness int);
CREATE EDGE INDEX like_index on like();
REBUILD EDGE INDEX like_index;
INSERT EDGE like(likeness) \
VALUES "player100"->"player101":(95);
LOOKUP ON like;

统计点或边

统计Tag为player的点和Edge type为like的边:

LOOKUP ON player |\
YIELD COUNT(*) AS Player_Number;
LOOKUP ON like | \
YIELD COUNT(*) AS Like_Number;

GO

GO用指定的过滤条件遍历图,并返回结果。

语法

GO [[<M> TO] <N> STEPS ] FROM <vertex_list>
OVER <edge_type_list> [{REVERSELY | BIDIRECT}]
[ WHERE <conditions> ]
[YIELD [DISTINCT] <return_list>]
[| ORDER BY <expression> [{ASC | DESC}]]
[| LIMIT [<offset_value>,] <number_rows>]

GO [[<M> TO] <N> STEPS ] FROM <vertex_list>
OVER <edge_type_list> [{REVERSELY | BIDIRECT}]
[ WHERE <conditions> ]
[| GROUP BY {col_name | expr | position} YIELD <col_name>]
• <N> STEPS:指定跳数。如果没有指定跳数,默认值N为1。如果N为0,Nebula Graph不会检索任何边。
• M TO N STEPS:遍历M~N跳的边。如果M为0,输出结果和M为1相同,即GO 0 TO 2和GO 1 TO 2是相同的。
• <vertex_list>:用逗号分隔的点ID列表,或特殊的引用符$-.id。
• <edge_type_list>:遍历的Edge type列表。
• REVERSELY | BIDIRECT:默认情况下检索的是<vertex_list>的出边(正向),REVERSELY表示反向,即检索入边;BIDIRECT 为双向,即检索正向和反向,通过返回 <edge_type>._type 字段判断方向,其正数为正向,负数为反向。
• WHERE <conditions>:指定遍历的过滤条件。
• YIELD [DISTINCT] <return_list>:指定输出结果。如果没有指定,默认返回目的点ID。
• ORDER BY:指定输出结果的排序规则。
• LIMIT:限制输出结果的行数。
• GROUP BY:根据指定属性的值将输出分组。

示例:

1)返回player102所属队伍:

GO FROM "player102" OVER serve;

2)返回距离player102两跳的朋友:

GO 2 STEPS FROM "player102" OVER follow;

3)添加过滤条件:

GO FROM "player100", "player102" OVER serve \
WHERE serve.start_year > 1995 \
YIELD DISTINCT $$.team.name AS team_name, serve.start_year AS start_year, $^.player.name AS player_name;

4)返回player100的入边:

方法一:
GO FROM "player100" OVER follow REVERSELY \
YIELD follow._dst AS destination;
方法二:
MATCH (v)<-[e:follow]- (v2) WHERE id(v) == 'player100' \
RETURN id(v2) AS destination;

5)查询player100的朋友和朋友所属队伍:

方法一:
GO FROM "player100" OVER follow REVERSELY \
YIELD follow._dst AS id | \
GO FROM $-.id OVER serve \
WHERE $^.player.age > 20 \
YIELD $^.player.name AS FriendOf, $$.team.name AS Team;
方法二:
MATCH (v)<-[e:follow]- (v2)-[e2:serve]->(v3)  \
WHERE id(v) == 'player100' \
RETURN v2.name AS FriendOf, v3.name AS Team;

6)返回player102的出边和入边:

方法一:
GO FROM "player102" OVER follow BIDIRECT \
YIELD follow._dst AS both;
方法二:
MATCH (v) -[e:follow]-(v2) \
WHERE id(v)== "player102" \
RETURN id(v2) AS both;

7)查询player100 1~2跳内的朋友:

方法一:
GO 1 TO 2 STEPS FROM "player100" OVER follow \
YIELD follow._dst AS destination;
方法二:
MATCH (v) -[e:follow*1..2]->(v2) \
WHERE id(v) == "player100" \
RETURN id(v2) AS destination;

8)根据年龄分组:

GO 2 STEPS FROM "player100" OVER follow \
YIELD follow._src AS src, follow._dst AS dst, $$.player.age AS age \
| GROUP BY $-.dst \
YIELD $-.dst AS dst, collect_set($-.src) AS src, collect($-.age) AS age

9)分组并限制输出结果的行数:

$a = GO FROM "player100" OVER follow YIELD follow._src AS src, follow._dst AS dst; \
GO 2 STEPS FROM $a.dst OVER follow \
YIELD $a.src AS src, $a.dst, follow._src, follow._dst \
| ORDER BY $-.src | OFFSET 1 LIMIT 2;

10)在多个边上通过IS NOT EMPTY进行判断:

GO FROM "player100" OVER * WHERE $$.player.name IS NOT EMPTY YIELD follow._dst;

FETCH

FETCH可以获取指定点或边的属性值。

语法(点)

FETCH PROP ON {<tag_name>[, tag_name ...] | *} 
<vid> [, vid ...] 
[YIELD <output>]

示例
1)基于Tag获取点的属性值:

FETCH PROP ON player "player100";

2)获取点的指定属性值:

FETCH PROP ON player "player100" \
YIELD player.name;

3)获取多个点的属性值:

FETCH PROP ON player "player101", "player102", "player103";

4)基于多个Tag获取点的属性值:

FETCH PROP ON player, t1 "player100";

5)在所有标签中获取点的属性值:

FETCH PROP ON * "player100", "player106", "team200";

语法(边)

FETCH PROP ON <edge_type> <src_vid> -> <dst_vid>[@<rank>] [, <src_vid> -> <dst_vid> ...]
[YIELD <output>]

示例
1)获取边的所有属性:

FETCH PROP ON serve "player100" -> "team204";

2)获取边的指定属性:

FETCH PROP ON serve "player100" -> "team204"    \
YIELD serve.start_year;

3)获取多条边的属性值:

FETCH PROP ON serve "player100" -> "team204", "player133" -> "team202";

4)基于rank获取属性值:
i) 插入不同属性值、不同rank的边

insert edge serve(start_year,end_year) \
values "player100"->"team204"@1:(1998, 2017);
insert edge serve(start_year,end_year) \
values "player100"->"team204"@2:(1990, 2018);

ii) 默认返回rank为0的边

FETCH PROP ON serve "player100" -> "team204";
iii) 要获取rank不为0的边,需要在FETCH语句中指定rank
FETCH PROP ON serve "player100" -> "team204"@1;

5)复合语句中使用FETCH:
i) 返回从点player101开始的follow边的degree值

GO FROM "player101" OVER follow \
YIELD follow._src AS s, follow._dst AS d \
| FETCH PROP ON follow $-.s -> $-.d \
YIELD follow.degree;
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐