文档章节

从零开始学习Hadoop--第6章 MapReduce的输入输出

brian_2017
 brian_2017
发布于 2017/01/17 09:13
字数 1485
阅读 5
收藏 0

    这一章都是文字叙述,不需要写源代码了。一般情况下,只需要记住这些东西就可以了。


Hadoop处理大数据。


大数据以文件的形式存储在HDFS


大文件被划分成文件块存贮,每个文件块有固定的大小,通常是64M,或者128M,或者255M


我们在第2章写了一个WordCountMapReduce程序,最关键部分是MapperReducer。在做MapReuce时,先做Map,再做ReduceHadoop的框架让我们不需要关注MapperReducer之外的地方,但我们肯定会想,数据是怎么从HDFS传给Mapper的?Reducer处理完数据之后,又是怎么将数据存储到HDFS的?


将数据从HDFS传到Mapper是由InputFormat类实现的。


将数据从Reducer存储到HDFS是由OutputFormat类实现的。


先解释一下Java的抽象类。抽象类就是声明了抽象函数的类。假如A是一个抽象类,它有一个抽象函数do_it,那么它只是声明有do_it这个函数,但并没有实现它的功能。抽象类只能作为类的模板,也就是说抽象类不能实例化。假设,类B继承了类AB也就有了dot_it函数,如果B是一个具体的类,它就必须在自己的内部实现do_it函数的功能。

1.InputFormat

InputFormat类是一个抽象类。InputFormat类定义了两个抽象函数。这两个抽象函数是:

abstract List<InputSplit> getSplits(JobContext context) ”

abstract RecordReader<K,V> createRecordReader(InputSplit split,TaskAttemptContext context) ”

如果检查一下源代码,InputFormat抽象类的定义是在InputFormat.java,代码非常短,注释之外只有这两行抽象函数声明。


函数getSplits的功能,是将输入的HDFS文件切分成若干个spit。在Hadoop集群里的每个节点做MapReduce时候处理的时候,每次只处理一个split,所以splitMapReduce处理的最小单元。


函数createRecordReader的功能,是创建RecordReader对象,这个RecordReader对象根据split的内容,将split解析成若干个键值对。在做MapReduce的时候,Mappper会不断地调用RecordReader的功能,从RecordReader里读取键值对,然后用map函数进行处理。


InputFormat类是一个抽象类,它并不具体负责这两个功能的实现。它有3个继承类,DBInputFormat,DelegatingInputFormat类和FileInputFormat类。其中,DBInputFormat类是处理从数据库输入,DelegatingInputFormat类是用在多个输入处理,FileInputFormat类是处理基于文件的输入。


fileInputFormat类为例。FileInputFormat类是一个抽象类,它在InputFormat类的基础上,增加一些跟文件操作相关的函数。它实现了getSplits函数,但没实现createRecordReader函数,它把createRecordReader的实现留给继承类去做。在getSplits函数里,最重要的是这段:






// generatesplits

//这是返回值

List<InputSplit>splits = new ArrayList<InputSplit>();

//获取HDFS文件的信息,FileStatus在前面的章节使用过。

List<FileStatus>files= listStatus(job);

//对作业的每个文件都进行处理

for(FileStatus file: files) {

//获取文件路径

Path path =file.getPath();

FileSystemfs = path.getFileSystem(job.getConfiguration());

//获取文件长度

long length= file.getLen();

//获取文件在HDFS上存储的文件块的位置信息

BlockLocation[]blkLocations = fs.getFileBlockLocations(file, 0, length);


if ((length!= 0) && isSplitable(job, path)) {

//获取文件块的大小

longblockSize = file.getBlockSize();

//根据文件块大小,最小尺寸,最大尺寸,计算出split的大小

longsplitSize = computeSplitSize(blockSize, minSize, maxSize);


//这段代码是根据splitSize,每次计算一个split的块位置和所在主机的位置。

//然后生成split对象存储。

longbytesRemaining = length;

while(((double) bytesRemaining)/splitSize > SPLIT_SLOP) {

intblkIndex = getBlockIndex(blkLocations, length-bytesRemaining);

splits.add(newFileSplit(path, length-bytesRemaining, splitSize,

blkLocations[blkIndex].getHosts()));

bytesRemaining-= splitSize;

}


//最后剩下的不够一个splitSize的数据单独做一个split

if(bytesRemaining != 0) {

splits.add(newFileSplit(path, length-bytesRemaining, bytesRemaining,

blkLocations[blkLocations.length-1].getHosts()));

}

} else if(length != 0) {

//如果文件很小,就直接做成一个split

splits.add(newFileSplit(path, 0, length, blkLocations[0].getHosts()));

} else {

//如果文件尺寸是0,空文件,就创建一个空主机,主要是为了形式上一致。

splits.add(newFileSplit(path, 0, length, new String[0]));

}

}


FileInputFormat5个继承类,包括CombineFileInputFormat类,KeyValueTextInputFormat类,NLineInputFormat类,SequenceFileInputFormat类和TextInputFormat类。这几个有抽象类,也有具体类。


TextInputFormat类为例,它实现了createRecordReader函数,非常简单,函数体只有一个语句,返回一个LineRecordReader


