MapReduce-XML处理-自定义OutputFormat以及自定义RecordWriter

友情提示:更多有关大数据、人工智能方面技术文章请关注博主个人微信公众号:高级大数据架构师

这一篇紧接上一篇博客《MapReduce-XML处理-自定义InputFormat及自定义RecordReader》,上一篇是说明InputFormat和RecordReader,这里说明OutputFormat以及RecordWriter的定制,下面是
这次测试的要求:
输入数据:
<configuration>
  <property>
    <name>hadoop.kms.authentication.type</name>
    <value>simple</value>
  </property>
  <property>
    <name>hadoop.kms.authentication.kerberos.keytab</name>
    <value>${user.home}/kms.keytab</value>
  </property>
  <property>
    <name>hadoop.kms.authentication.kerberos.principal</name>
    <value>HTTP/localhost</value>
  </property>
  <property>
    <name>hadoop.kms.authentication.kerberos.name.rules</name>
    <value>DEFAULT</value>
  </property>
</configuration>
实现的结果:把上述XML文件中的value的值倒序,然后按照XML标签的格式输出,如下:
<name>hadoop.kms.authentication.kerberos.keytab</name>
<value>batyek.smk/}emoh.resu{$</value>
<name>hadoop.kms.authentication.kerberos.name.rules</name>
<value>TLUAFED</value>
<name>hadoop.kms.authentication.kerberos.principal</name>
<value>tsohlacol/PTTH</value>
<name>hadoop.kms.authentication.type</name>
<value>elpmis</value>
由于代码量过多,这里就不贴出上一篇说明InputFormat和RecordReader的代码了,如果要做完整的测试到上一篇找代码
《MapReduce-xml文件的处理-定制InputFormat及定制RecordReader》。InputFormat、RecordReader、mapper的代码在这
里就不贴出来了。
定制步骤:
扩展OutputFormat和RecordWriter这两类或其子类,其功能是:
OutputFormat用于验证数据接收器的属性,RecordWriter用于将reduce对象的输出结果导入数据接收器中。
首先扩展OutputFormat类其要实现的内容为:
1.public abstract class OutputFormat<K, V>
K,V为定义reduce输入键和值的类型
2.public abstract RecordWriter<K, V> getRecordWriter(TaskAttemptContext context ) throws IOException, InterruptedException;
创建一个RecordWriter实例将数据写入到目标
3.public abstract void checkOutputSpecs(JobContext context ) throws IOException, InterruptedException;
验证与MapReduce作业相关联的输出信息是否下确
4.public abstract OutputCommitter getOutputCommitter(TaskAttemptContext context ) throws IOException, InterruptedException;
获取相关OutputCommitter。当所有任务成功和作业完成后,OutputCommitters负责在最后将结果输出
然后扩展RecordWriter类,其实现的内容为:
1.public abstract class RecordWriter<K, V>
K,V为定义reduce输入键和值的类型
2.public abstract void write(K key, V value ) throws IOException, InterruptedException;
将一个逻辑键/值对写到接收器。
3.public abstract void close(TaskAttemptContext context ) throws IOException, InterruptedException;
清理任何与目标数据接收器相关的资源

 

 

定制OutputFormat:这里是扩展OutputFormat的子类FileOutputFormat

 

 

 

[java] view plain copy

  1. import java.io.DataOutputStream;  
  2. import java.io.IOException;  
  3. import org.apache.hadoop.conf.Configuration;  
  4. import org.apache.hadoop.fs.FSDataOutputStream;  
  5. import org.apache.hadoop.fs.FileSystem;  
  6. import org.apache.hadoop.fs.Path;  
  7. import org.apache.hadoop.io.Text;  
  8. import org.apache.hadoop.io.compress.CompressionCodec;  
  9. import org.apache.hadoop.io.compress.GzipCodec;  
  10. import org.apache.hadoop.mapreduce.RecordWriter;  
  11. import org.apache.hadoop.mapreduce.TaskAttemptContext;  
  12. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  13. import org.apache.hadoop.util.ReflectionUtils;  
  14.   
  15. public class XMLOutputFormat extends FileOutputFormat<Text, Text> {  
  16.     @Override  
  17.     public RecordWriter<Text, Text> getRecordWriter(TaskAttemptContext job) throws IOException, InterruptedException {  
  18.         /** 
  19.          * 为创建FSDataOutputStream做准备,判断是否设置了输出压缩 
  20.          * 如果有提取扩展名 
  21.          */  
  22.         Configuration conf = job.getConfiguration();  
  23.         boolean isCompressed = getCompressOutput(job);  
  24.         CompressionCodec codec = null;  
  25.         String extension = "";  
  26.         if (isCompressed) {  
  27.             Class<? extends CompressionCodec> codecClass = getOutputCompressorClass(job, GzipCodec.class);  
  28.             codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, conf);  
  29.             extension = codec.getDefaultExtension();  
  30.         }  
  31.         Path file = getDefaultWorkFile(job, extension);  
  32.         FileSystem fs = file.getFileSystem(conf);  
  33.         /** 
  34.          * 创建RecordWriter,并把准备好的输出流传入RecordWriter以便其输出定制格式换 
  35.          * key,value到指定的文件中 
  36.          */  
  37.         if (!isCompressed) {  
  38.             FSDataOutputStream fileOut = fs.create(file, false);  
  39.             return new XMLRecordWriter(fileOut);  
  40.         } else {  
  41.             FSDataOutputStream fileOut = fs.create(file, false);  
  42.             return new XMLRecordWriter(new DataOutputStream( codec.createOutputStream(fileOut)));  
  43.         }  
  44.     }  
  45. }  

