记一次使用MapReduce做WordCount遇到的坑

450 阅读2分钟

首先介绍下开发环境,Hadoop部署在阿里云上,本地用IDEA开发,目的是使用MR做一个简单的WC。

1、Mapper、Reducer及Driver相关代码

1.1 Mapper业务代码

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/**
 * keyin Map任务读取数据的key类型,offset,是每行数据起始位置的偏移量,Long
 * Valuein Map任务读数据的value类型,其实就是一行行的字符串,String类型
 * hello world welcome
 * hello welcome
 * keyout map方法自定义实现输出的key类型,String
 * valueout map方法自定义实现的value类型,Integer类型
 */
public class WordCountMapper extends Mapper<LongWritable,Text,Text,IntWritable>{

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        // 把value对应的行数据按照指定的分隔符拆开
        String[] words = value.toString().split("\t");
        for(String word : words){
            context.write(new Text(word),new IntWritable(1));
        }
    }
}

1.2 Reducer业务代码

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;
import java.util.Iterator;


public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
    /**
     * (hello,1) (world,1)
     * (hello,1) (world,1)
     * (welcome,1)
     * <p>
     * map的输出到reduce端,是按照相同的key分发到一个reduce上去执行的
     * <p>
     * reduce1: (hello,1) (hello,1) (hello,1) --> (hello,<1,1,1>)
     * reduce2: (world,1) (world,1) (world,1) --> (world, <1,1,1>)
     * reduce3: (welcome,1) --> (welcome,<1>)
     *
     * @param key
     * @param values
     * @param context
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        int count = 0;
        Iterator<IntWritable> iterator = values.iterator();
        while (iterator.hasNext()) {
            IntWritable value = iterator.next();
            count += value.get();
        }
        context.write(key,new IntWritable(count));
    }
}

1.3 Driver业务代码

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;

/**
 * 使用MR统计HDFS上的文件对应的词频
 */
public class WordCountApp {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        // System.setProperty("HADOOP_USER_NAME","root");
        Configuration configuration = new Configuration();
        configuration.set("fs.defaultFS", "hdfs://121.**.***.81:8020/");
        // configuration.set("dfs.client.use.datanode.hostname", "true");

        // 创建一个job
        Job job = Job.getInstance(configuration);
        // 设置job对应的参数:主类
        job.setJarByClass(WordCountApp.class);
        // 设置job对应的参数:自定义Mapper和Reducer类
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);
        // 设置Job对应的参数:Mapper输出key和value的类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        // 设置Job对应的参数:Reducer输出key和value的类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        // 设置Job对应的参数:Mapper输出key和value的类型,作业输入和输出的路径
        FileInputFormat.setInputPaths(job, new Path("/wordcount/input"));
        FileOutputFormat.setOutputPath(job, new Path("/wordcount/output"));
        // 提交job
        boolean res = job.waitForCompletion(true);
        System.exit(res ? 0 : -1);
    }
}

2、相关错误汇总及解决办法

2.1 第一个错误

解决办法下载 解决办法:
(1) 下载winutils,注意需要与hadoop的版本相对应。
hadoop2.2版本可以在这里下载 github.com/srccodes/ha…
hadoop2.6版本可以在这里下载 github.com/amihalik/ha…
由于配置的测试集群是hadoop2.6.0,所以我在这里下载的是2.6.0版本的。下载后,将其解压。

(2) 配置环境变量
增加系统变量HADOOP_HOME,值是下载的zip包解压的目录,我这里解压后将其重命名为hadoop-common-2.6.0
在系统变量path里增加%HADOOP_HOME%\bin
重启电脑,使环境变量配置生效,上述问题即可解决。   

2.2 第二个错误

解决办法,在上一个基础上删除所有文件夹内部的hadoop.dll文件

2.3 第三个错误

解决办法,自定义NativeIO类,在access方法处之间返回true

2.4 第四个错误

提示Windows用户权限不足。
加一行代码,用Linux内部操作Hadoop的用户来操作

System.setProperty("HADOOP_USER_NAME","root");

2.5 第五个错误

连接超时 解决方法:

 configuration.set("dfs.client.use.datanode.hostname", "true");