Hadoop之MapReduce的Java实现

作者: landy8530 | 来源:发表于2017-11-25 16:13 被阅读394次

    今天将为大家演示一下,Hadoop中MR用Java是如何编码实现的。

    1.环境准备

    1.1 需要把下载的hadoop包解压到windows目录下,注意不要有空格目录或者中文字符

    image.png

    1.2 配置环境变量

    配置系统环境变量HADOOP_HOME,指向hadoop安装目录(如果你不想招惹不必要的麻烦,不要在目录中包含空格或者中文字符) 。把HADOOP_HOME/bin加到PATH环境变量(非必要,只是为了方便)
    以下截图为windows下配置:


    image.png
    image.png

    1.3 windows例外配置1

    如果是windows:在E:\bigdata\hadoop\etc\hadoop目录下的hadoop-env.cmd文件中修改JAVA_HOME环境变量(注意JDK安装路径不能含有空格,如:C:\Java\jdk1.8.0_11)


    image.png

    1.4 windows例外配置2

    如果是在windows下开发,需要添加windows的库文件,把网盘中共享的bin目录覆盖HADOOP_HOME/bin(已经转移到CSDN,下载),如果还是不行,把其中的hadoop.dll复制到c:\windows\system32目录下,可能需要重启机器。

    1.5 建立新项目,引入hadoop需要的jar文件

    2.代码

    WordMapper类:

    import java.io.IOException;
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.LongWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Mapper;
    
    
    public class WordMapper extends Mapper<LongWritable,Text, Text, IntWritable> {
    
        @Override
        protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context)
                throws IOException, InterruptedException {
    
           //接收到split中的输出结果作为map的输入 
            String line = value.toString();
            String[] words = line.split(" ");
           
            //放到list中,每个text统计加1,作为map的输出
            //写到context上下文环境中,输出到下一个执行过程shuffle
            for(String word : words) {
                context.write(new Text(word), new IntWritable(1));
            }
        }
    
    }
    
    

    WordReducer类

    import java.io.IOException;
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.LongWritable;
    import org.apache.hadoop.io.Text;
    import org.apache.hadoop.mapreduce.Reducer;
    
    public class WordReducer extends Reducer<Text, IntWritable, Text, LongWritable> {
    
        @Override
        protected void reduce(Text key, Iterable<IntWritable> values,
                Reducer<Text, IntWritable, Text, LongWritable>.Context context) throws IOException, InterruptedException {
            long count = 0;
            
            //此时的输入是shuffle的输出
            //输入的key是字符串,输入的value是shuffle派发过来的是一个个list
            for(IntWritable v : values) {
                count += v.get();
            }
            context.write(key, new LongWritable(count));
        }
    
    }
    
    

    3.运行

    3.1 直接本地运行

    直接本地输入输出,代码Test

    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.IntWritable;
    import org.apache.hadoop.io.LongWritable;
    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;
    
    
    public class Test {
        public static void main(String[] args) throws Exception {
            Configuration conf = new Configuration();
    
            Job job = Job.getInstance(conf);
    
            job.setMapperClass(WordMapper.class);
            job.setReducerClass(WordReducer.class);
            job.setMapOutputKeyClass(Text.class);
            job.setMapOutputValueClass(IntWritable.class);
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(LongWritable.class);
    
            FileInputFormat.setInputPaths(job, "c:/bigdata/hadoop/test/test.txt");
            FileOutputFormat.setOutputPath(job, new Path("c:/bigdata/hadoop/test/out/"));
    
            job.waitForCompletion(true);
        }
    }
    
    

    直接本地运行结果:

    本地运行结果1.png 本地运行结果2.png

    3.2 把hdfs中的文件拉到本地来运行

    需要Test中的以下代码:

    FileInputFormat.setInputPaths(job, "hdfs://master:9000/wcinput/");
    FileOutputFormat.setOutputPath(job, new Path("hdfs://master:9000/wcoutput2/"));
    

    注意这里是把hdfs文件拉到本地来运行,如果观察输出的话会观察到jobID带有local字样
    同时这样的运行方式是不需要yarn的(自己停掉yarn服务做实验)


    hdfs文件拉到本地来运行.png

    如上图,此时还是在本地运行mapReduce程序

    3.3 在远程服务器执行

    修改以下代码:

    //配置了fs.defaultFS选项,则下面的setInputPaths等配置不需要再配置前缀
    conf.set("fs.defaultFS", "hdfs://192.168.56.200:9000/");
    conf.set("mapreduce.framework.name", "yarn");//MapReduce运行环境为yarn
    conf.set("yarn.resourcemanager.hostname", "192.168.56.200");//yarn的recourseManager的主机名
    conf.set("mapreduce.app-submission.cross-platform", "true");//表示MapReduce是跨平台运行的
    FileInputFormat.setInputPaths(job, "/wcinput/");
    FileOutputFormat.setOutputPath(job, new Path("/wcoutput3/"));
    

    此时运行,则会出现权限问题,如下图:


    image.png

    如果遇到权限问题,有三种方法:

    1. 在系统的环境变量或java JVM变量里面添加HADOOP_USER_NAME,这个值具体等于多少看自己的情况,以后会运行HADOOP上的Linux的用户名。(修改完重启eclipse,不然可能不生效)
    2. 将当前系统的帐号修改为hadoop(运行HADOOP上的Linux的用户名,本例为root)
    3. 使用HDFS的命令行接口修改相应目录的权限,hadoop fs -chmod 777 /user,后面的/user是要上传文件的路径,不同的情况可能不一样,比如要上传的文件路径为hdfs://namenode/user/xxx.doc,则这样的修改可以,如果要上传的文件路径为hdfs://namenode/java/xxx.doc,则要修改的为hadoop fs -chmod 777 /java或者hadoop fs -chmod 777 /,java的那个需要先在HDFS里面建立Java目录,后面的这个是为根目录调整权限。

    这里采用第一种方法配置执行时的虚拟机参数-DHADOOP_USER_NAME=root


    image.png

    也可以将hadoop的四个配置文件拿下来放到src根目录下,就不需要进行手工配置了,默认到classpath目录寻找
    或者将配置文件放到别的地方,使用conf.addResource(.class.getClassLoader.getResourceAsStream)方式添加,不推荐使用绝对路径的方式
    通过以上配置以后,就可以运行MapReduce了,如下图所示:


    image.png

    上图就表示,已经在远程服务器中执行MapReduce程序了(jobid没有local前缀了),但是问题又来了,执行到后面出现以下找不到类的情况:

    java.lang.ClassNotFoundException: Class org.lyx.mapreduce.WordMapper not found
    
    image.png

    这是因为服务器上没有WordMapper这个类,这时候需要两个步骤的操作:
    1.打包整个MapReduce工程为一个jar包,eclipse的话直接export(java工程),如果是maven工程,直接使用Package打包成jar。如下图所示(idea):


    image.png

    打包完成如下图所示:


    image.png
    2.加入以下代码:
    //配置此工程打好的jar包路径,建议使用相对路径
    conf.set("mapreduce.job.jar", "target/mapreduce-0.0.1-SNAPSHOT.jar");
    

    或者

    job.setJar("target/mapreduce-0.0.1-SNAPSHOT.jar");
    

    加入以上代码后,需要重新打包。

    此时再次运行即可在远程服务器中执行MapReduce程序,执行结果如下图所示:


    远程运行结果.png 远程运行结果.png

    在web网页中观察结果如下:

    hdfs中的情况:


    image.png

    在yarn中的情况如下:


    image.png

    4.Maven配置

    建立maven-hadoop项目

    4.1 pom.xml

    <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-client</artifactId>
                <version>${hadoop.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-common</artifactId>
                <version>${hadoop.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-hdfs</artifactId>
                <version>${hadoop.version}</version>
            </dependency>
        </dependencies>
    

    4.2 log4j

    配置log4j.properties,放到src/main/resources目录下
    log4j.rootCategory=INFO, stdout

    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n

    5.MapReduce运行程序常见错误以及解决办法:

    错误1.
    Exit code: 1
    Exception message: /bin/bash: 第 0 行: fg: 无任务控制
    Stack trace: ExitCodeException exitCode=1: /bin/bash: 第 0 行: fg: 无任务控制
    在客户端配置文件(mapred-site.xml)中添加如下属性:

     <property>
            <name>mapreduce.app-submission.cross-platform</name>
            <value>true</value>
     </property>
    

    注意:必须添加到Hadoop程序读取的客户端本地配置文件中,添加到客户端Hadoop安装路径中的“core-site.xml”,“mapred-site.xml”等文件中不起作用
    或者在代码中加入:

    conf.set("mapreduce.app-submission.cross-platform", "true");//表示MapReduce是跨平台运行的
    

    6. eclipse插件

    插件下载:http://download.csdn.net/download/landy8530/10106631
    安装hadoop-eclipse插件,直接把hadoop-eclipse-plugin-2.7.3.jar文件放入到eclipse安装目录下的plugins目录即可(为了安全起见,可以先把eclipse先备份一下),重启eclipse,open perspective显示map/reduce即可。

    eclipse MR插件.png 然后在 image.png

    中新增一个hdfs的配置即可看到hdfs中的文件系统。


    image.png
    image.png

    7.延伸阅读

    1. Hadoop安装与集群配置
    2. Hadoop基本知识点之HDFS
    3. Hadoop之HDFS的Java实现
    4. Hadoop之YARN的安装与测试

    事例完整代码:https://github.com/landy8530/mapreduce

    相关文章

      网友评论

        本文标题:Hadoop之MapReduce的Java实现

        本文链接:https://www.haomeiwen.com/subject/fwjcbxtx.html