Hadoop的读和写


   Mapreduce处理原则:将输入数据分割成块(称输入分片),在各台计算机上并行处理。HDFS按块存储文件,并分布在多台计算机上,如果每个分片/块都由它所驻留的机器处理,就实现了并行。HDFS再在多个节点上复制数据块,MapReduce可以选择任意一个包含分片/数据库副本的节点。

InputFormat

    Hadoop分割与读取输入文件的方式,被定义在InputFormat的一个实现中。TextInputFormat是InputFormat的默认实现,返回的键为每行的字节偏移量。

 TextInputFormat(默认)  在文本文件中的每一行均为一个记录,键(key)为一行的字节偏移,而值(value)为一行的内容  Key:LongWritable
Value:Text
 KeyValueTextInputFormat  在文本文件中的每一行均为一个记录,以每一行的第一个分隔符为界,分隔符之前的是键(key),之后的是值(value),分离器在属性key.value.separator.in.input.line中设定,默认为制表符(\t)  Key:Text
Value:Text
 SequenceFileInputFormat  用于读取序列文件的InputFormat,键和值由用户定义,序列文件为Hadoop专用的压缩二进制文件格式,它专用于一个MapReduce作业和其他MapReduce作业之间传送数据  Key:K(用户定义)
Value:V(用户定义)
 NLineInputFormat 与TextInputFormat相同,但每个分片一定有N行,N在属性mapred.line.input.format.linespermap中设定,默认为1  Key:LongWritable
Value:Text
表1主要的InputFormat类

※输出和输入类型必须匹配,Mapper实现和map()方法均须采用正确的输入类型

生成一个定制的InputFormat——InputSplit和RecordReader


   若要用与InputFormat类不同的方式读和取数据,必须编写自定义的InputFormat类,InputFormat类的两个方法:
   
 publicinterface InputFormat{
       //确定所有用于输入数据的文件,并将之分割为输入分片,每个map任务分配一片,job是要分割的东西,numSplits是要分割的份数
       InputSplit[] getSplits(JobConf job, int numSplits) throwsIOException;
       //提供一个对线(RecordReader)循环提取给定分片中的记录,并解析每个记录为预定义类型的键与值
       RecordReader getRecordReader(
           InputSplit split,
           JobConf job,
           Reporter reporter
       ) throws IOException;
    }
   在创建时,最好从FileInputFormat中继承一个子类(如表1中类),它实现了getSplits方法,把数据粗略的分片,数目在numSplit中定,大小一般为64MB,还保留了getRecordReader让子类填写。
   FileInputFormat中有一定数量的protected方法,可以通过覆盖改变行为。
   使用FileInputFormat主要在定制RecordReader→把一个输入分片解析为记录→记录解析为键/值对。FileInputFormat接口如下:
    publicinterface RecordReader{
       boolean next(K key, V value) throws IOException;
       K createKey();
       V createValue();
       long getPos() throws IOException;
       public void close() throws IOException;
       float getProgress() throws IOException;
    }

   RecordReader不用自己去写,用Hadoop所提供的类去实现,一般基于现有实现的封装,并把大多数的操作方法放在next()中。

例:把URL作为URLWritable类型,扩展FileInputFormat,生成InputFormat类,并实现一个factory方法,返回RecordReader。

package org.apache.hadoop.examples;

import java.io.IOException;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.FileInputFormat;
import org.apache.hadoop.mapred.FileSplit;
import org.apache.hadoop.mapred.InputSplit;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.RecordReader;
import org.apache.hadoop.mapred.Reporter;

public class TimeUrlTextInputFormat extends FileInputFormat{
   @Override
    publicRecordReader getRecordReader(InputSplit input, JobConf job,Reporter reporter)
          throwsIOException{   
       return newTimeUrlLineRecordReader(job, (FileSplit)input);
    }
}

package org.apache.hadoop.examples;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.FileSplit;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.KeyValueLineRecordReader;
import org.apache.hadoop.mapred.RecordReader;

public class URLWritable {

    protectedURL url;
   
    publicURLWritable(){}
   
    publicURLWritable(URL url){
       this.url =url;
    }
   
    public voidwrite(DataOutput out) throws IOException{
      out.writeUTF(url.toString());
    }
   
    public voidreadFields(DataInput in) throws IOException{
       url = newURL(in.readUTF());
    }
   
    public voidset(String s) throws MalformedURLException{
       url = newURL(s);
    }
}

class TimeUrlLineRecordReader implements RecordReader{

    privateKeyValueLineRecordReader lineReader;
    private TextlineKey,lineValue;
   
    publicTimeUrlLineRecordReader(JobConf job, FileSplit split) throwsIOException{
       lineReader =new KeyValueLineRecordReader(job, split);
      
       lineKey =lineReader.createKey();
       lineValue =lineReader.createValue();   
    }
   
   @Override
    public voidclose() throws IOException {
      lineReader.close();
    }

   @Override
    public TextcreateKey() {
       return newText("");
    }

   @Override
    publicURLWritable createValue() {
       return newURLWritable();
    }

   @Override
    public longgetPos() throws IOException {
       returnlineReader.getPos();
    }

   @Override
    public floatgetProgress() throws IOException {
       returnlineReader.getProgress();
    }

   @Override
    publicboolean next(Text key, URLWritable value) throws IOException{
       if(!lineReader.next(lineKey, lineValue)){
       returnfalse;
       }
      
      key.set(lineKey);
      value.set(lineValue.toString());
      
       returntrue;
   }   
}


Output Format

   输出数据到文件,输出文件放在一个公用目录中,通常命名为part-nnnn,nnnn是reduce分区id,RecordWriter将输出格式化,RecordReader对输入格式解析。

 TextOutputFormat(默认) 将每个记录写为一行文本,键和值以字符串的形式写入,并以制表符(/t)分割,这个分隔符可以在属性mapred.textoutputformat.separator中修改
 SequenceFileOutputFormat  以Hadoop专有序列文件格式写入键/值对,与SequenceFileInputFormat配合使用
 NullOutputFormat  无输出
表2主要的OutputFormat类

定制OutputFormat

   调用JobConf中的setOutputFFormat(),JobConf包含对MapReduce作业的配置信息。

你可能感兴趣的:(hadoop)