zoukankan      html  css  js  c++  java
  • 创建一个普通的Java项目,编写MapReduce程序

    1.程序初始化

    此常规Java项目,不是Maven项目,也不是Java Enterprise项目。

    打开 File->New->Project菜单,选择Java即可,逐步点击Next,在目录D:Javahadoopmr下创建一个项目名称。

    这里我们创建的项目叫groupbysum,表示groupbysum MapReduce小项目。

    以后各种功能的mapreduce程序均已小项目形式放在mr目录下。

    其实我们也可以把mr创建为一个项目(类似空间),各个小mapreduce程序作为modules(项目)放在该项目(空间)下,但这种方式一般是是大项目,分组协同开发各个模块功能的时候使用较多,这里就不采用了,一次只开发一个项目。

    2.导入Hadoop核心依赖包

    导入执行mapreduce程序依赖的Hadoop包:

    • hadoop-core-1.2.1
    • hadoop-hdfs-2.7.6
    • hadoop-client-2.7.6
    • hadoop-auth-2.7.6
    • hadoop-mapreduce-client-core-2.7.6
    • commons-io-2.6
    • commons-logging-1.2

    Apache Commons IO : 主要是文件处理,比如复制、输入输出、文件名处理、大小写敏感等等。

    The Apache Commons IO library contains utility classes, stream implementations, file filters, file comparators, endian transformation classes, and much more.

    导入操作:打开项目结构(CTRL+ALT_SHIFT+S 或者使用工具栏的 图标 ),点击Modules,切换tab标签到Dependencies,点击 +  加号,选择准备好的包含这些Jar包的目录D:Javahadoopjar,到这里功能上已经可以用了,但是为了便于区分管理我们导入的Jar包,这里可以点击这个目录,选择右侧的小铅笔(EDIT),给这些包在这个项目里起一个分组名称,这里我们起了hadoop-2.7.6。

    3.编写mapreduce程序

    写Java类,通常有两种方式,一种是类中类,只写一个Java文件,一种是一个类一个Java文件,多个Java文件。

    这里我们选择分开写,增加对mapreduce原理对认识和理解。

    创建包体,右击src,new->package,输入包名,这里我们命名包为com.leeyk99.com。(这个包名写的瞎眼了,后续会写com.leeyk99.hadoop)

    EN50f251c1EN50f251d1EN50f251e1EN50f251f0

    重点参考:

    1. https://www.cnblogs.com/bovenson/p/6275762.html?utm_source=itdadao&utm_medium=referral

    2. https://www.cnblogs.com/hunttown/p/5810591.html

    3. https://hadoop.apache.org/docs/current/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html

    4. 个人学习的Java代码(文件和目录io代码 ioReadWrite.java)

    意外发现:

    因为之前在公司通过Maven创建了WordCount官方示例MR项目,仅在pom.xml中配置了最重要的几个Hadoop jar包依赖,成功运行。实际上Maven项目自动下载了相关的jar包,比如jackson-core-asl-1.9.13.jar、commons-configuration-1.10.ja等。

    <!-- 基础依赖hadoop-core和hadoop-common -->
    
    <!--hadoop-core的version一般为1.2.1-->
    
    <dependency>
    
    <groupId>org.apache.hadoop</groupId>
    
    <artifactId>hadoop-core</artifactId>
    
    <version>1.2.1</version>
    
    </dependency>
    
    <!--hadoop-common的version可以依照你的实际需要来-->
    
    <dependency>
    
    <groupId>org.apache.hadoop</groupId>
    
    <artifactId>hadoop-common</artifactId>
    
    <version>2.7.6</version>
    
    </dependency>
    
    <!--如果需要读写HDFS,则还需要依赖hadoop-hdfs和hadoop-client-->
    
    <dependency>
    
    <groupId>org.apache.hadoop</groupId>
    
    <artifactId>hadoop-hdfs</artifactId>
    
    <version>2.7.6</version>
    
    </dependency>
    
    <dependency>
    
    <groupId>org.apache.hadoop</groupId>
    
    <artifactId>hadoop-client</artifactId>
    
    <version>2.7.6</version>
    
    </dependency>

    在这个普通Java项目导入第2步指定的jar包,报告了很多类缺失错误,最后都一一找来了。故,实际依赖完整的Jar包如下:

    • commons-cli-1.4.jar
    • commons-configuration-1.10.jar
    • commons-httpclient-3.1.jar (这个就是去了一个warn)
    • commons-io-2.6.jar
    • commons-lang-2.6.jar
    • commons-logging-1.2.jar
    • hadoop-auth-2.7.6.jar
    • hadoop-client-2.7.6.jar
    • hadoop-common-2.7.6.jar
    • hadoop-core-1.2.1.jar
    • hadoop-hdfs-2.7.6.jar
    • hadoop-mapreduce-client-core-2.7.6.jar
    • jackson-core-asl-1.9.13.jar
    • jackson-mapper-asl-1.8.8.jar

    导入这些包后,运行无误。

    故,在对Hadoop的包的功能基本了解或者实际开发的时候,为提高效率,可以使用Maven项目。

    4.MapReduce学习总结

    本次Hadoop MR学习总结,主要集中在对整体运行逻辑和局部编写细节的学习和测试,源码原理未研究。

    4.1单维度单度量统计

    该MR程序测试了单度量在单维度上聚合统计的情形,即常用的:

    select dim_a,sum(kpi_a) from table_name group by dim_a

    4.2继承Mapper类,重写map方法

    GroupBySumMapper类继承抽象类:org.apache.hadoop.mapreduce.Mapper (新API)。(旧API:extends MapReduceBase implements Mapper<LongWritable, Text, Text, DoubleWritable>)

    Mapper是一个泛型类型,有四个形参,分别是map函数的输入键、输入值、输出键、输出值。泛型类型的形参只能是引用类型,不能是原始类型(如int、double、char)。

    Hadoop提供了一套可优化网络序列化传输的引用类型(LongWritable、Text、DoubleWritable、IntWritable),而不是直接用Java的引用类型(Long、String、Double、Integer,被hadoop提供的四个类型替代).

    map函数是对一行记录进行处理,数据集的每一行是输入,输入键就是相对于文件起始位置的偏移量(如果从第一行开始,就是行号了),因为Hadoop通常是处理大数据量,因此输入键类型通常指定为 LongWritable.

    获取到一行记录后,将行转换成成Java的String类型,提取相应的数据域(列),常用的方法:

    • a.无分隔符但每组数据长度都是固定的,可以使用字符串截取,比如substring;
    • b.有分隔符,可以使用split按分隔符分隔得到数组,获取特定的数组元素;
    • c.使用StringTokenizer(标记)类及其nextToken方法,按顺序依次获取数据列;

    获取到指定数据域后,conntext.write将结果输出,写出到临时文件,作为reduce函数的输入。

    map任务将其输出写到本地硬盘,而非HDFS。因为map的输出只是中间结果,一旦作业完成,map的输出即可以删除,存储到HDFS并实现备份,难免小题大做(说白了,占用存储,数据备份也需要时间和带宽)。

    4.3继承Reducer类,重写reduce方法

    reduce函数以map的输出作为输入,因此reduce函数的输入键、输入值和map的输出键、输出值类型需要是一致的,这种情况下reduce函数的输出类型也必须是Text和DoubleWritable。

    reduce函数实现的操作通常是对输入值的遍历处理,比如求和、计数、比较、取均、去重等多种运算,然后将结果输出,写入到HDFS,作为最终产出结果。

    4.4Hadoop Job配置及启动

    Job对象指定作业执行规范。可以将代码打包成Jar文件,发不到Hadoop集群。不必指明JAR文件名称,在Job对象的setJarByClass(GroupBySumRun.class)方法中传递类即可。Hadoop会根据这个类查找相关的JAR文件.

    构造Job对象后,指定输入(调用FileInputFormat类的静态方法addInputPath(),可以多次调用实现多路径输入,路径可以是单个文件、一个目录、符合特定模式的一些列文件)、输出(调用FileOutputFormat类的静态方法setOutputPath(),只能一个,且在运行前不能存在)路径。

    接着setMapperClass、setReducerClass指定要使用的map类型、reduce类型。至于setCombinerClass根据需要来使用。combiner是对map的输出在MR框架混洗后的分组结果,进行组内计算,减少需要传递给reduce函数的数据量。

    setOutputKeyClass()、setOutputValueClass()控制reduce函数的输出类型,并且必须和Reduce类产生的相匹配,map函数的输出类型默认情况下和reduce函数是相同的,因此mapper产生出和reducer函数相同的类型时,不需要单独设置map的输出类型,否则需要通过setMapOutputKeyClass()、setMapOutputValueClass()方法来设置map函数的输出类型。

    文件的输入输出:

    输入的类型通过输入格式来控制,setInputFormatClass(),如果不指定,则使用默认的格式TextInputFormat.class(文本输入格式);

    输出的类型通过输出格式来控制,setOutputFormatClass(),如果不指定,则使用默认的格式TextOutputFormat.class(文本输入格式).


    设置完成后,可以开始运行作业。waitForCompletion()方法提交作业并等待执行完成。其参数true表示作业会把其进度信息写到控制台,返回结果是布尔值,true-成,false-败。

    这个例子的代码不是最简洁的,后续参照《Hadoo权威指南》再写个 简洁点的。

    4.5Java io温习

    由于reduce函数的输出目录在运行前必须不存在,为方便调试代码,不用每次都去手动删目录,写了DelOutputDir类,在提交作业前执行删除output目录及其目录下文件的方法。

    这个方法要求output目录里只有文件,不能有目录,因为代码未对子目录作处理。

    4.6 Intellij IDEA使用技巧

    使用Intellij IDEA创建一个常规Java项目,导入外部依赖。参见1、2步。

    这里未使用导入libraries的方法(这个是最推荐的方法,创建lib目录,添加JAR文件,后续尝试)。

    5.MR程序打包提交到集群

    Inerllij IDEA将程序打包成JAR文件,主要是做两件事:1.创建MANIFEST.MF文件,这个文件指定MAIN CLASS的位置(包);2.将MANIFEST.MF和编译后的class文件一起打包。

    打开IDEA的项目结构 (CTRL+SHILT+ALT+S 或者 快捷图标 ),在Artifacts菜单中新建一个空JAR文件,如果有就进行配置即可。流程步骤:(未完待续)

    Image  ---》


    6.代码、JAR包、测试数据下载

    https://files.cnblogs.com/files/leeyuki/code.rar 代码

    JAR包大于10M,博客园传不了,如需要自行下载或留言索取。

  • 相关阅读:
    JavaAPI基础(1)
    类与对象、封装、构造方法
    Java语言基础
    Request请求的应用
    Response的应用
    java生成动态验证码
    Servlet的配置
    常见的状态码。。
    简单学习【1】——打包JS
    NodeJS2-2环境&调试----引用系统内置模块,引用第三方模块
  • 原文地址:https://www.cnblogs.com/leeyuki/p/9516310.html
Copyright © 2011-2022 走看看