Hadoop实践(三)---高阶MapReduce

本文探讨了Hadoop MapReduce框架中的高级应用技巧,包括如何链接多个MapReduce作业以实现复杂的处理流程,以及如何在Hadoop中实现不同数据集之间的联结。文中详细介绍了顺序链接和复杂依赖的MapReduce作业,还提供了实现数据联结的技术方案,如Reduce侧联结、基于DistributedCache的复制联结以及半联结等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、链接多个MapReduce作业

  • 通常会存在这样的情况,无法把整个流程写在单个MapReduce作业中。因此,需要将多个MapReduce程序链接成更大的作业
  • 数据处理可能涉及多个数据集,因此需要讨论多个数据集的各种联结技术

1-1、顺序链接MapReduce作业

生成一个自动化的执行序列,将MapReduce作业按照顺序链接在一起,用一个MapReduce作业的输出作为下一个的输入

类似于Linux中的管道命令:

mapreduce1 | mapreduce2 | mapreduce3 | 。。。

顺序链接MapReduce作业很简单, driver类为作业创建一个带有配置参数的job(jobconf旧API)的对象,并将该对象传递给job.submit(jonClient.runJob旧API)来启动这个作业;当运行到作业结尾处被阻止时,作业的链接会在MapReduce作业之后调用另一个作业的driver。(每个作业的driver必须创建一个新的对象,并将输入路径设置为前一个输出路径,可以在最后一个作业中删除前面的中间结果)

1-2、复杂依赖MapReduce作业

复杂的数据处理任务的子任务并不是按顺序运行的,作业不能按照现行方式链接(例如,MR1处理Set1,MR2处理Set2;MR3处理MR1和MR2的结果)

通过Job和JobControl来管理这样的非线性作业一直的相互依赖,采用的是addDependingJob()方法:

A.addDependingJob(B) //A在B完成之前不会启动

通过addJob()方法,可以为JobControl对象添加作业,当所有作业和依赖关系添加完成后,调用JobControl的run()方法生成一个线程来提交作业并监视其执行,JobControl中有一些方法来跟踪批处理中各个作业的执行

1-3、预处理和后处理阶段的链接

数据的处理任务涉及对记录的预处理和后处理:

  1. 可以为预处理和后处理步骤各自编写一个MapReduce作业,并把它们链接起来。这样的话每个步骤的中间结果都需要占用I/O,和存储资源,效率低下。
  2. 另一种方法,编写mapper去预先调用所有的预处理步骤,再让reducer调用所有的后处理步骤,这将强制采用模块化和可组合的方式来构建预处理和后处理的构成【ChainMapper & ChainReducer】,全部步骤在单一的作业中运行,不会产生中间文件,大大减少I/O操作

关于2的ChainMapper & ChainReducer:

MAP | REDUCE   //1
MAP+ | REDUCE |MAP*    //2
MAP1 | MAP2 | REDUCE | MAP3 | MAP4 //3
  • 1 的map和reduce可以重复执行一次或多次,一个跟着一个
  • 2 的作业按序执行多个map来预处理,然后执行reducer 然后在执行多个map进行后处理,在ChainMapper & ChainReducer中调用addMapper()方法来分别组合预处理和后处理的步骤
  • 3 的作业可以把MAP2和REDUCE视为这个作业的核心,在他们之间使用标准的分区和洗牌操作,把MAP1视为预处理,把MAP3,MAP4视为后处理

示例代码如下:

