1. 自定义inputFormat

1.1 需求

无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案

1.2 分析

小文件的优化无非以下几种方式:

1、 在数据采集的时候,就将小文件或小批数据合成大文件再上传HDFS

2、 在业务处理之前,在HDFS上使用mapreduce程序对小文件进行合并

3、 在mapreduce处理时,可采用combineInputFormat提高效率

实现

本节实现的是上述第二种方式

程序的核心机制:

自定义一个InputFormat

改写RecordReader,实现一次读取一个完整文件封装为KV

在输出时使用SequenceFileOutPutFormat输出合并文件

代码如下:

自定义InputFromat

  1. package cn.itcast.bigdata.combinefile;
  2.  
  3. import java.io.IOException;
  4.  
  5. import org.apache.hadoop.fs.Path;
  6. import org.apache.hadoop.io.BytesWritable;
  7. import org.apache.hadoop.io.NullWritable;
  8. import org.apache.hadoop.mapreduce.InputSplit;
  9. import org.apache.hadoop.mapreduce.JobContext;
  10. import org.apache.hadoop.mapreduce.RecordReader;
  11. import org.apache.hadoop.mapreduce.TaskAttemptContext;
  12. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  13.  
  14. public class WholeFileInputFormat extends FileInputFormat<NullWritable, BytesWritable>{
  15.  
  16. @Override
  17. protected boolean isSplitable(JobContext context, Path file) {
  18. return false;
  19. }
  20.  
  21. @Override
  22. public RecordReader<NullWritable, BytesWritable> createRecordReader(
  23. InputSplit split, TaskAttemptContext context) throws IOException,
  24. InterruptedException {
  25. WholeFileRecordReader reader = new WholeFileRecordReader();
  26. reader.initialize(split, context);
  27. return reader;
  28. }
  29.  
  30. }
  1. package cn.itcast.bigdata.combinefile;
  2.  
  3. import java.io.IOException;
  4.  
  5. import org.apache.hadoop.conf.Configuration;
  6. import org.apache.hadoop.fs.FSDataInputStream;
  7. import org.apache.hadoop.fs.FileSystem;
  8. import org.apache.hadoop.fs.Path;
  9. import org.apache.hadoop.io.BytesWritable;
  10. import org.apache.hadoop.io.IOUtils;
  11. import org.apache.hadoop.io.NullWritable;
  12. import org.apache.hadoop.mapreduce.InputSplit;
  13. import org.apache.hadoop.mapreduce.RecordReader;
  14. import org.apache.hadoop.mapreduce.TaskAttemptContext;
  15. import org.apache.hadoop.mapreduce.lib.input.FileSplit;
  16.  
  17. /**
  18. *
  19. * RecordReader的核心工作逻辑:
  20. * 通过nextKeyValue()方法去读取数据构造将返回的key value
  21. * 通过getCurrentKey 和 getCurrentValue来返回上面构造好的key和value
  22. *
  23. *
  24. * @author
  25. *
  26. */
  27. class WholeFileRecordReader extends RecordReader<NullWritable, BytesWritable> {
  28. private FileSplit fileSplit;
  29. private Configuration conf;
  30. private BytesWritable value = new BytesWritable();
  31. private boolean processed = false;
  32.  
  33. @Override
  34. public void initialize(InputSplit split, TaskAttemptContext context)
  35. throws IOException, InterruptedException {
  36. this.fileSplit = (FileSplit) split;
  37. this.conf = context.getConfiguration();
  38. }
  39.  
  40. @Override
  41. public boolean nextKeyValue() throws IOException, InterruptedException {
  42. if (!processed) {
  43. byte[] contents = new byte[(int) fileSplit.getLength()];
  44. Path file = fileSplit.getPath();
  45. FileSystem fs = file.getFileSystem(conf);
  46. FSDataInputStream in = null;
  47. try {
  48. in = fs.open(file);
  49. IOUtils.readFully(in, contents, 0, contents.length);
  50. value.set(contents, 0, contents.length);
  51. } finally {
  52. IOUtils.closeStream(in);
  53. }
  54. processed = true;
  55. return true;
  56. }
  57. return false;
  58. }
  59.  
  60. @Override
  61. public NullWritable getCurrentKey() throws IOException,
  62. InterruptedException {
  63. return NullWritable.get();
  64. }
  65.  
  66. @Override
  67. public BytesWritable getCurrentValue() throws IOException,
  68. InterruptedException {
  69. return value;
  70. }
  71.  
  72. /**
  73. * 返回当前进度
  74. */
  75. @Override
  76. public float getProgress() throws IOException {
  77. return processed ? 1.0f : 0.0f;
  78. }
  79.  
  80. @Override
  81. public void close() throws IOException {
  82. // do nothing
  83. }
  84. }
  1. package cn.itcast.bigdata.combinefile;
  2.  
  3. import java.io.IOException;
  4.  
  5. import org.apache.hadoop.conf.Configuration;
  6. import org.apache.hadoop.conf.Configured;
  7. import org.apache.hadoop.fs.Path;
  8. import org.apache.hadoop.io.BytesWritable;
  9. import org.apache.hadoop.io.NullWritable;
  10. import org.apache.hadoop.io.Text;
  11. import org.apache.hadoop.mapreduce.InputSplit;
  12. import org.apache.hadoop.mapreduce.Job;
  13. import org.apache.hadoop.mapreduce.Mapper;
  14. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  15. import org.apache.hadoop.mapreduce.lib.input.FileSplit;
  16. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  17. import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;
  18. import org.apache.hadoop.util.GenericOptionsParser;
  19. import org.apache.hadoop.util.Tool;
  20. import org.apache.hadoop.util.ToolRunner;
  21.  
  22. public class SmallFilesToSequenceFileConverter extends Configured implements Tool {
  23. static class SequenceFileMapper extends
  24. Mapper<NullWritable, BytesWritable, Text, BytesWritable> {
  25. private Text filenameKey;
  26.  
  27. @Override
  28. protected void setup(Context context) throws IOException,
  29. InterruptedException {
  30. InputSplit split = context.getInputSplit();
  31. Path path = ((FileSplit) split).getPath();
  32. filenameKey = new Text(path.toString());
  33. }
  34.  
  35. @Override
  36. protected void map(NullWritable key, BytesWritable value,
  37. Context context) throws IOException, InterruptedException {
  38. context.write(filenameKey, value);
  39. }
  40. }
  41.  
  42. @Override
  43. public int run(String[] args) throws Exception {
  44. Configuration conf = new Configuration();
  45. /*System.setProperty("HADOOP_USER_NAME", "hadoop");*/
  46. String[] otherArgs = new GenericOptionsParser(conf, args)
  47. .getRemainingArgs();
  48. if (otherArgs.length != 2) {
  49. System.err.println("Usage: combinefiles <in> <out>");
  50. System.exit(2);
  51. }
  52.  
  53. Job job = Job.getInstance(conf,"combine small files to sequencefile");
  54. job.setJarByClass(SmallFilesToSequenceFileConverter.class);
  55.  
  56. job.setInputFormatClass(WholeFileInputFormat.class);
  57. job.setOutputFormatClass(SequenceFileOutputFormat.class);
  58. job.setOutputKeyClass(Text.class);
  59. job.setOutputValueClass(BytesWritable.class);
  60. job.setMapperClass(SequenceFileMapper.class);
  61.  
  62. FileInputFormat.setInputPaths(job, new Path(args[0]));
  63. FileOutputFormat.setOutputPath(job, new Path(args[1]));
  64.  
  65. return job.waitForCompletion(true) ? 0 : 1;
  66. }
  67.  
  68. public static void main(String[] args) throws Exception {
  69. args=new String[]{"c:/wordcount/smallinput","c:/wordcount/smallout"};
  70. int exitCode = ToolRunner.run(new SmallFilesToSequenceFileConverter(),
  71. args);
  72. System.exit(exitCode);
  73.  
  74. }
  75. }

