MR案例:定制InputFormat
数据输入格式
InputFormat类用于描述MR作业的输入规范,主要功能:输入规范检查(比如输入文件目录的检查)、对数据文件进行输入切分和从输入分块中将数据记录逐一读取出来、并转化为Map的输入键值对。细节详见解读:标准输入/输出格式
Hadoop中最常用的数据输入格式包括:TextInputFormat 和 KeyValueInputFormat。
1). TextInputFormat 是系统默认的数据输入格式,可以将文件的每一行解析成一个键值对。其中,Key是当前行在整个文件中的字节偏移量,而Value就是该行的内容。默认的RecordReader是LineRecordReader。
2). KeyValueInputFormat是将一个按照<key,value>格式存放的文本文件逐行读出,并自动解析生成相应的key和value。默认是KeyValueLineRecordReader。
定制数据输入格式
用户可以从基类 InputFormat 和 RecordReader 开始定制过程,主要实现 InputFormat 中的 createRecordReader() 和 getSplits() 两个抽象方法,而 RecordReader 中则需要实现 gerCurrentKey() 和 getCurrentValue() 几个抽象方法。
需求:为了能更细粒的记录每个单词在文档中出现时的行位置信息FileName@LineOffset。
- 方法一:基于默认的TextInputFormat和LineRecordReader
public static class IIMapper extends Mapper<Text, Text, Text, Text>{
@Override
//输出key:word 输出value:FileName@LineOffset
protected void map(Text key, Text value,Context context)
throws IOException, InterruptedException {
//得到输入文件的文件名FileName(优化:应在setup方法中获取)
FileSplit fileSplit = (FileSplit)context.getInputSplit();
String name = fileSplit.getPath().getName();
//组装拼接Value: FileName@LineOffset
Text fileName_lineOffset=new Text(name+"@"+key.toString());
String[] splited = value.toString().split("\t");
for(String word : splited){
context.write(new Text(word), fileName_lineOffset);
}
}
}
- 方法二:基于 TextInputFormat 和 LineRecordReader 定制 FileNameInputFormat 和 FileNameRecordReader
package invertedIndex; import java.io.IOException; 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.mapreduce.lib.input.LineRecordReader; public class FileNameRecordReader extends RecordReader<Text, Text> { //成员变量
String fileName;
//实例化一个LineRecordReader实例
LineRecordReader lrr=new LineRecordReader(); @Override
public void initialize(InputSplit split, TaskAttemptContext context)
throws IOException, InterruptedException { //调用LineRecordReader类的初始化方法
lrr.initialize(split, context); //获取当前InputSplit的文件名
fileName=((FileSplit)split).getPath().getName();
} @Override
public Text getCurrentKey() throws IOException, InterruptedException { //调用LineRecordReader类的方法,拼接key
//其中lrr.getCurrentKey()返回:当前行在整个文本文件中的字节偏移量
return new Text("("+fileName+"@"+lrr.getCurrentKey().toString()+")");
} @Override
public Text getCurrentValue() throws IOException, InterruptedException { //调用LineRecordReader类的方法
return lrr.getCurrentValue();
} @Override
public boolean nextKeyValue() throws IOException, InterruptedException { return lrr.nextKeyValue();
} @Override
public float getProgress() throws IOException, InterruptedException { return lrr.getProgress();
} @Override
public void close() throws IOException { lrr.close();
}
} package invertedIndex; import java.io.IOException; 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; public class FileNameInputFormat extends FileInputFormat<Text, Text>{ @Override
public RecordReader<Text, Text> createRecordReader(InputSplit split,
TaskAttemptContext context) throws IOException, InterruptedException { FileNameRecordReader fnrr = new FileNameRecordReader(); //调用FileNameRecordReader的初始化方法
fnrr.initialize(split, context); return fnrr;
}
}
- 使用自定义的 FileNameInputFormat 和 FileNameRcordReader :
package invertedIndex; import java.io.IOException;
import java.util.StringTokenizer; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class InvertedIndex {
public static void main(String[] args) throws Exception {
Job job = Job.getInstance(new Configuration());
job.setJarByClass(InvertedIndex.class);
//设置数据输入格式【使用自定义的InputFormat】
job.setInputFormatClass(FileNameInputFormat.class);
job.setMapperClass(FFMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setNumReduceTasks(0);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
job.waitForCompletion(true);
} public static class FFMapper extends Mapper<Text, Text, Text, Text>{
@Override
protected void map(Text key, Text value, Context context)
throws IOException, InterruptedException {
//分词
StringTokenizer st = new StringTokenizer(value.toString());
for(;st.hasMoreTokens();){
//key:单词word value:FileName+偏移量
context.write(new Text(st.nextToken()), key);
}
}
}
}
输出结果为:key:单词,value:FileName@偏移量
read (data1@0)
file (data1@0)
read (data1@11)
data (data1@11)
数据输出格式
数据输出格式(OutputFormat)用于描述MR作业的数据输出规范。主要功能:输出规范检查(如检查输出目录是否存在),以及提供作业结果数据输出功能。
Hadoop默认的数据输出格式是TextOutputFormat,可以将结果以【key+\t+value】的形式逐行输出。默认的RecordWriter是LineRecordWriter。
MR案例:定制InputFormat的更多相关文章
- MR案例:倒排索引
1.map阶段:将单词和URI组成Key值(如“MapReduce :1.txt”),将词频作为value. 利用MR框架自带的Map端排序,将同一文档的相同单词的词频组成列表,传递给Combine过 ...
- MR案例:Reduce-Join
问题描述:两种类型输入文件:address(地址)和company(公司)进行一对多的关联查询,得到地址名(例如:Beijing)与公司名(例如:Beijing JD.Beijing Red Star ...
- MR案例:小文件处理方案
HDFS被设计来存储大文件,而有时候会有大量的小文件生成,造成NameNode资源的浪费,同时也影响MapReduce的处理效率.有哪些方案可以合并这些小文件,或者提高处理小文件的效率呢? 1). 所 ...
- MR案例:定制Partitioner
可以继承基类Partitioner,也可以继承默认的HashPartitioner类,覆写其中的 getPartition() 方法实现自己的分区. 需求:本例是对上一个实例的改写,需求不变 pack ...
- MR案例:CombineFileInputFormat
CombineFileInputFormat是一个抽象类.Hadoop提供了两个实现类CombineTextInputFormat和CombineSequenceFileInputFormat. 此案 ...
- MR案例:倒排索引 && MultipleInputs
本案例采用 MultipleInputs类 实现多路径输入的倒排索引.解读:MR多路径输入 package test0820; import java.io.IOException; import j ...
- MR案例:输出/输入SequenceFile
SequenceFile文件是Hadoop用来存储二进制形式的key-value对而设计的一种平面文件(Flat File).在SequenceFile文件中,每一个key-value对被看做是一条记 ...
- MR案例:小文件合并SequeceFile
SequeceFile是Hadoop API提供的一种二进制文件支持.这种二进制文件直接将<key, value>对序列化到文件中.可以使用这种文件对小文件合并,即将文件名作为key,文件 ...
- MR案例:MR和Hive中使用Lzo压缩
在MapReduce中使用lzo压缩 1).首先将数据文件在本地使用lzop命令压缩.具体配置过详见配置hadoop集群的lzo压缩 //压缩lzop,解压缩lzop -d [root@ncst wo ...
随机推荐
- spring boot 加载jsp
1.spring boot启动类继承SpringBootServletInitializer ,并且重写configure方法 package com.springapp.mvc;import jav ...
- 170424、Mysql权限控制 - 允许用户远程连接
Mysql为了安全性,在默认情况下用户只允许在本地登录,可是在有此情况下,还是需要使用用户进行远程连接,因此为了使其可以远程需要进行如下操作: 一.允许root用户在任何地方进行远程登录,并具有所有库 ...
- java拾遗4----一个简单java程序的运行全过程
简单说来,一个java程序的运行需要编辑源码.编译生成class文件.加载class文件.解释或编译运行class中的字节码指令. 下面有一段简单的java源码,通过它来看一下java程序的运行流程: ...
- HDU_5534_Partial Tree
Partial Tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)To ...
- Spark源码分析 – SparkEnv
SparkEnv在两个地方会被创建, 由于SparkEnv中包含了很多重要的模块, 比如BlockManager, 所以SparkEnv很重要 Driver端, 在SparkContext初始化的时候 ...
- aliyun ECS da shang chuang 安装小结
1. 服务器系统选centos 6.x 选错了可以在管理界面重装系统 阿里云自带ip限制功能,默认是关闭外网访问(ftp http)进来的,需要手动在管理界面 - 本实例安全组 - 配置. 先安装v ...
- Vue1.x 到Vue2.0的一个变化
小弟初来乍到,写的不好的地方还望指正.谢谢各位! 废话不多说 进入正题: Vue1.x到2.0的一个变化 1. 在每个组件模板,不在支持片段代码 组件中模板: 之前: <templa ...
- 如何缩减手游app安装包的大小?
包体过大对手游的影响更是诟病已久,有具体数据证明,游戏包体越大,在游戏运营推广过程中游戏用户的转化率就越低:反之,游戏包体越小,游戏用户的下载转化率就越高(如下图),所有的手机app.游戏在大版本更新 ...
- 【opencv入门篇】快速在VS上配置opencv
环境配置:win7-32 + opencv2.4.6 + vs2013 注意:无论电脑是32位还是64位,配置opencv库目录时选择x84文件夹!因为编译都是使用32位编译:如果选用X64,则程序运 ...
- myeclipse中更改web项目在tomcat中部署的路径
右键点击项目名称,选择属性properties,选择myeclipse->web.更改web context-root就可以.