Calcite分析 -- ConverterRule
Calcite Version:1.26.0
EnumerableRule是一种ConverterRule,用于将逻辑算子转化为物理算子,并改变其convention。
EnumerableSortedAggregateRule
将LogicalAggregate转换成物理算子,
ConverterRule主要做两件事,
convert,真正的转换算子
transformTo,注册新生成的算子
convert
以EnumerableSortedAggregateRule为例,
2件事,
更改input的traits,典型的required;物理属性就是这样Topdown的往下传递的
生成新的物理算子,包含新生成的自身的selfTraits
更改input的traits,调用convert,这里的convert逻辑基本等同于changeTraits,参考Calcite分析 -- Convention&Converter
主要就是在input,增加subset,
transformTo
新生成的rel#26:EnumerableSortedAggregate.ENUMERABLE.[0],调用transformTo注册,
正常的注册过程,会新增一个subset,
rel#27:RelSubset#2.ENUMERABLE.[0]
但这里会触发,getOrCreateSubset的addConverters (触发条件,subset为新创建,并且convention不为none,即新创建的物理算子)
注意required是false
addConverters
RelSet是等价集合,所以每个SubSet应该都是等价的,Parent可以任意选取cost小的作为input。
Rule是等价变化,变换出来的RelNode和原先是等价的,但是有个问题是Rule本身是不会考虑物理属性的,Traits。
所以如果要做到物理属性的等价,就需要加入Conventer,来保证所有SubSet的物理属性的等价。
所以这里的逻辑是,如果subset中既有required,又有Delivered,那么需要将Delivered的物理属性转换成Required所需要的,这样parent才能用啊。
这里的case,是当前subset是非required,那么看看set的subset中是不是有required?
这里满足条件的只有,rel#24:RelSubset#2.ENUMERABLE.[0 DESC-nulls-last]
这里注意from和to的转换,一定是将非required的转换成required的
最终调用到增加converter,
两种选择,如果是非top down,那么创建AbstractConverter;否则调用Convention.enforce
AbstractConverter,只会修改Convention;Convention.enforce会对齐所有的traits
Convention.enforce
EnumerableConvention,会分别比较Convention和Collation,有不匹配的进行转换;
这里的case是Collation不同,所以创建一个EnumerableSort,
最后是注册这个新创建的enforcer,
注意enforcer是和to是等价的,因为他们的convention相同
结果,
继续注册,rel#26:EnumerableSortedAggregate.ENUMERABLE.[0]
在addRelToSubset中,完成addRels后,调用到ruleDriver.drive()
为新的rel#26:EnumerableSortedAggregate.ENUMERABLE.[0]增加Task,
这块逻辑,
- 非isLogical,是PhysicalNode或者convention不为null
- canPassThrough,等价于PhysicalNode,除非已经passThrough过了
PassThrough,
只是找出,subsets中是required,并且正在优化的,并且traitSet和当前node不符合的subset,对该subset再调用一遍OptimizeInput
getOptimizeInputTask,
和一般的常见逻辑比,这里由于rel和group的traitSet不匹配,所以先要convert生成新的匹配的node,然后再注册一下,
convert调用到passThrough,把物理属性传递到input,
用新生成的input,copy生成新的RelNode返回
返回新生成的RelNode是,
最后完成注册,并生成新的Task
总结一下,这个rule的过程,
EnumerableLimitRule
上面的例子是个ConvertRule的标准的例子,
而这个rule,重写了ConvertRule的onMatch,
但是做的工作仍然是两步,
convert,生成新的算子
transform,注册
- 但是这里没有显式的convert函数,都写在onMatch中了,transformTo以外的工作都是在convert
- 新增input,这里增加了一个input logicalSort算子;这也是他为什么不用标准的convertRule的原因
这里增加的logicalSort以原来的input为input,加了一层算子
这里replace不会改变原先traitSet的值,是会做clone的,所以RelNode的traits是不会改变的,Convention变化只是生成不同的Subset
changeTraits,
先ensureRegister,然后getOrCreateSubset,具体逻辑在Converter相关blog中分析过,
这里的sort是新的,所以会注册生成新的Relset,并生成带Enumerable convention的subset
transformTo,完成注册,
结果如图,
这个Rule的逻辑不复杂,但是新生成了一个RelSet,比较特殊