前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Hive优化器原理与源码解析系列--优化规则HiveFilterAggregateTransposeRule(十八)

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

作者头像
用户7600169
发布2022-04-25 15:39:41
6870
发布2022-04-25 15:39:41
举报
文章被收录于专栏:BigDataplus

目录

背景

优化规则HiveFilterAggregateTransposeRule

  • matches方法逻辑详解
  • onMatch方法逻辑详解
  • canPush判断谓词表达式是否能下推的方法详解

总结

背景

这篇文章来讲优化规则HiveFilterAggregateTransposeRule,主要功能是将Filter过滤器下推到Aggregate聚合操作之下。满足的前提条件,这些谓词表达式必须是确定性的。

谓词下推,优化的思路大致为尽量地将过滤条件下推到离数据源近的位置。提前过滤掉减少数据量,减少不必要的IO。记录数和IO同时都是HiveCostModel成本模型的关键构成指标。但前提必须满足等价变换的大前提,所谓等价变换,就是相同的输入,返回相同的确定的结果,优化就是减少或降低中间过程的计算成本。

Fileter过滤器操作和Aggregate聚合操作调换顺序,也是谓词下推一种的优化规则。

优化规则HiveFilterAggregateTransposeRule

1)matches方法逻辑详解

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

判断由RelOptCall调用的优化规则Rule是否与输入参数RelNode关系表达式匹配,即此优化规则Rule能否应用到一个RelNode关系表达式树上。

代码语言:javascript
复制
@Override
public boolean matches(RelOptRuleCall call) {
  final Filter filterRel = call.rel(0);
  RexNode condition = filterRel.getCondition();
  if (!HiveCalciteUtil.isDeterministic(condition)) {//判断是否为确定性方法,如果是确定性,并谓词表达式,否则跳出优化。
    return false;
  }
  return super.matches(call);
}

这里Hive实现了自己的判断,要求Filter操作的谓词条件,必须是确定性谓词表达式,否则退出优化。

表达式的确定性与非确定性区别:

一个表达式确定性与非确定性的区别是给定函数同一个确定值,是否永远返回同一个确定值。刚好相反的是非确定性函数,如随机函数Randow()每次返回的值都不确定。

关于onMatch方法优化规则HiveFilterAggregateTransposeRule没有实现,而是直接继承了Calcite实现优化规则父类FilterAggregateTransposeRule。

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优化规则的调用。

首先分别获取Filter和Aggregate对象,使用RelOptUtil.conjunctions把Filter对象谓词条件分解成有AND连接行表达式列表。获取Aggregate对象引用的字段列表,并判断与getGroupSet索引字段引用调整因子,以备下推Filter后AGG字段引用的调整使用。

代码语言:javascript
复制
final Filter filterRel = call.rel(0);
final Aggregate aggRel = call.rel(1);
final List<RexNode> conditions =
        RelOptUtil.conjunctions(filterRel.getCondition());//把谓词条件分解成有AND连接行表达式列表
final RexBuilder rexBuilder = filterRel.getCluster().getRexBuilder();
final List<RelDataTypeField> origFields =
        aggRel.getRowType().getFieldList();//获取Aggregate对象引用的字段列表
final int[] adjustments = new int[origFields.size()];
int j = 0;
for (int i : aggRel.getGroupSet()) {//遍历GroupBy字段索引,并向前退
    adjustments[j] = i - j;
    j++;
}

分离出哪些为可下推的谓词及其余不能下推的谓词列表。

首先conditions谓词列表,InputFinder访问遍历器生成表达式所用输入的位图,并使用bits返回描述表达式RelNode使用的输入的位集。canPush判断当前AGG对象中的,此谓词表达式元素是否可下推(canPush方法文章后面有讲解)。使用RelOptUtil.RexInputConverter遍历表达式树,根据调整因子adjustments转换RexInputRefs的索引并添加到可下推pushedConditions列表中,否则其余的谓词存放remainingConditions列表中。

代码语言:javascript
复制
final List<RexNode> pushedConditions = Lists.newArrayList();//存放可下推的表达式列表
final List<RexNode> remainingConditions = Lists.newArrayList();//存放其余不可下推的表达式列表
  //InputFinder:Visitor which builds a bitmap of the inputs used by an expression.
  //bits方法:Returns a bit set describing the inputs used by an expression.
for (RexNode condition : conditions) {//遍历上述分解的,AND连接RexNode列表
    ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(condition);
/**
 *  static class RelOptUtil.RexInputConverter
 * Walks an expression tree, converting the index of RexInputRefs based on some adjustment    factor.
 */
    if (canPush(aggRel, rCols)) {
        pushedConditions.add(
                condition.accept(
                        new RelOptUtil.RexInputConverter(rexBuilder, origFields,
                                aggRel.getInput(0).getRowType().getFieldList(),
                                adjustments)));
    } else {
        remainingConditions.add(condition);
    }
}

接下来,生成RelBuilder构建器对象,把谓词下推到AGG的子输入INPUT压入构建器,如果刚压入的带有下推谓词表达式的INPUT和原AGG的输入相同,则没有优化的必要,退出优化。复制AGG特征集合并使用已下推谓词的子输入RelNode生成新的RelNode对象,再补上剩余的没有下推的谓词条件,注册到RelSet等价关系表达式集合,以备优化器成本评估和选择,构建出最优的执行计划。

代码语言:javascript
复制
final RelBuilder builder = call.builder();
RelNode rel = builder.push(aggRel.getInput()).filter(pushedConditions).build();//把谓词下推到AGG的子输入INPUT
if (rel == aggRel.getInput(0)) {//如果rel和原AGG的输入相同,退出优化。
   return;
}
rel = aggRel.copy(aggRel.getTraitSet(), ImmutableList.of(rel));//复制新生成的已下推的RelNode
rel = builder.push(rel).filter(remainingConditions).build();//再补上剩余的没有下推的谓词条件
call.transformTo(rel);//注册到优化器

3)canPush判断谓词表达式是否能下推的方法

如果Filter所引用的字段,没在GroupBy中使用,则不能下推。还有如果使用GroupSet语句,并在谓词表达式中出现的字段引用,都在grouping sets中出现,也是可以下推的。

代码语言:javascript
复制
private boolean canPush(Aggregate aggregate, ImmutableBitSet rCols) {
    // If the filter references columns not in the group key, we cannot push
    final ImmutableBitSet groupKeys =
            ImmutableBitSet.range(0, aggregate.getGroupSet().cardinality());
    if (!groupKeys.contains(rCols)) {
        return false;
    }
    if (aggregate.indicator) {//标识是否AGG是否使用了GroupSets
      //在谓词表达式中出现的字段引用,都在grouping sets中出现,也是可以下推的。
        for (ImmutableBitSet groupingSet : aggregate.getGroupSets()) {
            if (!groupingSet.contains(rCols)) {
                return false;
            }
        }
    }
    return true;
}

总结

优化规则HiveFilterAggregateTransposeRule, Fileter过滤器操作和Aggregate聚合操作调换顺序,把谓词Filter过滤器下推到Aggregate聚合操作之下。提前过滤掉不必要的数据量,减少IO,达到优化效果。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BigDataplus 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档