From parser to executor, modifing nGQL statement¶
约 670 个字 107 行代码 预计阅读时间 5 分钟
这里以为Create TAG
语句增加 VECTOR 属性为例进行叙述,既是给读者一份更改源码的参考,也是对自己更改代码逻辑的梳理。
我们最后期望的语句形式如下:
- 有 Default value
- 有 TTL 选项
0.0 Context & Plan¶
- Query、Session、Storage 等打包成 Request Context,随后将 Request Context 打包成 Query Context
- CreateSchemaContext CreateTagValidator 自己拥有的上下文,用于将 Sentence 转变为 Plan,里面是需要传递给 CreateTagNode 的参数。
- 执行计划中的每个 Node 实际上需要的是 QueryContext,以及其他 Validator 自己生成的 Schema 或 Name 等变量
CreateTag 需要
QueryContext* qctx
,std::string name
,meta::cpp2::Schema schema
, 只有 qctx 是整个 nGQL 都需要维护的 - 在 Scheduler 中将 Logical Plan 变成 Physical Plan,这里是 CreateTag 变成 CreateTagExecutor,这里调用了 Meta 服务中的 createTagSchema 方法
0.1 Processing¶
- Parser: From string to sentences
- 最外层是 CreateTagSentence,里面每个属性是 ColumnSpecification - Validater:
- 验证 column,将验证后的 column 加入 schema,并将这个新构建的 schema 传入 CreateTagContext
- CreateTagPlanner 通过 transform 生成 Logical Plan - Optimizer: 这里暂时没有优化,先跳过
- Executor: 在 Scheduler 中将生成的 Logical Plan 变成 Physical Plan,在 graphd 的 executor 执行过程中会向 metad 请求服务
1. Parser modifing¶
我们需要对 scanner.lex 和 parser.yy 进行修改,这里我们可能需要对 bison 中的语法进行检查,出现复杂问题我们可能还要进行 debug,我的另一篇文章中有详细叙述该过程,这里不再赘述。
scanner.lex 修改¶
主要就是增加 VECTOR 关键字的解析
parser.yy 修改¶
这里我们需要对 VECTOR 的语法进行解析,首先一个问题就是,对[0.01, 0.02, 0.03]
的解析会有两种解析方式成立:
- 一种是解析成 List
- 一种是我们希望的解析成 Vector
C++
Example: L_BRACKET DOUBLE • R_BRACKET
First reduce derivation
container_expression
↳ list_expression
↳ L_BRACKET opt_expression_list R_BRACKET
↳ expression_list
↳ expression_internal
↳ constant_expression
↳ DOUBLE •
Second reduce derivation
container_expression
↳ vector_expression
↳ L_BRACKET vector_item_list R_BRACKET
↳ vector_element_expression
↳ DOUBLE •
暂时我们的处理是解析成 Vector 的规则放在首位,因为 bison 是默认从头到尾匹配规则。
我们同样需要处理 Column Spec 支持 VECTOR 类型,而 VECTOR 类型需要有 dimension 参数,我们在ColumnSpecification
中增加一个成员变量
C++
column_spec
: name_label type_spec {
$$ = new ColumnSpecification($1, $2->type, new ColumnProperties(), $2->type_length_ref().value_or(0), $2->geo_shape_ref().value_or(meta::cpp2::GeoShape::ANY), $2->dimension_ref().value_or(0));
delete $2;
}
| name_label type_spec column_properties {
$$ = new ColumnSpecification($1, $2->type, $3, $2->type_length_ref().value_or(0), $2->geo_shape_ref().value_or(meta::cpp2::GeoShape::ANY), $2->dimension_ref().value_or(0));
delete $2;
}
Transfer Statement¶
- 需要修改 ColumnSpecification 支持 VECTOR 类型,由于 VECTOR 类型中有 dimension 参数,我们需要增加 dimension 参数
C++ColumnSpecification(std::string *name, nebula::cpp2::PropertyType type, ColumnProperties *properties = nullptr, int16_t typeLen = 0, meta::cpp2::GeoShape geoShape = meta::cpp2::GeoShape::ANY, int16_t dimension = 0) : name_(name), type_(type), properties_(DCHECK_NOTNULL(properties)), typeLen_(typeLen), geoShape_(geoShape), dimension_(dimension) {}
- 需要修改
ColumnTypeDef
支持 VECTOR 类型,由于 VECTOR 类型中有 dimension 参数,我们需要在 meta.thrift 中添加该参数
C++
struct ColumnTypeDef {
1: required common.PropertyType type,
// type_length is valid for fixed_string type
2: optional i16 type_length = 0,
// geo_shape is valid for geography type
3: optional GeoShape geo_shape,
// dim is valid for vector type
4: optional i16 dimension,
}
2. Validater Modifing¶
修改 validate columns 来实现对 VECTOR 类型 column 的验证
C++
static Status validateColumns(const std::vector<ColumnSpecification *> &columnSpecs,
meta::cpp2::Schema &schema,
bool isAlter = false) {
for (auto &spec : columnSpecs) {
meta::cpp2::ColumnDef column;
auto type = spec->type();
column.name_ref() = *spec->name();
column.type.type_ref() = type;
if (nebula::cpp2::PropertyType::FIXED_STRING == type) {
column.type.type_length_ref() = spec->typeLen();
} else if (nebula::cpp2::PropertyType::GEOGRAPHY == type) {
column.type.geo_shape_ref() = spec->geoShape();
} else if (nebula::cpp2::PropertyType::VECTOR == type) {
column.type.dimension_ref() = spec->dimension();
}
// ...
schema.columns_ref().value().emplace_back(std::move(column));
}
return Status::OK();
}
修改 Schema 来实现对 VECTOR 类型的处理
- 首先是增加 SchemaField 对 VECTOR 的处理
C++SchemaField(const std::string& name, nebula::cpp2::PropertyType type, bool nullable, bool hasDefault, std::string defaultValue, size_t size, size_t offset, size_t nullFlagPos, cpp2::GeoShape geoShape, int32_t dimension) : name_(name), type_(type), nullable_(nullable), hasDefault_(hasDefault), defaultValue_(defaultValue), size_(size), offset_(offset), nullFlagPos_(nullFlagPos), geoShape_(geoShape), dimension_(dimension) {}
- 增加 NebulaSchemaProvider 添加 VECTOR 属性 column 的方法