由于Apache Calcite的功能复杂,很多专业词汇不好理解,因此将找到的一系列YYDS的博客,文章结束会附上转载地址,仅限大家互相学习,支持原创,多多交流。
https://www.querifylabs.com/blog/custom-traits-in-apache-calcite
https://www.querifylabs.com/author/vladimir-ozerov
注解
1: 为什么必须添加内置的ExpandConversionRule优化规则?
此规则将尝试将 AbstractConverter 扩展为一系列enforcer,以满足参考特征定义的所需特征。
从这个类的定义可以看出主要用来转化AbstractConverter类型的RelNode。
这里主要查看一下onMatch(实际转化方法)方法:
@Override public void onMatch(RelOptRuleCall call) {
// RelOptPlanner 优化器
final VolcanoPlanner planner = (VolcanoPlanner) call.getPlanner();
AbstractConverter converter = call.rel(0);
final RelNode child = converter.getInput();
RelNode converted =
planner.changeTraitsUsingConverters(
child,
converter.traitSet);
if (converted != null) {
call.transformTo(converted);
}
}
具体查看changeTraitsUsingConverters方法
@Nullable RelNode changeTraitsUsingConverters(
RelNode rel,
RelTraitSet toTraits) {
final RelTraitSet fromTraits = rel.getTraitSet();
assert fromTraits.size() >= toTraits.size();
final boolean allowInfiniteCostConverters =
CalciteSystemProperty.ALLOW_INFINITE_COST_CONVERTERS.value();
// Traits may build on top of another...for example a collation trait
// would typically come after a distribution trait since distribution
// destroys collation; so when doing the conversion below we use
// fromTraits as the trait of the just previously converted RelNode.
// Also, toTraits may have fewer traits than fromTraits, excess traits
// will be left as is. Finally, any null entries in toTraits are
// ignored.
RelNode converted = rel;
for (int i = 0; (converted != null) && (i < toTraits.size()); i++) {
RelTrait fromTrait = converted.getTraitSet().getTrait(i);
final RelTraitDef traitDef = fromTrait.getTraitDef();
RelTrait toTrait = toTraits.getTrait(i);
if (toTrait == null) {
continue;
}
assert traitDef == toTrait.getTraitDef();
// 判断trait是否需要进行转化
if (fromTrait.satisfies(toTrait)) {
// No need to convert; it's already correct.
continue;
}
// 这里调用了具体的RelTraitDef中定义的转化方法
RelNode convertedRel =
traitDef.convert(
this,
converted,
toTrait,
allowInfiniteCostConverters);
if (convertedRel != null) {
assert castNonNull(convertedRel.getTraitSet().getTrait(traitDef)).satisfies(toTrait);
register(convertedRel, converted);
}
converted = convertedRel;
}
// make sure final converted traitset subsumes what was required
if (converted != null) {
assert converted.getTraitSet().satisfies(toTraits);
}
return converted;
}