public class ChainMaper {
    public static void main(String[] args) throws IOException {
        Configuration conf = new Configuration();

        JobConf job = new JobConf(conf);

        JobConf job1 = new JobConf(false);
        JobConf job2 = new JobConf(false);
        JobConf job3 = new JobConf(false);
        JobConf job4 = new JobConf(false);
        JobConf job5 = new JobConf(false);

        ChainMapper.addMapper(job, (Class<? extends Mapper<LongWritable, Text, Text, Text>>) Map1.class, LongWritable.class,Text.class,Text.class, Text.class,true,job1);
        ChainMapper.addMapper(job, (Class<? extends Mapper<Text, Text, LongWritable, Text>>) Map2.class, Text.class,Text.class, LongWritable.class,Text.class,true,job2);
        ChainReducer.setReducer(job, (Class<? extends Reducer<LongWritable, Text, Text, Text>>) Reduce.class, LongWritable.class,Text.class,Text.class, Text.class,true,job3);
        ChainMapper.addMapper(job, (Class<? extends Mapper<Text, Text, LongWritable, Text>>) Map4.class, Text.class,Text.class, LongWritable.class,Text.class,true,job4);
        ChainMapper.addMapper(job, (Class<? extends Mapper<LongWritable, Text, LongWritable, Text>>) Map5.class, LongWritable.class,Text.class, LongWritable.class,Text.class,true,job5);

        JobClient.runJob(job);
    }
}

2、联结不同来源的数据

在数据分析中不可避免地需要从不同的来源提取数据。在Hadoop中数据的联结更为复杂,并有几种可能的方法,需做不同的权衡

假设有如下数据记录:(数据之间以,分隔)

客户ID名字电话
1SS555
2EE123
3JJ281
4DD408
客户ID订单ID价格交易时间
3A1202-Jun-2008
2B8820-May-2008
3C3230-Nov-2007
3D2522-Jan-2009

预计的输出结果如下:

客户ID名字号码订单ID价钱交易时间
1SS555B8820-May-2008
2EE123C3230-Nov-2007
3JJ281A1202-Jun-2008
3JJ281D2522-Jan-2009

2-1、Reduce侧的联结

1、Reduce侧联结的数据流

与数据库处理表的连接类似:

  • 需要用户自定义一个组键(Group Key)
  • 并且为每个记录定义一个标签(tag),表示其数据的来源,标签确保这个元信息一直跟随记录

处理步骤如下:

  1. 每个map处理一个文件,在示例中有2个文件,来自2个不同的数据源
  2. 将每个记录打包,使其可以在reduce侧联结
  3. map输出的记录中的键是用户自定义的组键(group key)
  4. 然后进行MR框架的洗牌和排序操作
  5. reduce会接收到相同的组键(group key)的记录,其中包括来自2个文件的数据记录,分别带有不同的标签(tag)
  6. 输出联结后的记录

Tips:存在这样的情况,reduce处理记录时group key1 对于tag1有一条记录,而tag2有2条记录时,那么得到的结果是他们的完全交叉乘积。即group key1 tag1 tag2-1 和group key1 tag1 tag2-2 这样的2条记录

2、使用DATAJOIN软件包实现联结
Hadoop有一个名为datajoun的软件包,用作数据联结的通用框架。有3个可供继承的抽象类:

  1. DataJoinMapperBase
  2. DataJoinReducerBase
  3. TaggedMapOutput:是一种用Text标签封装记录的数据类型,实现了getTag(),setTag(Text Tag)方法,抽象方法getData()【作为mapper的输出, TaggedMapOutput必须为Writable类型,因此,必须实现readFields()和write()方法】

Datajoin软件包已经在这些基类上实现了map()和reduce()方法,可用于执行联结数据流。

2-2、基于DistributedCache的复制联结

Hadoop有一种称为分布式缓存的机制,设计主旨在于将文件分布到集群中所有节点上(通常用于分发包含所有mapper所需“背景”数据文件)

使用这个类的步骤:

  1. 配置作业时,调用静态方法DistributedCache.addCacheFile()来设定要传播到所有节点上的文件(这些文件被指定为URI对象,除非设置了不同的文件系统,否则都保存在HDFS中)JobTracker在开始工作时,将取得URI列表,并在所有TaskTracker中创建文件的本地副本
  2. 在每个单独的TaskTracker上的mapper会调用静态方法DistributedCache.getLoalCacheFiles()来获取数组本地副本所在的本地文件的路径

