本案例采用 MultipleInputs类 实现多路径输入的倒排索引。解读:MR多路径输入

package test0820;

import java.io.IOException;
import java.lang.reflect.Method; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.input.MultipleInputs;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class WC0826 { public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(WC0826.class); job.setMapperClass(IIMapper.class);
job.setCombinerClass(IICombiner.class);
job.setReducerClass(IIReducer.class); job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class); job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class); //使用MultipleInputs类指定多路径输入
MultipleInputs.addInputPath(job, new Path(args[0]), TextInputFormat.class);
MultipleInputs.addInputPath(job, new Path(args[1]), TextInputFormat.class);
FileOutputFormat.setOutputPath(job, new Path(args[2])); System.exit(job.waitForCompletion(true)? 0:1);
} //map
public static class IIMapper extends Mapper<LongWritable, Text, Text, Text>{ String fileName; /**
* 使用 MultipleInputs 获得 FileName 必须添加的类
*/
private Path getFilePath(Context context) throws IOException { InputSplit split = context.getInputSplit();
Class<? extends InputSplit> splitClass = split.getClass(); FileSplit fileSplit = null;
if (splitClass.equals(FileSplit.class)) {
fileSplit = (FileSplit) split;
} else if (splitClass.getName().
equals("org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit")) { // begin reflection hackery...
try {
Method getInputSplitMethod = splitClass.getDeclaredMethod("getInputSplit");
getInputSplitMethod.setAccessible(true);
fileSplit = (FileSplit) getInputSplitMethod.invoke(split);
} catch (Exception e) {
// wrap and re-throw error
throw new IOException(e);
}
// end reflection hackery
}
return fileSplit.getPath();
} @Override
protected void setup(Context context)
throws IOException, InterruptedException { //get file name
fileName = getFilePath(context).getName();
} @Override
protected void map(LongWritable key, Text value,Context context)
throws IOException, InterruptedException { String[] splited = value.toString().split("\t"); for(String word : splited){
Text word_fileName=new Text(word+"@"+fileName);
context.write(word_fileName,new Text("1"));
}
}
} //combiner
public static class IICombiner extends Reducer<Text, Text, Text, Text>{
@Override
protected void reduce(Text key, Iterable<Text> v2s, Context context)
throws IOException, InterruptedException { Long sum = 0L;
String value=new String(); String[] splited = key.toString().split("@"); for(Text vl :v2s){
sum += Long.parseLong(vl.toString());
value = splited[1]+"@"+sum.toString();
}
context.write(new Text(splited[0]), new Text(value));
}
} //reduce
public static class IIReducer extends Reducer<Text, Text, Text, Text>{
@Override
protected void reduce(Text key, Iterable<Text> v2s, Context context)
throws IOException, InterruptedException { String value=new String(); for(Text text : v2s){
value = text.toString()+":"+value;
}
//去掉最后的":"
context.write(key, new Text(value.substring(0, value.length()-1)));
}
}
}

出现问题01:使用MultipleInputs类指定输入路径,当setup()方法中调用getInputSplit()方法获取当前split对应的FileName时会报IO异常:

Error: java.lang.ClassCastException: org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit cannot be cast to org.apache.hadoop.mapreduce.lib.input.FileSplit

问题原因01:filesplit实际上就是TaggedInputSplit中的成员变量inputSplit,而TaggedInputSplit类并不是public的(默认是default声明类型),所以不能直接获得对应的信息。

解决方案01:

  • 第一种方法:在当前项目中新建对应的TaggedInputSplit类,并声明为public。即覆盖掉原有TaggedInputSplit类的声明类型。然后通过以下代码就可以正确调用:
(FileSplit)((TaggedInputSplit)reporter.getInputSplit()).getInputSplit(); 
  • 第二种方法:通过反射机制。代码如下:
/**
* 反射机制
* 使用 MultipleInputs 获得 FileName 必须添加的类
*/
private Path getFilePath(Context context) throws IOException { InputSplit split = context.getInputSplit();
Class<? extends InputSplit> splitClass = split.getClass(); FileSplit fileSplit = null;
if (splitClass.equals(FileSplit.class)) {
fileSplit = (FileSplit) split;
} else if (splitClass.getName().
equals("org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit")) { // begin reflection hackery...
try {
Method getInputSplitMethod = splitClass.getDeclaredMethod("getInputSplit");
getInputSplitMethod.setAccessible(true);
fileSplit = (FileSplit) getInputSplitMethod.invoke(split);
} catch (Exception e) {
// wrap and re-throw error
throw new IOException(e);
}
// end reflection hackery
}
return fileSplit.getPath();
}

出现问题02:

map<Object,Text,Text,IntWritble>
combiner<Text,IntWritble,Text,Text>
reduce<Text,Text,Text,Text>

这样设置,系统会异常。这是因为Combiner和Reducer其实是同一个函数,所以输入和输出类型必须保持一致。