定制RecordWriter:

 

 

[java] view plain copy

  1. import java.io.DataOutputStream;  
  2. import java.io.IOException;  
  3. import java.io.UnsupportedEncodingException;  
  4. import org.apache.hadoop.io.Text;  
  5. import org.apache.hadoop.mapreduce.RecordWriter;  
  6. import org.apache.hadoop.mapreduce.TaskAttemptContext;  
  7.   
  8. public class XMLRecordWriter extends RecordWriter<Text, Text> {  
  9.     protected DataOutputStream out;  
  10.     private static final String utf8 = "UTF-8";  
  11.     private static final byte[] newline;  
  12.     private String nameTag;  
  13.     private String valueTag;  
  14.     private Text key_ = new Text();  
  15.     private Text value_ = new Text();  
  16.     static {  
  17.       try {  
  18.           /** 
  19.            * 定义换行符 
  20.            */  
  21.         newline = "\n".getBytes(utf8);  
  22.       } catch (UnsupportedEncodingException uee) {  
  23.         throw new IllegalArgumentException("can't find " + utf8 + " encoding");  
  24.       }  
  25.     }  
  26.     @Override  
  27.     public synchronized void close(TaskAttemptContext arg0) throws IOException,  
  28.             InterruptedException {  
  29.         out.close();  
  30.     }  
  31.     /** 
  32.      * 实现输出定制的核心方法,在reduce调用write方法后,根据传入的key,value 
  33.      * 来做相应形式的输出 
  34.      */  
  35.     @Override  
  36.     public synchronized void write(Text key, Text value) throws IOException,  
  37.             InterruptedException {  
  38.         boolean nullKey = key == null;   
  39.         boolean nullValue = value == null;  
  40.         /** 
  41.          * 判断key,value是否都为空如果都为空则不输出 
  42.          */  
  43.         if (nullKey && nullValue) {  
  44.             return;  
  45.         }  
  46.         /** 
  47.          * 如果key不为空怎么输出 
  48.          */  
  49.         if (!nullKey) {  
  50.             nameTag = "<name>" + key.toString() +"</name>";  
  51.             key_.set(nameTag.getBytes());  
  52.             writeObject(key_);  
  53.         }  
  54.         if (!(nullKey || nullValue)) {  
  55.             out.write(newline);  
  56.         }  
  57.         /** 
  58.          * 如果value不为空怎么输出 
  59.          */  
  60.         if (!nullValue) {  
  61.             valueTag = "<value>" + value.toString() + "</value>";  
  62.             value_.set(valueTag.getBytes());  
  63.             writeObject(value_);  
  64.         }  
  65.         out.write(newline);  
  66.     }  
  67.     /** 
  68.      * 调用以下方法把对象写入HDFS 
  69.      * @param o 
  70.      * @throws IOException 
  71.      */  
  72.     private void writeObject(Object o) throws IOException {  
  73.         if (o instanceof Text) {  
  74.             Text to = (Text) o;  
  75.             out.write(to.getBytes(), 0, to.getLength());  
  76.         } else {  
  77.             out.write(o.toString().getBytes(utf8));  
  78.         }  
  79.     }  
  80.     public XMLRecordWriter(DataOutputStream out ) {  
  81.         this.out = out;  
  82.     }  
  83. }  

