一、输入格式

  1、输入分片split

      一个分片对应一个map任务;

      一个分片包含一个表(整个文件)上的若干行,而一条记录(单行)对应一行;

      分片包含一个以字节为单位的长度 和 一组存储位置,分片不包含实际的数据;

      map处理时会用分片的大小来排序,优先处理最大的分片;

  hadoop中Java定义的分片为InputSplit抽象类:主要两个方法,涉及分片长度,分片起始位置

  1. public abstract class InputSplit{
  2. public abstract long getLength() throws IOException, InterruptedException;
  3. public abstract String[] getLocations() throws IOException, InterruptedException;
  4. }

  InputSplit不需要手动去处理它,它是由InputFormat生成;InputFormat负责产生输入分片并将它们分割成记录:

  1. public abstract class InputFormat<K, V> {
  2. public abstract List<InputSplit> getSplits( JobContext context) throws IOException, InterruptedException;
  3. public abstract RecordReader<K, V> createRecordReader(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException;
  4. }

  InputFormat抽象类定义的两个方法:getSplits() 和 createRecordReader()

  运行作业的客户端会调用getSplits()来计算分片,然后将它们发送到jobtracker,jobtracker会使用其存储位置来调度map任务从而在tasktracker上来处理这个分片数据。在tasktracker上,map任务把输入分片传给InputFormat的getRecordReader()方法来获得这个分片的RecordReader。RecordReader就是一个集合迭代器,map任务用一个RecordReader来生成记录的键/值对,然后再传递给map函数。

  2、FileInputFormat类

    FileInputFormat类是所有指定数据源实现类的基类,它本身主要有两个功能:a. 指定输入文件位置;b. 输入文件生成分片的实现代码段,具体实现由子类完成;

    继承图:

        

    设置输入文件位置:

      FileInputFormat.addInputPath(job, new Path("hdfs://fileClusters:9000/wordcount.txt"));

      或 FileInputFormat.setInputPaths(job, new Path("hdfs://fileClusters:9000/wordcount.txt"));      

      可添加文件过滤器, FileInputFormat 中静态方法:

        public static void setInputPathFilter(Job job, Class<? extends PathFilter> filter)

        文件添加时,默认就会有一个过滤器,过滤掉"." 和 "_"开头的文件,会过滤掉隐藏文件;自定义的过滤器也是在默认过滤的基础上过滤;

    切分的分片大小:

        一个split的大小计算:max( minimumSize, min( maximumSize, blockSize ));

        minimumSize默认为1,maximumSize默认为Long.MAX_VALUE;

        所以通常 blockSize 在 minimumSize和maximumSize之间,所以一般分片大小就是块大小。

    设置不切分文件:

        两种方法:

          a. 设置minimumSize的大小为Long.MAX_VALUE;

          b. 在实现FileInputFormat的子类时,重写isSplitable()方法返回为false;

     

    在mapper中获取文件分片信息:

        在mapper中可以获取当前处理的分片的信息,可通过context.getInputSplit()方法来获取一个split;当输入的格式源于FileInputFormat时,该方法返回的InputSplit可以被强制转换化一个FileSplit(继承自InputSplit),可调用如下信息:

           a. getPath()  Path/String  文件的路径

           b. getStart() long

             c. getLength() long

    

     自定义一个输入格式,把整个文件作为一条记录: 

  1. // Example 7-2. An InputFormat for reading a whole file as a record
  2. class WholeFileInputFormat extends FileInputFormat<NullWritable, BytesWritable> {
  3. @Override
  4. protected boolean isSplitable(JobContext context, Path file) {
  5. return false;
  6. }
  7.  
  8. @Override
  9. public RecordReader<NullWritable, BytesWritable> createRecordReader(InputSplit split, TaskAttemptContext context)
  10. throws IOException, InterruptedException {
  11. WholeFileRecordReader reader = new WholeFileRecordReader();
  12. reader.initialize(split, context);
  13. return reader;
  14. }
  15. }
  16.  
  17. //主要是实现RecordReader类
  18. class WholeFileRecordReader extends RecordReader<NullWritable, BytesWritable> {
  19. private FileSplit fileSplit;
  20. private Configuration conf;
  21. private BytesWritable value = new BytesWritable();
  22. private boolean processed = false;
  23.  
  24. @Override
  25. public void initialize(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException {
  26. this.fileSplit = (FileSplit) split;
  27. this.conf = context.getConfiguration();
  28. }
  29.  
  30. @Override
  31. public boolean nextKeyValue() throws IOException, InterruptedException {
  32. if (!processed) {
  33. byte[] contents = new byte[(int) fileSplit.getLength()];
  34. Path file = fileSplit.getPath();
  35. FileSystem fs = file.getFileSystem(conf);
  36. FSDataInputStream in = null;
  37. try {
  38. in = fs.open(file);
  39. IOUtils.readFully(in, contents, 0, contents.length);
  40. value.set(contents, 0, contents.length);
  41. } finally {
  42. IOUtils.closeStream(in);
  43. }
  44. processed = true;
  45. return true;
  46. }
  47. return false;
  48. }
  49.  
  50. @Override
  51. public NullWritable getCurrentKey() throws IOException, InterruptedException {
  52. return NullWritable.get();
  53. }
  54.  
  55. @Override
  56. public BytesWritable getCurrentValue() throws IOException, InterruptedException {
  57. return value;
  58. }
  59.  
  60. @Override
  61. public float getProgress() throws IOException {
  62. return processed ? 1.0f : 0.0f;
  63. }
  64.  
  65. @Override
  66. public void close() throws IOException {
  67. // do nothing }
  68. }
  69. }

       整个文件作为一条记录的应用,把多个小文件合并为一个大文件:

  1. public class SmallFilesToSequenceFileConverter extends Configured implements Tool {
  2. static class SequenceFileMapper extends Mapper<NullWritable, BytesWritable, Text, BytesWritable> {
  3. private Text filenameKey;
  4.  
  5. @Override
  6. protected void setup(Context context) throws IOException, InterruptedException {
  7. InputSplit split = context.getInputSplit();
  8. Path path = ((FileSplit) split).getPath();
  9. filenameKey = new Text(path.toString());
  10. }
  11.  
  12. @Override
  13. protected void map(NullWritable key, BytesWritable value, Context context)
  14. throws IOException, InterruptedException {
  15. context.write(filenameKey, value);
  16. }
  17. }
  18.  
  19. @Override
  20. public int run(String[] args) throws Exception {
  21. Job job = JobBuilder.parseInputAndOutput(this, getConf(), args);
  22. if (job == null) {
  23. return -1;
  24. }
  25. job.setInputFormatClass(WholeFileInputFormat.class);
  26. job.setOutputFormatClass(SequenceFileOutputFormat.class);
  27. job.setOutputKeyClass(Text.class);
  28. job.setOutputValueClass(BytesWritable.class);
  29. job.setMapperClass(SequenceFileMapper.class);
  30. return job.waitForCompletion(true) ? 0 : 1;
  31. }
  32.  
  33. public static void main(String[] args) throws Exception {
  34. int exitCode = ToolRunner.run(new SmallFilesToSequenceFileConverter(), args);
  35. System.exit(exitCode);
  36. }
  37. }

     文本输入:

        a. TextInputFormat  行首偏移量:行内容

          扩展:如何处理跨行Block和InputSplit

        b. KeyValueTextInputFormat  以tab划分一行的key value

        c. NLineInputFormat  让每个map收到定义的相同行数,每个分片只包含N行

     二进制输入:

        Hadoop的MapReduce不只是可以处理文本信息,还可以处理二进制格式,通过会用以下几个类:

          SequenceFileInputFormat,处理SequenceFile 和 MapFile的文件类型;

          SequenceFileAsTextInputFormat 是 SequenceFileInputFormat的扩展,它将SequenceFile的键值转换为Text对象,这个转化是通过键和值上调用toString()方法实现。

          SequenceFileAsBinaryInputFormat 也是SequenceFileInputFormat的扩展,它将SequenceFile的键值作为二进制对象。它们被封装为BytesWritable对象,因而可以任意解释这些字节数组。

      多输入MultipleInputs:

        它可为每条输入路径指定InputForamt 和 Mapper:       

  1. MutipleInputs.addInputPath(job , ncdcInputPath, TextInputFormat.class, MaxTemperatureMapper.class);
  2. MutipleInputs.addInputPath(job ,metofficeInputPath, TextInputFormat.class, MetofficeMaxTemperatureMapper.class);
  3.  
  4. //MutipleInputs还有一个重载,当只用一个Mapper时
  5. public static void addInputPath(Job job, Path path, class<? extends InputFormat> inputFormatClass);  

        它取代了FileInputFormat.addInputPath() 和 job.setMapperClass()的调用。

      合成输入:CompositeInputFormat ( join )、CombineFileInputFormat ( 多个小文件合并成一个split输入,是一个抽象类 )

           

二、输出格式

继承图:  

    

  文体输出TextOutputFormat:

  默认的输出是文本输出TextOutputFormat,它把每条记录写为文本行,它调用toString()方法把key value转化为字符串。

  与之对应的输入为KeyValueTextInputFormat;

  二进制输出:与输入对应。

多输出:

  默认一个reducer生成一个输出文件,命名为part-r-00000;

  有时需要对输出的文件名进行控制 或 让每个redeucer输出多个文件,可利用 MultipleOutputFormat 类;

  范例:按气象站来区分气象数据,各个气象站输出到不同的文件中:

    方法一:可利用每个reducer创建一个输出文件的特点,通过设置多个分区,来输出到各个文件,这样做有两点不好:

          a. 分区个数必须预先就知道;可能有空reducer,可能有的获取不到气象站信息导致值丢失;

          b. 每个reducer处理一个气象站,可能需要过多的reducer,也会有严重的数据倾斜问题;

    方法二:使用 MutipleOutputs 类:

  1. public class PartitionByStationUsingMultipleOutputs extends Configured implements Tool {
  2. static class StationMapper extends Mapper<LongWritable, Text, Text, Text> {
  3. private NcdcRecordParser parser = new NcdcRecordParser();
  4.  
  5. @Override
  6. protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
  7. parser.parse(value);
  8. context.write(new Text(parser.getStationId()), value);
  9. }
  10. }
  11.  
  12. static class MultipleOutputsReducer extends Reducer<Text, Text, NullWritable, Text> {
  13. private MultipleOutputs<NullWritable, Text> multipleOutputs;
  14.  
  15. @Override
  16. protected void setup(Context context) throws IOException, InterruptedException {
  17. multipleOutputs = new MultipleOutputs<NullWritable, Text>(context);
  18. }
  19.  
  20. @Override
  21. protected void reduce(Text key, Iterable<Text> values, Context context)
  22. throws IOException, InterruptedException {
  23. for (Text value : values) {
  24. multipleOutputs.write(NullWritable.get(), value, key.toString());
  25. }
  26. }
  27.  
  28. @Override
  29. protected void cleanup(Context context) throws IOException, InterruptedException {
  30. multipleOutputs.close();
  31. }
  32. }
  33.  
  34. @Override
  35. public int run(String[] args) throws Exception {
  36. Job job = JobBuilder.parseInputAndOutput(this, getConf(), args);
  37. if (job == null) {
  38. return -1;
  39. }
  40. job.setMapperClass(StationMapper.class);
  41. job.setMapOutputKeyClass(Text.class);
  42. job.setReducerClass(MultipleOutputsReducer.class);
  43. job.setOutputKeyClass(NullWritable.class);
  44. return job.waitForCompletion(true) ? 0 : 1;
  45. }
  46.  
  47. public static void main(String[] args) throws Exception {
  48. int exitCode = ToolRunner.run(new PartitionByStationUsingMultipleOutputs(), args);
  49. System.exit(exitCode);
  50. }
  51. }

        输出文件结果如下:          

          output/010010-99999-r-00027

          output/010050-99999-r-00013

          output/010100-99999-r-00015

          output/010280-99999-r-00014

    方法三:MultipleOutputFormat(旧API已移弃)的使用    

  1. public static class WordCountOutputFormat extends MultipleOutputFormat<Text, IntWritable> {
  2. private TextOutputFormat<Text, IntWritable> output = null;
  3.  
  4. @Override
  5. protected RecordWriter<Text, IntWritable> getBaseRecordWriter(FileSystem fs, JobConf job, String name,
  6. Progressable arg3) throws IOException {
  7. if (output == null) {
  8. output = new TextOutputFormat<Text, IntWritable>();
  9. }
  10. return output.getRecordWriter(fs, job, name, arg3);
  11. }
  12.  
  13. @Override
  14. protected String generateFileNameForKeyValue(Text key, IntWritable value, String name) {
  15. char c = key.toString().toLowerCase().charAt(0);
  16. if (c >= 'a' && c <= 'z') {
  17. return c + ".txt";
  18. }
  19. return "result.txt";
  20. }
  21. }

Hadoop MapReduce输入输出类型的更多相关文章

  1. MapReduce输入输出类型、格式及实例

    输入格式 1.输入分片与记录 2.文件输入 3.文本输入 4.二进制输入 5.多文件输入 6.数据库格式输入 1.输入分片与记录 1.JobClient通过指定的输入文件的格式来生成数据分片Input ...

  2. mapreduce 输入输出类型

    默认的mapper是IdentityMapper,默认的reducer是IdentityReducer,它们将输入的键和值原封不动地写到输出中. 默认的partitioner是HashPartitin ...

  3. 023_数量类型练习——Hadoop MapReduce手机流量统计

    1) 分析业务需求:用户使用手机上网,存在流量的消耗.流量包括两部分:其一是上行流量(发送消息流量),其二是下行流量(接收消息的流量).每种流量在网络传输过程中,有两种形式说明:包的大小,流量的大小. ...

  4. Hadoop MapReduce 二次排序原理及其应用

    关于二次排序主要涉及到这么几个东西: 在0.20.0 以前使用的是 setPartitionerClass setOutputkeyComparatorClass setOutputValueGrou ...

  5. Hadoop 4、Hadoop MapReduce的工作原理

    一.MapReduce的概念 MapReduce是hadoop的核心组件之一,hadoop要分布式包括两部分,一是分布式文件系统hdfs,一部是分布式计算框就是mapreduce,两者缺一不可,也就是 ...

  6. Hadoop MapReduce开发最佳实践(上篇)

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  7. Hadoop MapReduce工作原理

    在学习Hadoop,慢慢的从使用到原理,逐层的深入吧 第一部分:MapReduce工作原理   MapReduce 角色 •Client :作业提交发起者. •JobTracker: 初始化作业,分配 ...

  8. Hadoop Mapreduce运行流程

    Mapreduce的运算过程为两个阶段: 第一个阶段的map task相互独立,完全并行: 第二个阶段的reduce task也是相互独立,但依赖于上一阶段所有map task并发实例的输出: 这些t ...

  9. Hadoop Mapreduce 案例 wordcount+统计手机流量使用情况

    mapreduce设计思想 概念:它是一个分布式并行计算的应用框架它提供相应简单的api模型,我们只需按照这些模型规则编写程序,即可实现"分布式并行计算"的功能. 案例一:word ...

