挖挖Hive的代码(三)——生成MapReduce(中)

好久没有更新博客了,最近终于有空可以继续分享我对Hive代码的剖析了。不想再用上一篇的那种风格来解读代码了,直接上白话版的代码解读吧。

上一篇已经贴过一段模式匹配法处理Operator树的代码,罗列了十多个处理流程。这次就具体展开的解读一下Hive是如何实现这些处理流程的。


GenMRProcContext (下面简称ctx),

记录了整个遍历过程中的上下文信息。

ParseContext(下面简称parseCtx),语义分析的结果,包含了整个job的operator树


TS%:

构造一个新的MapRedTask对象(task),并在ctx中记录该task为currTask,记录当前operator为currTopOp;

在parseCtx中找到当前operator对应的alias;

为当前operator构造一个GenMapRedCtx对象,以currTask,currTopOp和alias为参数,并以当前operator为key记录在ctx中。

(Analyze的操作也在这里处理,没研究,暂略)


TS%.*RS%:

通过上一个operator(对应的GenMapRedCtx对象)获取到:currTask,currPlan,currTopOp,currAliasId等信息,并将这些信息保存在ctx中;

获取当前operator的child作为reducer(必然是一个MapReduce job的reduce部分的topOp),并从ctx获取到该reducer对应的task对象;

如果reducer对应的task不存在,说明这个reducer还没有被遍历过:

  • 如果currPlan的reduce部分也没有构造,则调用initPlan()方法初始化这个plan:
    • 将该reducer与currTask的映射关系存入ctx;
    • 将该reducer设为currPlan的reduce部分;
    • 将currTask存入ctx的rootTasks中;
    • 如果该reducer是个JoinOperator,会将currPlan的needsTagging设为true
    • 如果currTopOp不在ctx的seenOps中,添加之,并调用setTaskPlan()方法设置currTask的源输入信息(path2alias的映射关系,partition的裁剪也在这里实现的)
    • 将currTopOp,currAliasId置空
  • 如果reduce部分已经构造过了(当前这棵TS树有分叉,有两个RS,currPlan的reduce部分被另一个RS的child给占了),则调用splitPlan()方法构造一个新的task:
    • 构造一个新的task,将该reducer设为这个task的plan的reduce部分;
    • 将该reducer与这个task的映射关系存入ctx;
    • 调用splitTasks()方法关联这两个有依赖关系的task(旧的为parent,新的为child):
      • 设置俩task的关联关系;
      • 生成一个临时文件路径(用来存中间结果);
      • 根据这个临时文件路径,构造一个FileSinkOperator(FS),并用这个FS替换当前(currTask中的,也就是parent)的RS;
      • 构造一个TableScanOperator(TS)作为当前RS的parent;
      • 如果当前RS的reducer是JoinOperator(Join),则这个新生成的TS对应的alias会改成一个特殊的值,并且设置child task的plan的needsTagging为true;
      • 调用setTaskPlan()方法为child task设置源输入信息(会用到新构造的临时文件路径作为源输入路径,如果reducer是Join,map部分的alias就是刚设置的特殊值,否则用临时文件路径代替):
        • 在该方法中,会将前一步关联起来的TS-RS串添加到新的task的map部分中去。
      • 在ctx中,将currTopOp,currAliasId置空,将child task设为currTask。

如果reducer对应的task已经存在了(join的情况,另一个分支已经遍历过了),则调用joinPlan()方法合并当前task与该reducer对应的task:

  • 将currTopOp在ctx中标记为已遍历;
  • 判断当前TS到RS的逻辑是否为mapjoin的小表的逻辑;
  • 调用setTaskPlan()方法,在reducer对应的task中,为currTopOp设置对应的源输入信息:
    • 在该方法中,会将currTopOp添加到reducer对应的task的map部分中去。
  • 在ctx中,将currTopOp置空,将改reducer对应的task设为currTask

设置该reducer对应的task为currTask(这步确实做了两次,地方不同);

最后,为当前operator构造一个GenMapRedCtx对象,以currTask,currTopOp和currAliasId为参数,并以当前operator为key记录在ctx中。


RS%.*RS%:

通过上一个operator(对应的GenMapRedCtx对象)获取到:currTask,currTopOp,currAliasId等信息,并将这些信息保存在ctx中;