reduce阶段:

 

[java] view plain copy

  1. import java.io.IOException;  
  2. import org.apache.hadoop.io.Text;  
  3. import org.apache.hadoop.mapreduce.Reducer;  
  4.   
  5. public class XMLReducer extends Reducer<Text, Text, Text, Text>{  
  6.     private Text val_ = new Text();  
  7.     private StringBuffer sb = new StringBuffer();  
  8.     @Override  
  9.     protected void reduce(Text key, Iterable<Text> value, Context context)  
  10.             throws IOException, InterruptedException {  
  11.         for(Text val: value) {  
  12.             //倒序的处理也可以放到RecordWriter中去实现  
  13.             sb.append(val.toString());  
  14.             val_.set(sb.reverse().toString());  
  15.             context.write(key, val_);  
  16.             sb.delete(0, sb.length());  
  17.         }  
  18.     }  
  19. }  

启动函数:

 

 

[java] view plain copy

  1. import org.apache.hadoop.conf.Configuration;  
  2. import org.apache.hadoop.fs.Path;  
  3. import org.apache.hadoop.io.Text;  
  4. import org.apache.hadoop.mapreduce.Job;  
  5. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  6. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  7.   
  8. public class JobMain {  
  9.     public static void main(String[] args) throws Exception{  
  10.         Configuration configuration = new Configuration();  
  11.         configuration.set("key.value.separator.in.input.line"" ");  
  12.         configuration.set("xmlinput.start""<property>");  
  13.         configuration.set("xmlinput.end""</property>");  
  14.         Job job = new Job(configuration, "xmlread-job");  
  15.         job.setJarByClass(JobMain.class);  
  16.         job.setMapperClass(XMLMapper.class);  
  17.         job.setMapOutputKeyClass(Text.class);  
  18.         job.setMapOutputValueClass(Text.class);  
  19.         //设置输入格式处理类  
  20.         job.setInputFormatClass(XMLInputFormat.class);  
  21.         job.setNumReduceTasks(1);  
  22.         job.setReducerClass(XMLReducer.class);  
  23.         //设置输出格式处理类  
  24.         job.setOutputFormatClass(XMLOutputFormat.class);  
  25.         FileInputFormat.addInputPath(job, new Path(args[0]));  
  26.         Path output = new Path(args[1]);  
  27.         FileOutputFormat.setOutputPath(job, output);  
  28.         output.getFileSystem(configuration).delete(output, true);  
  29.         System.exit(job.waitForCompletion(true) ? 01);  
  30.     }  
  31. }  

运行结果:

 


结论:

这一个实例是对上一篇博客《MapReduce-XML处理-定制InputFormat及定制RecordReader》的一个扩展,这里没有贴出Mapper,InputFormat以及RecordReader的代码,如果要运行出结果map端的实现代码请参考上一篇代码。下一篇会说明mapreduce中join的的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值