随机推荐

  1. bzoj2120 数颜色 莫队 带修改

    [bzoj2120]数颜色 Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔 ...

  2. JSP学习笔记(七十八):struts2中s:select标签的使用

    1.第一个例子: <s:select list="{'aa','bb','cc'}" theme="simple" headerKey="00& ...

  3. CodeForces 731C Socks

    http://codeforces.com/problemset/problem/731/C 并查集+贪心 将要求颜色相同的袜子序号放入一个集合中 贪心:然后统计这个集合中出现次数最多但颜色 可以得到 ...

  4. Gauss 高斯消元

    高斯消元…… (裸的暴力) 如果你有一个n元的方程组你会怎么办? Ans:直接用初中的解方程组的方法呀! 没错,直接暴力加减消元.那什么是“高斯消元”?说白了,就是普通的加减消元罢了. 本人再考场上打 ...

  5. Python入门--7--处理数据时学习到的东西

    一.数据导入(这里使用的是pands包) import pands as pd wenjian = pd.read_csv('路径') 二.数据变换 print wenjian.head()    # ...

  6. Scrapy学习-5-下载图片实例

    1. 在项目下创建一个images文件用于存放图片 2. 载图片相关模块 pip install pillow 3.修改配置文件,激活pipelines ITEM_PIPELINES = { 'Art ...

  7. ELK之收集Nginx、Tomcat的json格式日志

    1.安装Nginx yum -y install nginx vim /etc/nginx/nginx.conf # 修改日志格式为json格式,并创建一个nginxweb的网站目录 log_form ...

  8. Google代码风格配置文件(Java)(IDEA/Eclipse)

    官网:http://www.cnblogs.com/EasonJim/p/7837474.html 下载: 安装: IDEA/Eclipse导入相应文件即可. 说明: Google代码风格文件的缩进是 ...

  9. 4.JAVA语言基础部分—枚举与泛型

    枚举 //定义枚举 enum MyEnum{ ITEM_A, ITEM_B } public static void main(String[] args) { //values()获取所枚举项的集合 ...

  10. Oracle EBS - 工单状态

    Job status update 1. Job的几种状态 unreleased --未核发 released--已核发 complete --完成 complete no charges--完成不计 ...