Combiner实现对map端value的聚合,减少map 到 reudce 间数据传输,加快 shuffle 速度。牢记求平均值的MR不能使用Combiner。

MR案例:倒排索引 && MultipleInputs的更多相关文章

  1. MR案例:倒排索引

    1.map阶段:将单词和URI组成Key值(如“MapReduce :1.txt”),将词频作为value. 利用MR框架自带的Map端排序,将同一文档的相同单词的词频组成列表,传递给Combine过 ...

  2. MR案例:Reduce-Join

    问题描述:两种类型输入文件:address(地址)和company(公司)进行一对多的关联查询,得到地址名(例如:Beijing)与公司名(例如:Beijing JD.Beijing Red Star ...

  3. MR案例:小文件处理方案

    HDFS被设计来存储大文件,而有时候会有大量的小文件生成,造成NameNode资源的浪费,同时也影响MapReduce的处理效率.有哪些方案可以合并这些小文件,或者提高处理小文件的效率呢? 1). 所 ...

  4. MR案例:CombineFileInputFormat

    CombineFileInputFormat是一个抽象类.Hadoop提供了两个实现类CombineTextInputFormat和CombineSequenceFileInputFormat. 此案 ...

  5. MR案例:输出/输入SequenceFile

    SequenceFile文件是Hadoop用来存储二进制形式的key-value对而设计的一种平面文件(Flat File).在SequenceFile文件中,每一个key-value对被看做是一条记 ...

  6. MR案例:分区和排序

    现有一学生成绩数据,格式如下:<学号,姓名,学院,成绩>  //<id, name, institute, grade>. 需求描述:查询成绩大于等于60分的学生数据,按学院分 ...

  7. MR案例:链式ChainMapper

    类似于Linux管道重定向机制,前一个Map的输出直接作为下一个Map的输入,形成一个流水线.设想这样一个场景:在Map阶段,数据经过mapper01和mapper02处理:在Reduce阶段,数据经 ...

  8. MR案例:定制InputFormat

    数据输入格式 InputFormat类用于描述MR作业的输入规范,主要功能:输入规范检查(比如输入文件目录的检查).对数据文件进行输入切分和从输入分块中将数据记录逐一读取出来.并转化为Map的输入键值 ...

  9. MR案例:基站相关01

    字段解释: product_no:用户手机号: lac_id:用户所在基站: start_time:用户在此基站的开始时间: staytime:用户在此基站的逗留时间. product_no lac_ ...

随机推荐

  1. [ Office 365 开发系列 ] 身份认证

    前言 本文完全原创,转载请说明出处,希望对大家有用. 通常我们在开发一个应用时,需要考虑用户身份认证及授权,Office 365使用AAD(Azure Active Directory)作为其认证机构 ...

  2. Python--进阶处理8

    # ====================第八章:类与对象========================= # --------------改变对象的字符串显示------------------ ...

  3. Ubuntu 只能用guest登录的问题修复

    方式1(推荐): 1.先进入guest登入 2.通过Ctrl+Alt+F1进入命令行窗口(注释:Ctrl+Alt+F1~F6进入终端命令行,Ctrl+Alt+F7是退出终端) 3.登录root,然后进 ...

  4. 微信openid的单脚本获取 将 header 至自身,但是reques参数不同,响应也不同-----“单脚本APP”

    w 0-目的是封装成一个类.方法,方便在不同入口下,比如不是在微信公众号内而是在他人分享的url,获取opeid,且便于路由控制,将路由控制交给且仅交给codeigniter; 1-任何一个网站都可以 ...

  5. 【推荐】CentOS安装Subversion-1.8.17+HTTP协议支持配置

    注:以下所有操作均在CentOS 6.5 x86_64位系统下完成. 我们需要搭建一个自己的SVN服务器. 此外,搭建好的SVN服务器除了需要支持svn协议外,最好还需要支持HTTP协议和HTTPS协 ...

  6. HTTP协议 (七) Cookie(转)

    add by zhj: 客户端通过request header:cookie将cookie发给服务端,而服务端通过response header: set-cookie将cookie传回客户端 一条c ...

  7. python3.6.1 安装PyQt5,以及配置QTDesigner,PyUIC

    本人主机win10 64,python版本是3.6.1 64 注意python版本一定得是3.6.1 64位的,我原来电脑是安装的32位的,浪费了好长时间 (MMP) 第一步:安装python,自己官 ...

  8. ALV tree DUMP 问题处理-20180328

    Category ABAP Programming Error Runtime Errors MESSAGE_TYPE_X ABAP Program SAPLOLEA Application Comp ...

  9. mysql5.7新特性探究

    一.MySql5.7增加的特性 1.MySql服务方面新特性 1) 初始化方式改变 MySql5.7之前版本初始化方式: scripts/mysql_install_db MySql5.7版本初始化方 ...

  10. SDUT3143:Combinatorial mathematics(组合数学)

    题意:传送门 题目描述 As you know, shadow95 is pretty good at maths, especially combinatorial mathematics. Now ...