自定义outputFormat

需求

现有一些原始日志需要做增强解析处理,流程:

1、 从原始日志文件中读取数据

2、 根据日志中的一个URL字段到外部知识库中获取信息增强到原始日志

3、 如果成功增强,则输出到增强结果目录;如果增强失败,则抽取原始数据中URL字段输出到待爬清单目录

2.2 分析

程序的关键点是要在一个mapreduce程序中根据数据的不同输出两类结果到不同目录,这类灵活的输出需求可以通过自定义outputformat来实现

2.3 实现

实现要点:

1、 在mapreduce中访问外部资源

2、 自定义outputformat,改写其中的recordwriter,改写具体输出数据的方法write()

代码实现如下:

数据库获取数据的工具

  1. package cn.itcast.bigdata.mr.logenhance;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.ResultSet;
  5. import java.sql.Statement;
  6. import java.util.HashMap;
  7. import java.util.Map;
  8.  
  9. public class DBLoader {
  10.  
  11. public static void dbLoader(Map<String, String> ruleMap) throws Exception {
  12.  
  13. Connection conn = null;
  14. Statement st = null;
  15. ResultSet res = null;
  16.  
  17. try {
  18. Class.forName("com.mysql.jdbc.Driver");
  19. conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/urldb", "root", "root");
  20. st = conn.createStatement();
  21. res = st.executeQuery("select url,content from url_rule");
  22. while (res.next()) {
  23. ruleMap.put(res.getString(1), res.getString(2));
  24. }
  25.  
  26. } finally {
  27. try{
  28. if(res!=null){
  29. res.close();
  30. }
  31. if(st!=null){
  32. st.close();
  33. }
  34. if(conn!=null){
  35. conn.close();
  36. }
  37.  
  38. }catch(Exception e){
  39. e.printStackTrace();
  40. }
  41. }
  42.  
  43. }
  44.  
  45. }
  1. package cn.itcast.bigdata.mr.logenhance;
  2.  
  3. import java.io.IOException;
  4.  
  5. import org.apache.hadoop.fs.FSDataOutputStream;
  6. import org.apache.hadoop.fs.FileSystem;
  7. import org.apache.hadoop.fs.Path;
  8. import org.apache.hadoop.io.NullWritable;
  9. import org.apache.hadoop.io.Text;
  10. import org.apache.hadoop.mapreduce.RecordWriter;
  11. import org.apache.hadoop.mapreduce.TaskAttemptContext;
  12. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  13.  
  14. /**
  15. * maptask或者reducetask在最终输出时,先调用OutputFormat的getRecordWriter方法拿到一个RecordWriter
  16. * 然后再调用RecordWriter的write(k,v)方法将数据写出
  17. *
  18. * @author
  19. *
  20. */
  21. public class LogEnhanceOutputFormat extends FileOutputFormat<Text, NullWritable> {
  22.  
  23. @Override
  24. public RecordWriter<Text, NullWritable> getRecordWriter(TaskAttemptContext context) throws IOException, InterruptedException {
  25.  
  26. FileSystem fs = FileSystem.get(context.getConfiguration());
  27.  
  28. Path enhancePath = new Path("D:/temp/en/log.dat");
  29. Path tocrawlPath = new Path("D:/temp/crw/url.dat");
  30.  
  31. FSDataOutputStream enhancedOs = fs.create(enhancePath);
  32. FSDataOutputStream tocrawlOs = fs.create(tocrawlPath);
  33.  
  34. return new EnhanceRecordWriter(enhancedOs, tocrawlOs);
  35. }
  36.  
  37. /**
  38. * 构造一个自己的recordwriter
  39. *
  40. * @author
  41. *
  42. */
  43. static class EnhanceRecordWriter extends RecordWriter<Text, NullWritable> {
  44. FSDataOutputStream enhancedOs = null;
  45. FSDataOutputStream tocrawlOs = null;
  46.  
  47. public EnhanceRecordWriter(FSDataOutputStream enhancedOs, FSDataOutputStream tocrawlOs) {
  48. super();
  49. this.enhancedOs = enhancedOs;
  50. this.tocrawlOs = tocrawlOs;
  51. }
  52.  
  53. @Override
  54. public void write(Text key, NullWritable value) throws IOException, InterruptedException {
  55. String result = key.toString();
  56. // 如果要写出的数据是待爬的url,则写入待爬清单文件 /logenhance/tocrawl/url.dat
  57. if (result.contains("tocrawl")) {
  58. tocrawlOs.write(result.getBytes());
  59. } else {
  60. // 如果要写出的数据是增强日志,则写入增强日志文件 /logenhance/enhancedlog/log.dat
  61. enhancedOs.write(result.getBytes());
  62. }
  63.  
  64. }
  65.  
  66. @Override
  67. public void close(TaskAttemptContext context) throws IOException, InterruptedException {
  68. if (tocrawlOs != null) {
  69. tocrawlOs.close();
  70. }
  71. if (enhancedOs != null) {
  72. enhancedOs.close();
  73. }
  74.  
  75. }
  76.  
  77. }
  78.  
  79. }
  1. package cn.itcast.bigdata.mr.logenhance;
  2.  
  3. import java.io.IOException;
  4. import java.util.HashMap;
  5. import java.util.Map;
  6.  
  7. import org.apache.commons.lang.StringUtils;
  8. import org.apache.hadoop.conf.Configuration;
  9. import org.apache.hadoop.fs.Path;
  10. import org.apache.hadoop.io.LongWritable;
  11. import org.apache.hadoop.io.NullWritable;
  12. import org.apache.hadoop.io.Text;
  13. import org.apache.hadoop.mapreduce.Counter;
  14. import org.apache.hadoop.mapreduce.Job;
  15. import org.apache.hadoop.mapreduce.Mapper;
  16. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  17. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  18.  
  19. public class LogEnhance {
  20.  
  21. static class LogEnhanceMapper extends Mapper<LongWritable, Text, Text, NullWritable> {
  22.  
  23. Map<String, String> ruleMap = new HashMap<String, String>();
  24.  
  25. Text k = new Text();
  26. NullWritable v = NullWritable.get();
  27.  
  28. // 从数据库中加载规则信息倒ruleMap中
  29. @Override
  30. protected void setup(Context context) throws IOException, InterruptedException {
  31.  
  32. try {
  33. DBLoader.dbLoader(ruleMap);
  34. } catch (Exception e) {
  35. e.printStackTrace();
  36. }
  37.  
  38. }
  39.  
  40. @Override
  41. protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
  42. // 获取一个计数器用来记录不合法的日志行数, 组名, 计数器名称
  43. Counter counter = context.getCounter("malformed", "malformedline");
  44. String line = value.toString();
  45. String[] fields = StringUtils.split(line, "\t");
  46. try {
  47. String url = fields[26];
  48. String content_tag = ruleMap.get(url);
  49. // 判断内容标签是否为空,如果为空,则只输出url到待爬清单;如果有值,则输出到增强日志
  50. if (content_tag == null) {
  51. k.set(url + "\t" + "tocrawl" + "\n");
  52. context.write(k, v);
  53. } else {
  54. k.set(line + "\t" + content_tag + "\n");
  55. context.write(k, v);
  56. }
  57.  
  58. } catch (Exception exception) {
  59. counter.increment(1);
  60. }
  61. }
  62.  
  63. }
  64.  
  65. public static void main(String[] args) throws Exception {
  66.  
  67. Configuration conf = new Configuration();
  68.  
  69. Job job = Job.getInstance(conf);
  70.  
  71. job.setJarByClass(LogEnhance.class);
  72.  
  73. job.setMapperClass(LogEnhanceMapper.class);
  74.  
  75. job.setOutputKeyClass(Text.class);
  76. job.setOutputValueClass(NullWritable.class);
  77.  
  78. // 要控制不同的内容写往不同的目标路径,可以采用自定义outputformat的方法
  79. job.setOutputFormatClass(LogEnhanceOutputFormat.class);
  80.  
  81. FileInputFormat.setInputPaths(job, new Path("D:/srcdata/webloginput/"));
  82.  
  83. // 尽管我们用的是自定义outputformat,但是它是继承制fileoutputformat
  84. // 在fileoutputformat中,必须输出一个_success文件,所以在此还需要设置输出path
  85. FileOutputFormat.setOutputPath(job, new Path("D:/temp/output/"));
  86.  
  87. // 不需要reducer
  88. job.setNumReduceTasks(0);
  89.  
  90. job.waitForCompletion(true);
  91. System.exit(0);
  92.  
  93. }
  94.  
  95. }