获取当前operator的child作为reducer(必然是一个MapReduce job的reduce部分的topOp),并从ctx中获取到该reducer对应的task对象;

如果该reducer对象不存在(还没有被遍历过),调用splitPlan()方法构造一个新的MapRedTask对象,并依赖于currTask:

  • 通过ctx构造一个新的MapredWork对象,并以此构造一个新的MapRedTask对象(新的task);
  • 将该reducer设为新task的reduce部分;
  • 在ctx中记录该reducer与这个新task的映射关系;
  • 调用splitTasks()方法关联currTask与这个新的task:
    • 设置task间的依赖关系,currTask为parent,新的task为child;
    • 生成一个临时文件路径(用来存中间结果);
    • 根据这个临时文件路径,构造一个FileSinkOperator(FS),并用这个FS替换当前(currTask中)的RS;
    • 构造一个TableScanOperator(TS)作为当前RS的parent;
    • 如果当前RS的reducer是JoinOperator(Join),则这个新生成的TS对应的alias会改成一个特殊的值,并且设置child task的plan的needsTagging为true;
    • 调用setTaskPlan()方法为child task设置源输入信息(会用到新构造的临时文件路径作为源输入路径,如果reducer是Join,map部分的alias就是刚设置的特殊值,否则用临时文件路径代替):
      • 在该方法中,会将前一步关联起来的TS-RS串添加到新的task的map部分中去。
    • 在ctx中,将currTopOp,currAliasId置空,将child task设为currTask。

否则这个reducer必然已经被遍历过了,调用joinPlan()方法,将该reducer对应的task关联到currTask:

  • 设置task间的依赖关系:为currTask增加一个依赖于它的task(reducer对应的task);
  • 生成一个临时文件路径(用来存中间结果);
  • 根据这个临时文件路径,构造一个FileSinkOperator(FS),并用这个FS替换当前(currTask中)的RS;
  • 构造一个TableScanOperator(TS)作为当前RS的parent;
  • 如果当前RS的reducer是JoinOperator(Join),则这个新生成的TS对应的alias会改成一个特殊的值,并且设置child task的plan的needsTagging为true;
  • 调用setTaskPlan()方法为child task设置源输入信息(会用到新构造的临时文件路径作为源输入路径,如果reducer是Join,map部分的alias就是刚设置的特殊值,否则用临时文件路径代替):
    • 在该方法中,会将前一步关联起来的TS-RS串添加到reducer对应的task的map部分中去。
  • 在ctx中,将currTopOp,currAliasId置空,将reducer对应的task设为currTask。

最后,为当前operator构造一个GenMapRedCtx对象,以currTask,currTopOp和currAliasId为参数,并以当前operator为key记录在ctx中。


FS%:

关联moveTask;如有必要,添加statsTask;如有必要,添加merge files所必要的job。


TS%.*MAPJOIN%:

通过MapjoinOperator(MO)的parent获取currTask, currPlan, currAliasId;

在这个处理过程中,reducer就是当前MO;

从ctx中获取该reducer对应的task;

如果reducer对应的task不存在,调用initMapjoinPlan()就行初始化:

  • 将该reducer(MO)与currTask的映射关系记录在ctx中;
  • 将currTask加入ctx的root tasks中;
  • 在ctx中标注currTopOp为已遍历;
  • 调用setTaskPlan(),在reducer对应的task(currTask)中,为currTopOp设置对应的源输入信息,并将currTopOp添加到currTask的map部分中去;
  • 在ctx中,将currTopOp,currAliasId置空,将currTask设为currTask

如果reducer对应的task已经存在了(mapjoin的另一路已经被遍历过),则调用joinPlan()方法合并当前task与该reducer对应的task:

  • 判断当前TS到MO的逻辑是否为mapjoin的小表的逻辑;
  • 调用setTaskPlan(),在reducer对应的task(currTask)中,为currTopOp设置对应的源输入信息:
    • 如果currTopOp是个小表的TS,会在currTask的plan中生成一个MapLocalWork对象,源输入的信息是以alias -> FetchWork的形式存在。
  • 在ctx中,将currTopOp置空,将改reducer对应的task设为currTask

(未完,待续……)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值