Hive 如何计算Map,Reduce的个数

hql语句转mapreduce整个编译过程分为六个阶段:(参考美团技术团队)

1.      Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树ASTTree

2.      遍历AST Tree,抽象出查询的基本组成单元QueryBlock

3.      遍历QueryBlock,翻译为执行操作树OperatorTree

4.      逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量

5.      遍历OperatorTree,翻译为MapReduce任务

6.      物理层优化器进行MapReduce任务的变换,生成最终的执行计划

Sql转AST Tree

Hive使用Antlr实现SQL的词法和语法解析。Antlr是一种语言识别的工具,可以用来构造领域语言。

Antlr完成了词法分析、语法分析、语义分析、中间代码生成的过程。

AST Tree仍然非常复杂,不够结构化,不方便直接翻译为MapReduce程序,AST Tree转化为QueryBlock就是将SQL进一部抽象和结构化。

QueryBlock

QueryBlock是一条SQL最基本的组成单元,包括三个部分:输入源,计算过程,输出。简单来讲一个QueryBlock就是一个子查询。

AST Tree生成QueryBlock

AST Tree生成QueryBlock的过程是一个递归的过程,先序遍历AST Tree,遇到不同的Token节点,保存到相应的属性中,主要包含以下几个过程

TOK_QUERY => 创建QB对象,循环递归子节点

TOK_FROM => 将表名语法部分保存到QB对象的aliasToTabs等属性中

TOK_INSERT => 循环递归子节点

TOK_DESTINATION => 将输出目标的语法部分保存在QBParseInfo对象的nameToDest属性中

TOK_SELECT => 分别将查询表达式的语法部分保存在destToSelExpr、destToAggregationExprs、destToDistinctFuncExprs三个属性中

TOK_WHERE => 将Where部分的语法保存在QBParseInfo对象的destToWhereExpr属性中

最终样例SQL生成两个QB对象,QB对象的关系如下,QB1是外层查询,QB2是子查询

QB1
 
  \
 
   QB2

QueryBlock生成Operator Tree

QueryBlock生成Operator Tree就是遍历上一个过程中生成的QB和QBParseInfo对象的保存语法的属性,包含如下几个步骤:

QB#aliasToSubq => 有子查询,递归调用

QB#aliasToTabs => TableScanOperator

QBParseInfo#joinExpr => QBJoinTree => ReduceSinkOperator +JoinOperator

QBParseInfo#destToWhereExpr => FilterOperator

QBParseInfo#destToGroupby => ReduceSinkOperator + GroupByOperator

QBParseInfo#destToOrderby => ReduceSinkOperator + ExtractOperator

由于Join/GroupBy/OrderBy均需要在Reduce阶段完成,所以在生成相应操作的Operator之前都会先生成一个ReduceSinkOperator,将字段组合并序列化为Reduce Key/value, Partition Key

逻辑层优化器

大部分逻辑层优化器通过变换OperatorTree,合并操作符,达到减少MapReduceJob,减少shuffle数据量的目的。

名称

作用

② SimpleFetchOptimizer

优化没有GroupBy表达式的聚合查询

② MapJoinProcessor

MapJoin,需要SQL中提供hint,0.11版本已不用

② BucketMapJoinOptimizer

BucketMapJoin

② GroupByOptimizer

Map端聚合

① ReduceSinkDeDuplication

合并线性的OperatorTree中partition/sort key相同的reduce

① PredicatePushDown

谓词前置

① CorrelationOptimizer

利用查询中的相关性,合并有相关性的Job,HIVE-2206

ColumnPruner

字段剪枝

 OperatorTree生成MapReduceJob的过程

OperatorTree转化为MapReduce Job的过程分为下面几个阶段

1.      对输出表生成MoveTask

2.      从OperatorTree的其中一个根节点向下深度优先遍历

3.      ReduceSinkOperator标示Map/Reduce的界限,多个Job间的界限

4.      遍历其他根节点,遇过碰到JoinOperator合并MapReduceTask

