Hive优化器原理与源码解析系列--优化规则HiveFilterSetOpTransposeRule(二十)

2022-04-25 15:41:08 浏览数 (1)

目录

背景

优化规则HiveFilterSetOpTransposeRule

  • matches方法逻辑详解
  • onMatch方法逻辑详解

总结

背景

这篇文章来讲优化规则HiveFilterSetOpTransposeRule,主要功能是将Filter过滤器下推到SetOp集合操作之下,提前过滤掉不必要的数据,减少中间结果进行优化。

SetOp集合操作,是Calcite框架中的关系集运算符(如UNION、MINUS(aka EXCEPT)和INTERSECT)的抽象基。为了方便讲解,可暂且理解为UNION、MINUS、EXCEPT和INTERSECT的统称。简单来讲,将SetOp集合操作之上的Filter过滤条件下推到UNION、MINUS、EXCEPT和INTERSECT操作的各个分支上。此优化规则转换如下:

强调的是,优化器规则所有的RelNode变换,必须是在等价变换的前提下。

优化规则HiveFilterSetOpTransposeRule

1)matches方法逻辑详解

matches方法返回此规则Rule是否可能与给定的操作数operands匹配,但是此方法的任何实现都可以给出误报,也就是说虽然规则与操作数匹配,但随后具OnMatch(ReloptRuleCall)而不生成任何后续任务。

判断由RelOptCall调用的优化规则Rule是否与输入参数RelNode关系表达式匹配,即此优化规则Rule能否应用到一个RelNode关系表达式树上。但此matches方法是继承自父类方法,默认返回true。

代码语言:javascript复制
public boolean matches(RelOptRuleCall call) {  
  return true;
}

2)onMatch方法逻辑详解

接收有关一条规则匹配的通知。同时此方法被调用,call.rels保存了与规则Rule的操作数Operands匹配上的关系表达式RelNode集合;call.rels[0]是根表达式。通常一条规则Rule会检查这些节点是否有效匹配,创建一个新表达式RelNode(等价的)然后调用RelOptRuleCall.transformTo(org.apache.calcite.rel.RelNode, java.util.Map<org.apache.calcite.rel.RelNode, org.apache.calcite.rel.RelNode>)注册表达式。而RelOptRuleCall用一系列RelNode关系表达式集合作为参数,对RelOptRule优化规则的调用。

首先,call.rel(0)获取根Root RelNode为Filter操作filterRel变量,并返回RexNode行表达式,谓词判断条件condition。call.rel(1)得SetOp集合操作对象setOp,为以下谓词下推做好变量对象准备。

代码语言:javascript复制
// implement RelOptRule
public void onMatch(RelOptRuleCall call) {
    Filter filterRel = call.rel(0);//根Root
    SetOp setOp = call.rel(1); //SetOp集合操作
    RexNode condition = filterRel.getCondition();//或Filter过滤器谓词判断条件

为每个SetOp集合操作的子输入RelNode上创建过滤器,并修改过滤器引用每个SetOp集合操作的子输入RelNode的条件。RelDataTypeField列表这里因为Union、Intersect 和Minus 等集合运算符号都要求分支的投影字段有相同字段和一致的数据类型,所以这里可以从SetOp对象取List<RelDataTypeField>字段和类型对象列表,作为源字段List<RelDataTypeField>,遍历输入各个分支RelNode的List<RelDataTypeField>作为目标字段的List<RelDataTypeField>。

遍历SetOp集合操作的子输入RelNode,并使用RelOptUtil.RexInputConverter遍历表达式树为Filter过滤器的行表达式,根据某些调整因子adjustments转换RexInputRefs的索引,根据源和目标字段列表集合和调整因子,调整在SetOp对象的子分支上创建新判断条件表达式。

最后,把新下推的谓词条件,放置在SetOp每个分支后,并加到newSetOpInputs分支RelNode列表。

代码语言:javascript复制
RexBuilder rexBuilder = filterRel.getCluster().getRexBuilder();//Filter过滤器行表达式构建器
final RelBuilder relBuilder = call.builder();
List<RelDataTypeField> origFields =
        setOp.getRowType().getFieldList();//SetOp集合操作的字段列表可以总的源字段RelDataTypeField列表
int[] adjustments = new int[origFields.size()];//调整因子,默认为0
final List<RelNode> newSetOpInputs = new ArrayList<>();
for (RelNode input : setOp.getInputs()) {//遍历SetOp的子输入,如Union的子分支,并
    RexNode newCondition =
            condition.accept(
                    new RelOptUtil.RexInputConverter(//转换遍历器
                            rexBuilder,
                            origFields,//源字段列表
                            input.getRowType().getFieldList(),//目标字段列表
                            adjustments));//床架调整后的新condition
    newSetOpInputs.add(relBuilder.push(input).filter(newCondition).build());//把判断条件放置在分支RelNode上
}

使用谓词下推到分支列表newSetOpInputs,创建一个新的SetOp集合操作。并注册RelSet等价集合。

代码语言:javascript复制
SetOp newSetOp =
            setOp.copy(setOp.getTraitSet(), newSetOpInputs);//创建新SetOp操作
    call.transformTo(newSetOp);//注册到RelSet
}

总结

优化规则HiveFilterSetOpTransposeRule简单来讲,就是把过滤条件下推到SetOp集合操作(Union、InterSect、Minus等等集合运算符的总称)的输入子分支上,提前过滤数据,减少中间结果以优化。此优化规则相对简单,易于理解,这里不再赘述。

0 人点赞