LineRecordReader类继承了抽象类RecordReader。抽象类RecordReader定义的全是抽象函数。LineRecordReader每次从一个InputSplit里读取一行文本,以这行文本在文件中的偏移量为键,以这行文本为值,组成一个键值对,返回给Mapper处理。

2.OutputFormat

OutputFormat类将键值对写入存储结构。一般来说,Mapper类和Reducer类都会用到OutputFormat类。Mapper类用它存储中间结果,Reducer类用它存储最终结果。


OutputFormat是个抽象类,这个类声明了3个抽象函数:

publicabstract RecordWriter<K, V> getRecordWriter(TaskAttemptContext context)

publicabstract void checkOutputSpecs(JobContext context)

publicabstract OutputCommitter getOutputCommitter(TaskAttemptContextcontext)

其中,最主要的函数是getRecordWriter返回RecordWriter,它负责将键值对写入存储部件。函数checkOutputSpecs检查输出参数是否合理,一般是检查输出目录是否存在,如果已经存在就报错。函数getOutputCommitter获取OutputCommitterOutputCommitter类是负责做杂活的,诸如初始化临时文件,作业完成后清理临时目录临时文件,处理作业的临时目录临时文件等等。


OutputFormat4个继承类,有DBOutputFormatFileOutputFormatFilterOutputFormatNullOutputFormat。顾名思义,DBOutputFormat是将键值对写入到数据库,FileOutputFormat将键值对写到文件系统,FilterOutputFormat将其实是提供一种将OutputFormat进行再次封装,类似Java的流的Filter方式,NullOutputFormat将键值对写入/dev/null,相当于舍弃这些值。


FileOutputFormat为例。FileOutputFormat是一个抽象类。它有两个继承类,SequenceFileOutputFormatTextOutputFormatSequenceFileOutputFormat将键值对写入HDFS的顺序文件。TextOutputFormat将数据写入HDFS的文本文件。写入过程类似第3HDFS文件操作。

© 著作权归作者所有

brian_2017
粉丝 3
博文 61
码字总数 145216
作品 0
私信 提问
Apache Hadoop 入门教程第三章

免密码 ssh 设置 现在确认能否不输入口令就用 ssh 登录 localhost: $ ssh localhost 1 如果不输入口令就无法用 ssh 登陆 localhost,执行下面的命令: $ ssh-keygen -t rsa -P '' -f ~/.ssh/...

哈斗篷
2018/05/10
0
0
【电子书】Hadoop实战手册 (样章第一章)

Hadoop实战手册 [美] Jonathan R. Owens,Jon Lentz,Brian Femiano 著; 傅杰,赵磊,卢学裕 译 内容简介   这是一本Hadoop实用手册,主要针对实际问题给出相应的解决方案。《Hadoop实战手...

dwf07223
2018/06/28
0
0
Hadoop的mapreduce的简单用法

 Mapreduce初析   Mapreduce是一个计算框架,既然是做计算的框架,那么表现形式就是有个输入(input),mapreduce操作这个输入(input),通过本身定义好的计算模型,得到一个输出(outpu...

魔法王者安琪拉
2018/08/23
27
0
Hadoop 版本 生态圈 MapReduce模型

一 Hadoop版本 和 生态圈 1. Hadoop版本 (1) Apache Hadoop版本介绍 Apache的开源项目开发流程 : -- 主干分支 : 新功能都是在 主干分支(trunk)上开发; -- 特性独有分支 : 很多新特性稳定性很...

日拱一卒
2014/05/17
68
0
MapReduce 实验 (一) 原理

官网 http://hadoop.apache.org/ hadoop三大组件 HDFS:分布式存储系统 https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html MapReduce:分布式计算......

pcdog
2018/04/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

作为一个(IT)程序员!聊天没有话题?试试这十二种技巧

首先呢?我是一名程序员,经常性和同事没话题。 因为每天都会有自己的任务要做,程序员对于其他行业来说;是相对来说比较忙的。你会经常看到程序员在发呆、调试密密麻麻代码、红色报错发呆;...

小英子wep
今天
12
0
【SpringBoot】产生背景及简介

一、SpringBoot介绍 Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程,该框架使用了特定的方式来进行配置,从而使开发人员不再需要...

zw965
今天
4
0
简述并发编程分为三个核心问题:分工、同步、互斥。

总的来说,并发编程可以总结为三个核心问题:分工、同步、互斥。 所谓分工指的是如何高效地拆解任务并分配给线程,而同步指的是线程之间如何协作,互斥则是保证同一时刻只允许一个线程访问共...

dust8080
今天
6
0
OSChina 周四乱弹 —— 当你简历注水但还是找到了工作

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @花间小酌 :#今日歌曲推荐# 分享成龙的单曲《男儿当自强》。 《男儿当自强》- 成龙 手机党少年们想听歌,请使劲儿戳(这里) @hxg2016 :刚在...

小小编辑
今天
3.3K
22
靠写代码赚钱的一些门路

作者 @mezod 译者 @josephchang10 如今,通过自己的代码去赚钱变得越来越简单,不过对很多人来说依然还是很难,因为他们不知道有哪些门路。 今天给大家分享一个精彩的 GitHub 库,这个库整理...

高级农民工
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部