自定义inputformat和outputformat的更多相关文章

  1. 【Hadoop离线基础总结】MapReduce自定义InputFormat和OutputFormat案例

    MapReduce自定义InputFormat和OutputFormat案例 自定义InputFormat 合并小文件 需求 无论hdfs还是mapreduce,存放小文件会占用元数据信息,白白浪费内 ...

  2. 自定义InputFormat和OutputFormat案例

    一.自定义InputFormat InputFormat是输入流,在前面的例子中使用的是文件输入输出流FileInputFormat和FileOutputFormat,而FileInputFormat ...

  3. MapReduce自定义InputFormat和OutputFormat

    一.自定义InputFormat 需求:将多个小文件合并为SequenceFile(存储了多个小文件) 存储格式:文件路径+文件的内容 c:/a.txt I love Beijing c:/b.txt ...

  4. 【转自】自定义InputFormat、OutputFormat

    转自:http://www.cnblogs.com/xiaolong1032/p/4529534.html 一:自定义实现InputFormat *数据源来自于内存*1.InputFormat是用于处 ...

  5. Hadoop中常用的InputFormat、OutputFormat(转)

    Hadoop中的Map Reduce框架依赖InputFormat提供数据,依赖OutputFormat输出数据,每一个Map Reduce程序都离不开它们.Hadoop提供了一系列InputForm ...

  6. MapReduce自定义InputFormat,RecordReader

    MapReduce默认的InputFormat是TextInputFormat,且key是偏移量,value是文本,自定义InputFormat需要实现FileInputFormat,并重写creat ...

  7. commoncrawl 源码库是用于 Hadoop 的自定义 InputFormat 配送实现

    commoncrawl 源码库是用于 Hadoop 的自定义 InputFormat 配送实现. Common Crawl 提供一个示例程序 BasicArcFileReaderSample.java ...

  8. Hadoop案例(六)小文件处理(自定义InputFormat)

    小文件处理(自定义InputFormat) 1.需求分析 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案.将多个小文件合并 ...

  9. Hadoop_28_MapReduce_自定义 inputFormat

    1. 自定义inputFormat 1.1.需求: 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件,此时就需要有相应解决方案; 1.2.分析: 小文件的优化 ...