2-3、半联结:map侧过滤后在reduce侧联结

使用复制连接的限制之一是其中一个连接表必须小到可以放在内存中,解决这个问题的方式:重新组织处理的步骤让处理变得更为有效。

reduce侧联结的主要问题是数据仅仅有mapper做了标签,然后全部在网络上重排,而它们大多数都被reducer所忽略。如果mapper在网络重排以前,用一个额外的预过滤函数去除大多数都不必要的数据,效率低下的问题会得到改善。

3、创建一个Bloom filter

3-1、Bloom filter简介

Bloom filter是一个数据集的摘要,它的使用让其他的数据处理技术更为有效。

Bloom filter对象支持2个方法:add()和contains()【存在小概率的误报】,这2个方法的运行方式与Java中Set接口类似。

### Hadoop2x Eclipse Plugin与Hadoop 3.1.3版本的兼容性分析 Hadoop2x Eclipse Plugin最初设计用于支持较早版本的Hadoop(如2.x系列),而Hadoop 3.x引入了许多架构上的变化和API更新,这可能导致插件与其不完全兼容。具体来说: #### 插件版本与Hadoop版本的关系 Hadoop-eclipse-plugin需要严格匹配Hadoop的核心库版本。如果使用的是针对Hadoop 2.x开发的插件,则可能无法正常工作于Hadoop 3.x环境之中[^5]。这是因为Hadoop 3.x对许多内部类进行了重构或废弃操作,这些改动可能会破坏Eclipse插件的功能。 #### 已知问题描述 根据用户的尝试记录,在将`hadoop-eclipse-plugin-2.6.0`放置到Eclipse plugins目录后未能看到预期功能菜单项的情况表明该特定版本确实不适合当前所运行的Hadoop实例版本[^1]。即使更换至接近目标版本号(例如3.1.2),虽然能够部分加载但仍然存在功能性障碍比如创建新MapReduce作业时无响应等问题[^3]。 #### 自定义构建的可能性探讨 为了使Hadoop2x Eclipse Plugin适配更高版本的Hadoop, 可考虑自行编译适合的具体步骤包括但不限于调整源码中依赖项以反映最新版Hadoop组件的实际路径以及修正任何因升级引起冲突之处[^2]: ```bash # 设置环境变量以便Ant工具能正确识别Java SDK位置 export JAVA_HOME=/path/to/jdk export PATH=$JAVA_HOME/bin:$PATH cd /path/to/hadoop2x-eclipse-plugin-source/ ant clean jar -Dversion=3.1.3 -Declipse.home=/path/to/eclipse ``` 以上命令序列旨在清理旧构建产物并依据指定参数重新打包适用于Hadoop 3.1.3的新插件包。然而需要注意的是此过程复杂度较高且成功率取决于开发者对于两者间差异理解程度如何。 另外值得注意的一点是,Hortonworks曾提供过官方维护过的更现代化一些替代方案即Ambari Metrics Service GUI或者Zeppelin Notebook作为补充选项来弥补传统MR视图局限性;Cloudera同样也有相应产品线(Cloud CDP)可供选择. 尽管如此, 如果坚持沿用原生方式实现集成的话, 上述方法不失为一种努力方向. ```python import os def check_hadoop_version(): hadoop_home = "/usr/local/hadoop" version_file_path = f"{hadoop_home}/VERSION" if not os.path.exists(version_file_path): raise FileNotFoundError(f"Hadoop VERSION file does not exist at {version_file_path}") with open(version_file_path, 'r') as vf: content = vf.read() print(content) check_hadoop_version() ``` 上述脚本可用于验证本地安装好的Hadoop确切版本信息从而辅助判断下一步行动方针。 ### 结论 综上所述,Hadoop2x Eclipse Plugin理论上并不天然支持Hadoop 3.1.3这样的高阶变体形式。要达成无缝衔接效果要么寻找社区贡献者已经预先处理完毕的相关制品要么亲自动手完成定制化改造流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值