Hadoop实践(三)---MapReduce中的输入和输出
来源:互联网 发布:自动分辨率软件 编辑:程序博客网 时间:2024/05/20 10:54
图中显示了MR中的高层次数据流,并表明了数据流各个部分的角色。
在输入端,在map之前执行数据分割的工作,在map中执行读取分割工作,所有的输出工作在reduce段执行,输出结果
部分情况下只需要map作业就可以了,那么数据流中没有Partition和Reduce这2个模块
1、数据输入
MR中有2个支持数据输入的类:
- InputFormat:用于决定如何为map任务分割输入数据
- RecordReader:读取输入数据
1-1、 InputFormat
MR中的每个作业必须通过InputFormat抽象类来约定输入数据
InputFormat必须实现三个约定:
- 为map的输入参数key和value定义数据类型
- 指定如何分割输入数据
- 指定RecordReader实例从源读取数据
InputFormat类的注释和它的三个构造函数:
abstract InputFormat<K,V>
:map输入的键值的类型定义List<InoutSplit> getSplits(jobContext context)
:分割输入数据,转换为InputSplit列表RecordReader<K,V> createRecordReader(InputSplit split, TaskAttemptContext context)
:创建RecordReader从作业输入中读取数据
最关键的是确定如何划分输入数据
在MR中,这种划分称为input split,这直接影响map 的并行运行。
因为每个分片有一个单独的map任务执行,如果InputFormat不能通过单个数据源创建多个input split,这将导致map任务运行缓慢(此时文件是单线程顺序处理的)
TextInputFormat类实现了InputFormat类的createRecordReader方法,但是将计算input split个数的工作交给父类(FileInputFormat)处理。
指定MR作业的InputFormat:job.setInputFormatClass(TextInputFormat.class)
FileInputFormat:
package T607;import org.apache.hadoop.fs.BlockLocation;import org.apache.hadoop.fs.FileStatus;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;import org.apache.hadoop.mapreduce.InputSplit;import org.apache.hadoop.mapreduce.JobContext;import org.apache.hadoop.mapreduce.lib.input.FileSplit;import java.io.IOException;import java.util.ArrayList;import java.util.List;/** * Created by Promacanthus on 2017/6/7. */public class FileInputFormat { public List<InputSplit> getSplits(JobContext job) throws IOException{ //listStatus 方法获取所有这次工作需要输入的文件 List<InputSplit> splits = new ArrayList<InputSplit>(); List<FileStatus> files = listStatus(job); for (FileStatus file:files) { Path path = file.getPath(); BlockLocation[] blockLocations = FileSystem.getFileBlockLocations(file,0,length); //获取所有文件块 long splitSize = file.getBlockSize(); //这个分片的大小与文件块大小相同,每个文件可以有不同的文件块大小 while(splitsRemaining()){ splits.add(new FileSplit(path, ...)); //为每个文件块创建一个分片并加入结果集中 } } return splits; }}
TextInputFormat:
import org.apache.hadoop.io.LongWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.InputSplit;import org.apache.hadoop.mapreduce.RecordReader;import org.apache.hadoop.mapreduce.TaskAttemptContext;import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;import org.apache.hadoop.mapreduce.lib.input.LineRecordReader;import java.io.IOException;/** * Created by Promacanthus on 2017/6/7. */public class TextInputFormat extends FileInputFormat<LongWritable, Text> { //FileInputFormat作为父类提供所有的输入切分的功能 public RecordReader<LongWritable, Text> createRecordReader(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException { //默认的记录分割的换行符,但是可以使用自定义的textinputformat.record.delimiter来替换换行符 String delimiter = context.getConfiguration().get("textinoutformat.record.delimiter"); byte[] recordDelimiterBytes = null; if(null != delimiter){ recordDelimiterBytes = delimiter.getBytes(); } return new LineRecordReader(recordDelimiterBytes); } ...}
1-2、RecordReader
map任务中的RecordReader类用于从input split中读取数据,并将每行记录的键值对传给map任务,通常都要为每个input split创建一个任务,且每个任务都要一个独立的RecordReader用于读取input split中的数据
RecordReader类的注释和它的抽象方法:
abstract RecordReader<KEYIN, VALUEIN>
:定义map输入的键值对类型void initialize(InputSplit split, TaskAttempContext context)
:初始化,这可能涉及需要在一个文件中定位,并确定下一个记录的逻辑起点boolean nextKeyValue()
:读取下一个记录的文件,并放回一个标记确定是否应达到分片结尾KEYIN getCurrentKey()
:返回当前记录的键VALUEIN getCurrentValue()
:返回当前记录的值float getProgress()
:返回当前读取的进度void close()
:关闭所有与数据源关联的资源
在InputFormat中的TextInputFormat中返回的是一个LineRecordReader来读取input split 中的数据。LineRecordreader直接扩展RecordReader类,并利用LineReader类读取input split中的一行行数据,LineRecordreader将文件中的字节偏移量作为map 的key,将文件中的每行内容作业map 的值
LineRecordreader:
import org.apache.hadoop.fs.FSDataInputStream;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.io.LongWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.InputSplit;import org.apache.hadoop.mapreduce.RecordReader;import org.apache.hadoop.mapreduce.TaskAttemptContext;import org.apache.hadoop.mapreduce.lib.input.FileSplit;import org.apache.hadoop.util.LineReader;import java.io.IOException;/** * Created by Promacanthus on 2017/6/7. */public class LineRecordreader extends RecordReader<LongWritable, Text> { private LineReader in; private LongWritable key = new LongWritable(); private Text value = new Text(); public void initialize(InputSplit genericSplit, TaskAttemptContext context) throws IOException{ FileSplit split = (FileSplit) genericSplit; //open the file and seek to the start of the split FileSystem fileSystem = file.getFileSystem(job); FSDataInputStream fsDataInputStream = fileSystem.open(split.getPath()); //使用分片文件打开一个输入流 fsDataInputStream.seek(start); //定位到这个分片的起始位置 in = new LineReader(fsDataInputStream,job); //创建一个LineReader这样可以从流中读取每一行 if(notAtStartOfFile){ start += in.readLine(...); //如果不在文件的其起始位置,需要指出从哪里开始读取行。做到这一点的唯一方法是继续读字符,直到命中一个换行符,这样可以为map提供行输入 } } public boolean nextkeyvalue()throws IOException{ //初始化方法被调用后,MR框架反复调用nextkeyvalue()方法。直到它返回false,这意味着input split 结束 key.set(pos); //设置下一个key 的起始点的偏移量 return in.readLine(value....)>0; //读取下一行的值,如果读取超过input split的结尾,则返回false }}
2、数据输出
MR中有2个支持数据输出的类:
- OutputFormat:用于验证数据接收器的属性
- RecordWriter:用于将reduce对象的输出结果导入数据接收器中
指定MR作业的OutputFormat:job.setOutputFormatClass(TextOutputFormat.class)
2-1、OutputFormat
OutputFormat:
abstract OutputFormat<K,V>
:定义reduce输入键和值的类型RecordWriter<K,V> getRecordWriter(TaskAttemptContext context)
:创建一个RecordWriter实例将数据写入到目标void checkOutputSpecs(JobContext context)
:验证与MR作业相关联的输出信息是否正确OutputCommitter getOutputCommitter(TaskAttemptContext context)
:回去相关OutputCommitter,当所有任务成功完成,OutputCommitter复制在最后将结果输出
TextOutputFormat扩展了FileOutputFormat,这个类主要用于处理output committing
TextOutputFormat
import org.apache.hadoop.fs.FSDataOutputStream;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;import org.apache.hadoop.mapreduce.RecordWriter;import org.apache.hadoop.mapreduce.TaskAttemptContext;import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import java.io.IOException;/** * Created by Promacanthus on 2017/6/7. */public class TextOutputFormat extends FileOutputFormat<K,V> { public RecordWriter<K,V> getRecordWriter(TaskAttemptContext job) throws IOException,InterruptedException{ boolean isCompressed = getCompressOutput(job); String keyValueSpearator = conf.get("mapred.textoutputformat.separator","\t"); //默认的键值对的分隔符是tab字符,在这里可以通过更改mapred.textoutputformat.separator的设置来改变它 Path file = getDefaultWorkFile(job,extension); //在临时目录中为reducer创建一个唯一的文件名 FileSystem fs = file.getFileSystem(conf); FSDataOutputStream fsDataOutputStream = fs.create(file,false); //创建输出文件 return new LineRecordWriter<K,V>(fsDataOutputStream,keyValueSpearator); //返回一个用于写入文件的RecordWriter }}
2-2、 RecordWriter
LineRecordWriter返回一个LineRecordWriter对象(LineRecordWriter是LineRecordWriter的内部类)去执行写入操作
LineRecordWriter
import org.apache.hadoop.mapreduce.RecordWriter;import java.io.DataOutputStream;import java.io.IOException;/** * Created by Promacanthus on 2017/6/7. */public static class LineRecordWriter<K,V> extends RecordWriter<K,V> { protected DataOutputStream out; public synchronized void write(K key, V value) throws IOException{ //输出键、分隔符、值以及换行符 writeObjct(key); out.write(keyValueSpearator); writeObjecr(value); out.write(newline); } private void writeObjct(Object o) throws IOException{ //对输出流输出对象 out.write(0); }}
map端的InputFormat决定了有多少个map任务被执行,reduce端的任务的个数由客户端设置的mapred.reduce.tasks的值决定(如果客户端没有设置,这个值从mapred-site.xml中获取,如果不存在site文件,则从mapred-default中获取)
- Hadoop实践(三)---MapReduce中的输入和输出
- Hadoop实践(三)---MapReduce中的Counter
- Hadoop实践(三)---高阶MapReduce
- (三)C++中的输入和输出
- Hadoop之MapReduce输入与输出格式(五)
- hadoop之MapReduce输入(split)输出
- Hadoop之MapReduce输入(split)输出
- Hadoop教程(三):HDFS、MapReduce、程序入门实践
- Hadoop教程(三):HDFS、MapReduce、程序入门实践
- [hadoop]MapReduce简介和安装(三)
- MapReduce深入理解输入和输出格式(2)-输入和输出完全总结
- hadoop输入和输出格式
- mapreduce处理中文输入和输出
- Hadoop MapReduce开发最佳实践(上篇)
- Hadoop MapReduce开发最佳实践(上篇)
- Hadoop MapReduce开发最佳实践(上篇)
- Hadoop MapReduce多路径输入和多个类型输入
- Hadoop之MapReduce中的排序和分组(笔记11)
- IT大牛博客
- 【stm32f407】外部中断实现按键中断方式
- EF映射——从数据库更新实体
- 斯坦福机器学习之贝叶斯统计正则化
- java文件复制
- Hadoop实践(三)---MapReduce中的输入和输出
- 加载多个checkbox
- 把字符串转换成整数(java版)
- Python中单/双下划线使用
- 909422229_下拉框便利跳转与jsp获取当前时间
- Codeforces 813A The Contest 题解
- Factory Method模式角色与结构
- awk使用备忘
- windows找不到文件“-n”