一般的mapreduce的wordcount程序如下:

public class WcMapper extends Mapper<LongWritable, Text, Text, LongWritable> {

    @Override
protected void map(LongWritable key, Text value, Context ctx) throws IOException, InterruptedException { String[] words = value.toString().split(" ");
for (int i = 0; i < words.length; i++) {
ctx.write(new Text(words[i]), new LongWritable(1L));
}
}
}

 

public class WcReduer extends Reducer<Text, LongWritable, Text, LongWritable> {

    LongWritable count = new LongWritable();
@Override
protected void reduce(Text key, Iterable<LongWritable> values, Context ctx) throws IOException, InterruptedException {
Iterator<LongWritable> itr = values.iterator();
long sum = 0L;
while (itr.hasNext()) {
sum = sum + itr.next().get();
}
count.set(sum);
ctx.write(key, count);
}
}

  

驱动作业代码:

public class JobClient {

    public static void main(String[] args) throws Exception {

        Job job = Job.getInstance();
job.setJarByClass(JobClient.class);
job.setMapperClass(WcMapper.class);
job.setReducerClass(WcReduer.class); job.setInputFormatClass(TextInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class); job.setJobName("wordcount");
FileInputFormat.addInputPath(job, new Path("/daxin/hadoop-mapreduce/words"));
FileOutputFormat.setOutputPath(job, new Path("/daxin/hadoop-mapreduce/wordcount-result"));
job.waitForCompletion(true);
}
}

  

提交作业会报错:

Error: java.io.IOException: Type mismatch in key from map: expected org.apache.hadoop.io.LongWritable, received org.apache.hadoop.io.Text
at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.collect(MapTask.java:1072)
at org.apache.hadoop.mapred.MapTask$NewOutputCollector.write(MapTask.java:715)
at org.apache.hadoop.mapreduce.task.TaskInputOutputContextImpl.write(TaskInputOutputContextImpl.java:89)
at org.apache.hadoop.mapreduce.lib.map.WrappedMapper$Context.write(WrappedMapper.java:112)
at com.daxin.blog.WcMapper.map(WcMapper.java:20)
at com.daxin.blog.WcMapper.map(WcMapper.java:13)
at org.apache.hadoop.mapreduce.Mapper.run(Mapper.java:146)
at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:787)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:341)
at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:164)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1657)
at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:158) 

通过异常信息我们可以定位错误在源码中的位置:org.apache.hadoop.mapred.MapTask.MapOutputBuffer#collect,具体关键源码如下:

 public synchronized void collect(K key, V value, final int partition
) throws IOException {
reporter.progress();
if (key.getClass() != keyClass) {
throw new IOException("Type mismatch in key from map: expected "
+ keyClass.getName() + ", received "
+ key.getClass().getName());
}
if (value.getClass() != valClass) {
throw new IOException("Type mismatch in value from map: expected "
+ valClass.getName() + ", received "
+ value.getClass().getName());
}
.....
}

此处key.getClass可以确定是Text,需要确定keyClass是什么类型。下面就将确定一下keyClass类型,可以发现keyClass赋值源码:

 keyClass = (Class<K>)job.getMapOutputKeyClass();

 getMapOutputKeyClass源码:

  public Class<?> getMapOutputKeyClass() {
Class<?> retv = getClass(JobContext.MAP_OUTPUT_KEY_CLASS, null, Object.class);
if (retv == null) {
retv = getOutputKeyClass();
}
return retv;
} 

其中MAP_OUTPUT_KEY_CLASS则是获取map输出的key的类型,由于我们驱动代码没有设置因此此处得到的值为默认值null,接下在调用getOutputKeyClass方法:

  public Class<?> getOutputKeyClass() {
return getClass(JobContext.OUTPUT_KEY_CLASS,
LongWritable.class, Object.class);
}

 

 public static final String OUTPUT_KEY_CLASS = "mapreduce.job.output.key.class";

  

通过获取OUTPUT_KEY_CLASS的类型,OUTPUT_KEY_CLASS表示的是作业的key的输出类型,但是由于我们没有设置因此获取默认值为LongWritable。但是实际上我们的MapTask输出的key为Text,因而报如上类型不匹配错误。同理Map的value也有类似问题。为了解决此问题就需要显式的设置MapTask的Key、Value输出类型。代码如下:

        job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);

 

最后也可以分析org.apache.hadoop.mapred.ReduceTask#run方法可以得知:当我们不显式设置Map的Key/Value输出时候,默认Map的key类型为LongWritable,Value为Text,获取类型的关键代码:

 Class keyClass = job.getMapOutputKeyClass();
Class valueClass = job.getMapOutputValueClass();

其实我有一个困惑,因为我们在写Mapper与Reducer任务时候,Mapper与Reducer都是泛型类,由于泛型类的泛型信息可以保留,为什么还要我们显式设置Map的Key、Value输出类型呢?

我个人分析,可能存在错误,如果有错误望各位指正:

虽然泛型类可以保留信息,也可以在运行时获取泛型信息,但是能够得到的信息是一个整体并不是每一个具体的泛型的信息,说的有点模糊,以Mapper为例,Mapper定义如下:

public class WcMapper extends Mapper<LongWritable, Text, Text, LongWritable> {

    @Override
protected void map(LongWritable key, Text value, Context ctx) throws IOException, InterruptedException { //......
}
}

  

当我们获取该泛型信息时候只能获取到:

org.apache.hadoop.mapreduce.Mapper<org.apache.hadoop.io.LongWritable, org.apache.hadoop.io.Text, org.apache.hadoop.io.Text, org.apache.hadoop.io.LongWritable>

 而不是获取到四个泛型组成的数组,个人觉着可能mapreduce处于此考虑所以要求显示设置输出的类型信息(此处需要具体类型信息的目的是为了序列化)。(当然如果有人说通过解析过去四个泛型信息,这样的确可以,但是这样实现的话代码是不是不太优雅?)

mapreduce设置setMapOutputKeyClass与setMapOutputValueClass原因的更多相关文章

  1. C++构造函数/析构函数 设置成private的原因

    C++构造函数/析构函数 设置成private的原因 标签(空格分隔): c/c++ 将构造函数,析构函数声明为私有和保护的,那么对象如何创建? 已经不能从外部调用构造函数了,但是对象必须被构造,应该 ...

  2. 关于C# Winform DataGridView 设置DefaultCellStyle无效的原因与解决方案

    上周在开发Winform 项目中,我曾遇到一个看似简单,但一直都没有解决的问题,那就是:设置winform DataGridView控件的行DefaultCellStyle,但却没有任何变化,我也曾求 ...

  3. PHPStorm+XDebug进行调试图文教程以及解析wamp的php.ini设置不生效的原因

    这篇文章主要为大家详细介绍了PHPStorm+XDebug进行调试图文教程,内容很丰富,具有一定的参考价值,感兴趣的小伙伴们可以参考一下   笔者的开发环境如下:Windows8.1+Apache+P ...

  4. 重新绑定ItemsSource先设置ItemsSource = null;的原因

    即报错信息为:在使用 ItemsSource 之前,项集合必须为空.   原因:Items和ItemSource,只能有一个生效,想用其中一个,另一个必须是空.   重新绑定ItemSource,虽然 ...

  5. (转)mysql 无法设置外键的原因总结

    在Mysql中创建外键时,经常会遇到问题而失败,这是因为Mysql中还有很多细节需要我们去留意,我自己总结并查阅资料后列出了以下几种常见原因. 1.  两个字段的类型或者大小不严格匹配.例如,如果一个 ...

  6. hbase运行mapreduce设置及基本数据加载方法

    hbase与mapreduce集成后,运行mapreduce程序,同时需要mapreduce jar和hbase jar文件的支持,这时我们需要通过特殊设置使任务可以同时读取到hadoop jar和h ...

  7. DIV设置overflow无效的原因

    因为项目需求需要在一个div中添加多个checked 添加的时候使用了 <label><input type="checkbox" value="123 ...

  8. 解析wamp的php.ini设置不生效的原因

    你是否有过这样的经历,当你打开wamp的php.ini,并进行参数修改之后.再回到命令去运行你的php脚本,却发现你的设置居然不生效? 如果有这样的情况,那你得先了解php的两种运行运行环境,一个在命 ...

  9. ListView设置setFooterDividersEnabled无效的原因

    参考文章:http://gundumw100.iteye.com/blog/1169065 我的情况: 高度设置为了wrap_content, 且外边有一个FrameLayout(只包含了listvi ...

随机推荐

  1. 【公众号转载】超详细 Nginx 极简教程,傻瓜一看也会!

    什么是Nginx? Nginx (engine x) 是一款轻量级的Web 服务器 .反向代理服务器及电子邮件(IMAP/POP3)代理服务器. 什么是反向代理? 反向代理(Reverse Proxy ...

  2. java中那些类是线程安全的?

    Java中各种集合(字符串类)的线程安全性!!! 一.概念: 线程安全:就是当多线程访问时,采用了加锁的机制:即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读 ...

  3. POJ2186(强连通分量分解)

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 35035   Accepted: 14278 De ...

  4. 使用PHPExcel实现数据批量导出为excel表格

    首先需要下载PHPExecel类文件,帮助文档可以参考PHPExcel中文帮助手册|PHPExcel使用方法. 下面直接上例子,是我自己写的一个简单的批量导出数据为excel的例子 前台页面 比较简单 ...

  5. JS 对数组的操作集锦(基础)

    下面内容是自己复习基础时候整理出来的,感谢缪雪峰老师的课程让自己可以有节奏的复习基础的东西! 以下内容颜色是重点关注,已经特别注意提醒,不是为了颜色好看噢,希望能帮到刚学习前端的朋友们,后续还会持续更 ...

  6. 数据表自增Id获取时IDENTITY的正确使用方式

    在SQLServer中很多表主键会设置为自增列,有的业务需求需要知道新插入的自增Id是多少,一般我们会用SELECT @@IDENTITY来获取,可由于@@IDENTITY是个全局变量作用据较大,所以 ...

  7. Retrofit+OKHttp忽略https证书验证

    记录这个的原因,是因为很多时候,因为后台配置的证书不正确导致APP访问不到服务器数据,导致影响自身的开发进度.没几行代码,逻辑也清晰,所以下面就直接贴出工具类吧: package huolongluo ...

  8. SQLServer 学习笔记之超详细基础SQL语句 Part 6

    Sqlserver 学习笔记 by:授客 QQ:1033553122 -----------------------接Part 5------------------- 28 聚合函数 --求平均分 ...

  9. Unity Profiler Memory

    当游戏出现闪退时很大概率是内存出现了问题,查找下代码中是否报错导致一直申请内存,还是申请的内存没有释放掉,比如图集等. 比如开着Profiler,一直开关界面看界面用到的图集是否被释放掉. 点击Mem ...

  10. 从零自学Java-1.编写第一个Java程序

    编写第一个Java程序 完成工作:1.在文本编辑器中输入一个Java程序. 2.使用括号组织程序. 3.保存.编译和运行程序. package com.Jsample;//将程序的包名称命名为com. ...