建立一个普通的Java项目,编写MapReduce程序

1.程序初始化

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

打开 File->New->Project菜单,选择Java便可,逐步点击Next,在目录D:\Java\hadoop\mr下建立一个项目名称。java

这里咱们建立的项目叫groupbysum,表示groupbysum MapReduce小项目。apache

之后各类功能的mapreduce程序均已小项目形式放在mr目录下。数组

其实咱们也能够把mr建立为一个项目(相似空间),各个小mapreduce程序做为modules(项目)放在该项目(空间)下,但这种方式通常是是大项目,分组协同开发各个模块功能的时候使用较多,这里就不采用了,一次只开发一个项目。网络

2.导入Hadoop核心依赖包

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

  • 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:\Java\hadoop\jar,到这里功能上已经能够用了,可是为了便于区分管理咱们导入的Jar包,这里能够点击这个目录,选择右侧的小铅笔(EDIT),给这些包在这个项目里起一个分组名称,这里咱们起了hadoop-2.7.6。工具

3.编写mapreduce程序

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

这里咱们选择分开写,增长对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. http://www.javashuo.com/article/p-zgdtgrim-dm.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项目,导入外部依赖。参见一、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,博客园传不了,如须要自行下载或留言索取。

相关文章
相关标签/搜索