Graph 服务
查询请求发送到 Graph 服务后,会由如下模块依次处理:
Parser:词法语法解析模块。
Validator:语义校验模块。
Planner:执行计划与优化器模块。
Executor:执行引擎模块。
Parser
Parser 模块收到请求后,通过 Flex(词法分析工具)和 Bison(语法分析工具)生成的词法语法解析器,将语句转换为抽象语法树(AST),在语法解析阶段会拦截不符合语法规则的语句。
例如语句转换的 AST 如下。
Validator 模块对生成的 AST 进行语义校验,主要包括:
校验上下文引用信息
例如语句
$var = GO FROM "Tim" OVER like YIELD dst(edge) AS ID; GO FROM $var.ID OVER serve YIELD dst(edge)
,Validator 模块首先会检查变量var
是否定义,其次再检查属性ID
是否属于变量var
。校验类型推断
推断表达式的结果类型,并根据子句校验类型是否正确。
例如
WHERE
子句要求结果是bool
、null
或者empty
。校验
*
代表的信息查询语句中包含
*
时,校验子句时需要将*
涉及的Schema都进行校验。例如语句
GO FROM "Tim" OVER * YIELD dst(edge), properties(edge).likeness, dst(edge)
,校验OVER
子句时需要校验所有的 Edge type,如果 Edge type 包含 和serve
,该语句会展开为GO FROM "Tim" OVER like,serve YIELD dst(edge), properties(edge).likeness, dst(edge)
。校验输入输出
校验管道符(|)前后的一致性。
例如语句
GO FROM "Tim" OVER like YIELD dst(edge) AS ID | GO FROM $-.ID OVER serve YIELD dst(edge)
,Validator 模块会校验$-.ID
在管道符左侧是否已经定义。
校验完成后,Validator 模块还会生成一个默认可执行,但是未进行优化的执行计划,存储在目录 src/planner
内。
Planner
如果配置文件 nebula-graphd.conf
中 enable_optimizer
设置为 false
,Planner 模块不会优化 Validator 模块生成的执行计划,而是直接交给 Executor 模块执行。
如果配置文件 nebula-graphd.conf
中enable_optimizer
设置为 true
,Planner 模块会对 Validator 模块生成的执行计划进行优化。如下图所示。
-
如上图右侧未优化的执行计划,每个节点依赖另一个节点,例如根节点
Project
依赖Filter
、Filter
依赖GetNeighbor
,最终找到叶子节点Start
,才能开始执行(并非真正执行)。在这个过程中,每个节点会有对应的输入变量和输出变量,这些变量存储在一个哈希表中。由于执行计划不是真正执行,所以哈希表中每个key的value值都为空(除了 节点,起始数据会存储在该节点的输入变量中)。哈希表定义在仓库
nebula-graph
内的src/context/ExecutionContext.cpp
中。例如哈希表的名称为
ResultMap
,在建立Filter
这个节点时,定义该节点从ResultMap["GN1"]
中读取数据,然后将结果存储在ResultMap["Filter2"]
中,依次类推,将每个节点的输入输出都确定好。
Note
Nebula Graph 2.6.1 默认没有打开优化。
Executor 模块包含调度器(Scheduler)和执行器(Executor),通过调度器调度执行计划,让执行器根据执行计划生成对应的执行算子,从叶子节点开始执行,直到根节点结束。如下图所示。
每一个执行计划节点都一一对应一个执行算子,节点的输入输出在优化执行计划时已经确定,每个算子只需要拿到输入变量中的值进行计算,最后将计算结果放入对应的输出变量中即可,所以只需要从节点 Start
一步步执行,最后一个算子的输出变量会作为最终结果返回给客户端。
代码结构
Nebula Graph 的代码层次结构如下:
用户也可以通过视频全方位了解 Nebula Graph 的查询引擎。
- (33分30秒)