随机推荐

  1. Quartz快速入门

    Quartz是一个定时任务调度的框架,在预定的时间到达时,执行某一任务 可认为是JDK的Timer类的扩展 Quartz的核心接口Scheduler – 核心调度器Job – 任务JobDetail ...

  2. Tomcat和Servlet

    Tomcat Tomcat是什么,Tomcat是目前市场上主流Web服务器之一,是用Java语言开发的项目.Tomcat支持Servlet和JSP的规范,它由一组嵌套的层次和组件组成.结构如下图 所有 ...

  3. 【SQL查询】查询列中使用条件逻辑_case when then end

    select x.范围, count(*)  from (select t.ename,               case                 when t.sal <= 100 ...

  4. 一个 token 控件

    用于以分词形式显示某个对象的多个标签,比如: 用法 将 TagsView.h/.m 文件拷贝到你的项目文件夹,在需要用到该控件的地方导入 TagsView.h 头文件. IB 中的工作 拖一个 UIV ...

  5. Python中实现装饰模式的三种方式

    功能目标 编写一个可以打印被装饰函数名称.执行时间.内存地址得装饰器 前置依赖包 import time import functools from decorator import decorato ...

  6. 从无到有开发自己的Wordpress博客主题---创建主题

    上一篇教程,我们已经安装了Wordpress,我们可以成功的登录到Wordpress后台,接下来的任务就是创建我们自己的主题. 要想创建一个Wordpress主题,就必须按照Wordpress的规则, ...

  7. phpcms URL

    http://www.jb51.net/cms/112109.html 静态URL生成规则 http://v9.help.phpcms.cn/html/2010/database_1228/107.h ...

  8. FZU Problem 2129 子序列个数

    看了 dp 方程之后应该是妙懂 每次 加入一个数,×2  然后剪掉重复的: 重复的个数 维前面那个数,,,,, #include<iostream> #include<stdio.h ...

  9. HihoCoder - 1615矩阵游戏II(贪心)

    矩阵游戏II 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个NxN的整数矩阵,小Hi每次操作可以选择两列,将这两列中的所有数变成它的相反数. 小Hi可以进行任意 ...

  10. 数据结构之最小生成树Prim算法

    普里姆算法介绍 普里姆(Prim)算法,是用来求加权连通图的最小生成树算法 基本思想:对于图G而言,V是所有顶点的集合:现在,设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,T存放G的最 ...