5.      生成StatTask更新元数据

6.      剪断Map与Reduce间的Operator的关系

 物理层优化器

主要体现为hivejoin的优化

1.      map join

当一个较小的表和一个很大的表进行join时,可以把较小的表加载到每个大表数据所在节点的内存中,每读取一条大表的数据,就去遍历小表,如果join字段有相同的,就把数据进行join保存到map输出,不相同就弃掉,没有reduce过程。

实现方式:

 set hive.aotuo.convert.join=true; hive会自动识别小表,进行map join

         使用map join 语法格式 比如有两张表,employee(大表),dept(小表)

select /*+ MAP JOIN(dept) */

2.      reduce join

也叫common join,是hive默认的join方式

3.      SMB join

HQL如何决定map  reduce的数量

控制map的参数

set mapred.max.split.size=256000000;        -- 决定每个map处理的最大的文件大小,单位为B

set mapred.min.split.size.per.node=1;         -- 节点中可以处理的最小的文件大小

set mapred.min.split.size.per.rack=1;         -- 机架中可以处理的最小的文件大小

set dfs.block.size=128000000                 hdfs块文件大小

注意:当InputSplit 分片的大小大于 block 的大小时,Map Task 并不能完全满足数据的本地性,总有一本分的数据要通过网络从远程节点上读数据,故为了提高 Map Task 的数据本地性,减少网络传输的开销,应尽量是 InputFormat 的大小和 HDFS 的 block 块大小相同。

1.      输入的文件个数决定了map的个数,当文件大小大于hdfs块设置,会产生多个map,小于hdfs块大小,会产生1个map。

2.      在小文件过多时,可以开启小文件合并set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat,此时文件大于hdfs块大小时,按照块分割map,文件大小大于mapred.max.split.size大小,hdfs块大小,按照split大小分割map,将分割剩余的文件和小文件进行合并。 可以简单的理解为集群对一个表分区下面的文件进行分发到各个节点,之后根据mapred.max.split.size确认要启动多少个map数,逻辑如下 
a.假设有两个文件大小分别为(256M,280M)被分配到节点A,那么会启动两个map,剩余的文件大小为10MB35MB因为每个大小都不足241MB会先做保留 
b.根据参数setmapred.min.split.size.per.node看剩余的大小情况并进行合并,如果值为1,表示a中每个剩余文件都会自己起一个map,这里会起两个,如果设置为大于45*1024*1024则会合并成一个块,并产生一个map 
  如果mapred.min.split.size.per.node10*1024*1024,那么在这个节点上一共会有4map,处理的大小为(245MB,245MB,10MB,35MB)
  如果mapred.min.split.size.per.node45*1024*1024,那么会有三个map,处理的大小为(245MB,245MB,45MB) 
  实际中mapred.min.split.size.per.node无法准确地设置成45*1024*1024,会有剩余并保留带下一步进行判断处理 
c. b中余出来的文件与其它节点余出来的文件根据mapred.min.split.size.per.rack大小进行判断是否合并,对再次余出来的文件独自产生一个map处理

3.      对于记录很多的文件,可以手动设置map的数量set mapred.reduce.tsaks

控制reduce的参数

set hive.max.reduces.max  设置每个任务最大的reduce数量

set mapred.reduce.tasks=10; -- 设置reduce的数量

set hive.exec.reducers.bytes.per.reducer=1073741824 -- 每个reduce处理的数据量,默认1GB

hive.exec.reducers.max     控制最大的reducer的数量

reduce计算的准则

计算输入文件大小的方法:其实很简单,遍历每个路径获取length,累加。

int reducers =(int)((totalInputFileSize + bytesPerReducer - 1) / bytesPerReducer)

n=min(max reduces,reducers)

1.      可以直接手动设置reduce个数,set mapred.reduce.tasks

2.      如果不手动设置,hive会自动计算reduce数量,根据reduce计算准则

3.      在没有使用group by ,或者使用了order by,或者表存在笛卡尔积时,只会有一个reduce

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值