Hadoop基础教程-第6章 MapReduce入门(6.4 MapReduce程序框架)(草稿)
来源:互联网 发布:lol支持mac系统吗 编辑:程序博客网 时间:2024/06/07 16:00
第6章 MapReduce入门
6.4 MapReduce程序框架
6.4.1 模版框架
我们知道,从单线程编程到多线程编程,程序结构复杂度增大了。类似的,从单机程序到分布式程序,程序结构的复杂度也增大了。这是问题的复杂环境决定的。
所以,很多初学者更接触分布式编程时,望而却步、知难而退了。可事实上,Hadoop是一个很易用的分布式编程框架,经过良好封装屏蔽了很多分布式环境下的复杂问题,因此,对普通开发者来说很容易,容易到可以依照程序模版,照葫芦画瓢。
下面代码即是Hadoop的MapReduce程序模版,其中使用了Hadoop辅助类,通过Configured的getConf()方法获取Configuration对象,重写Tool接口的run方法,实现Job提交功能。
这样就可以实现代码与配置隔离,修改MapReduce参数不需要修改java代码、打包、部署,提高工作效率。
/* * MapReduce程序模板 * 写MR程序时,复制该文件,修改类名,实现相应的map、reduce函数等 */import java.io.IOException; import java.util.StringTokenizer; // 分隔字符串import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; // 相当于int类型import org.apache.hadoop.io.LongWritable; // 相当于long类型import org.apache.hadoop.io.Text; // 相当于String类型import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.input.TextInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; /*** MapReduce程序基础模板*/public class MapReduceTemplate extends Configured implements Tool{ //静态Mapper类 public static class MapTemplate extends Mapper<LongWritable, Text, Text, IntWritable> { @Override public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { // 将输入数据解析成Key/Value对 // TODO: map()方法实现 } } //静态Reducer类 public static class ReduceTemplate extends Reducer<Text, IntWritable, Text, IntWritable> { @Override public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { // TODO: reduce() 方法实现 } } /** * */ @Override public int run(String[] args) throws Exception { //读取配置文件 Configuration conf = getConf(); //设置参数 conf.set("fs.defaultFS", "hdfs://192.168.11.81:9000"); //自定义key value 之间的分隔符(默认为tab) conf.set("mapreduce.input.keyvaluelinerecordreader.key.value.separator", ","); // Job表示一个MapReduce任务,构造器第二个参数为Job的名称。 Job job = Job.getInstance(conf, "MapReduceTemplate"); job.setJarByClass(MapReduceTemplate.class);//主类 Path in = new Path(args[0]);//输入路径 Path out = new Path(args[1]);//输出路径 FileSystem hdfs = out.getFileSystem(conf); if (hdfs.isDirectory(out)) {//如果输出路径存在就删除 hdfs.delete(out, true); } FileInputFormat.setInputPaths(job, in);//文件输入 FileOutputFormat.setOutputPath(job, out);//文件输出 job.setMapperClass(MapTemplate.class); //设置自定义Mapper job.setReducerClass(ReduceTemplate.class); //设置自定义Reducer job.setInputFormatClass(KeyValueTextInputFormat.class);//文件输入格式 job.setOutputFormatClass(TextOutputFormat.class);//文件输出格式 job.setOutputKeyClass(Text.class);//设置作业输出值 Key 的类 job.setOutputValueClass(Text.class);//设置作业输出值 Value 的类 return job.waitForCompletion(true)?0:1;//等待作业完成退出 } //主方法,程序入口,调用ToolRunner.run( ) public static void main(String[] args) throws Exception { int exitCode = ToolRunner.run(new MapReduceTemplate(), args); System.exit(exitCode); } }
将输入数据解析成Key/Value对,具体解析成何种Key/Value跟在驱动中配置的输入方式有关,比如:TextInputFormat 将每行的首字符在整个文件中的偏移量作为Key(LongWritable),本行中的所有内容作为Value(Text),KeyValueTextInputFormat 则根据默认的第一个\t 也就是tab 之前的所有内容当做Key(Text),之后全部作为Value(Text)。
问题:为什么每次运行MapReduce程序,需要将确定输出目录不存在,或者说需要用户自己先删除已经存在的输出目录?
这是因为在分布式环境下,某一目录可以有着重要的数据文件,如果MapReduce程序默认自动把输出目录删除(或者说覆写),则可能造成事故。所以输出目录需要用户自己来删除。
6.4.2 创建maven项目
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.hadron</groupId> <artifactId>mrDemo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>mrDemo</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common --> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>2.7.3</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs --> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs</artifactId> <version>2.7.3</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-client --> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>2.7.3</version> </dependency> <dependency> <groupId>jdk.tools</groupId> <artifactId>jdk.tools</artifactId> <version>1.8</version> <scope>system</scope> <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath> </dependency> </dependencies> <build> <plugins> <!-- 编码和编译和JDK版本 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf8</encoding> </configuration> </plugin> </plugins> </build></project>
其中,下面这段代码是防止@Override报错
<plugins> <!-- 编码和编译和JDK版本 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf8</encoding> </configuration> </plugin> </plugins>
本节完整的项目目录结构
6.4.3 专利引用统计
(1)问题描述
有一份 CSV 格式专利引用数据供下载,超过 1600 万行,某几行如下:
“CITING(引用)”,”CITED(被引用)”
3858241,956203
3858241,1324234
3858241,3398406
3858242,1515701
3858242,3319261
3858242,3707004
3858243,1324234
2858244,1515701
…
比如,第二行的意思是专利 3858241 引用了 1324234。换句话说,专利 1324234 被 3858241 引用。
对每个专利,我们希望找到引用它的专利并合并,输出如下:
1324234 3858243,3858241
1515701 2858244,3858242
3319261 3858242
3398406 3858241
3707004 3858242
956203 3858241
比如,专利 1324234 被[3858243,3858241]引用。
(2)上传数据文件到hdfs
[root@node1 ~]# hdfs dfs -mkdir -p /user/root/cite/input[root@node1 ~]# hdfs dfs -put cite75_99.txt /user/root/cite/input[root@node1 ~]# hdfs dfs -ls /user/root/cite/input/Found 1 items-rw-r--r-- 3 root supergroup 264075431 2017-05-29 09:57 /user/root/cite/input/cite75_99.tx
(3)编写MapReduce程序
package cn.hadron.mrDemo;import java.io.IOException;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.conf.Configured;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Job;import org.apache.hadoop.mapreduce.Mapper;import org.apache.hadoop.mapreduce.Reducer;import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat;import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;import org.apache.hadoop.util.Tool;import org.apache.hadoop.util.ToolRunner;/** * 根据MapReduce程序基础模板改写 */public class CiteMapReduce extends Configured implements Tool { //Mapper类 public static class MapClass extends Mapper<Text,Text,Text,Text> { /** * Text key:每行文件的 key 值(即引用的专利)。 * Text value:每行文件的 value 值(即被引用的专利)。 * map方法把字符串解析成Key-Value的形式,发给 Reduce 端来统计。 */ @Override public void map(Text key, Text value, Context context) throws IOException, InterruptedException { //根据业务需求(value被key引用),将key和value调换输出 context.write(value, key); } } // Reducer类 public static class ReduceClass extends Reducer< Text, Text, Text, Text> { /** * 获取map方法的key-value结果,相同Key发送到同一个reduce里处理, * 然后迭代values集合,把Value相加,结果写到 HDFS 系统里面 */ @Override public void reduce(Text key, Iterable< Text> values, Context context) throws IOException, InterruptedException { String csv = ""; //将引入相同专利编号拼接输出 for(Text val:values) { if(csv.length() > 0)csv += ","; //添加分隔符 csv += val.toString(); } context.write(key, new Text(csv)); } } @Override public int run(String[] args) throws Exception {//驱动方法run() //Configuration读取配置文件,如site-core.xml、mapred-site.xml、hdfs-site.xml等 Configuration conf = getConf(); //指定fs.defaultFS conf.set("fs.defaultFS", "hdfs://192.168.80.131:9000"); //自定义key/value之间的分隔符(默认为tab) conf.set("mapreduce.input.keyvaluelinerecordreader.key.value.separator", ","); // Job表示一个MapReduce任务,构造器第二个参数为Job的名称。 Job job = Job.getInstance(conf, "word count"); job.setJarByClass(CiteMapReduce.class);//主类 Path in = new Path(args[0]);//输入路径 Path out = new Path(args[1]);//输出路径 FileSystem hdfs = out.getFileSystem(conf); if (hdfs.isDirectory(out)) {//如果输出路径存在就删除 hdfs.delete(out, true); } FileInputFormat.setInputPaths(job, in);//文件输入 FileOutputFormat.setOutputPath(job, out);//文件输出 job.setMapperClass(MapClass.class);//设置自定义Mapper job.setReducerClass(ReduceClass.class);//设置自定义Reducer job.setInputFormatClass(KeyValueTextInputFormat.class);//文件输入格式 job.setOutputFormatClass(TextOutputFormat.class);//文件输出格式 job.setOutputKeyClass(Text.class);//设置作业输出值 Key 的类 job.setOutputValueClass(Text.class);//设置作业输出值 Value 的类 return job.waitForCompletion(true)?0:1;//等待作业完成退出 } /** * @param args输入文件、输出路径,可在Eclipse的Run Configurations中配如: */ public static void main(String[] args){ System.setProperty("HADOOP_USER_NAME", "root"); try { //程序参数:输入路径、输出路径 String[] args0 ={"/user/root/cite/input/cite75_99.txt","/user/root/cite/output/"}; //本地运行:第三个参数可通过数组传入,程序中设置为args0 //集群运行:第三个参数可通过命令行传入,程序中设置为args //这里设置为本地运行,参数为args0 int res = ToolRunner.run(new Configuration(), new CiteMapReduce(), args0); System.exit(res); } catch (Exception e) { e.printStackTrace(); } }}
(4)运行,查看结果
[root@node1 ~]# hdfs dfs -ls /user/root/cite/outputFound 2 items-rw-r--r-- 3 root supergroup 0 2017-05-30 11:14 /user/root/cite/output/_SUCCESS-rw-r--r-- 3 root supergroup 158078539 2017-05-30 11:14 /user/root/cite/output/part-r-00000
将part-r-00000文件复制到本地,然后通过tail命令查看后几行
[root@node1 ~]# hdfs dfs -get /user/root/cite/output/part-r-00000 ./rs.txt[root@node1 ~]# tail -10 rs.txt999961 5782495,5738381,5878901,4171117,4262874,5048788,4871140,4832301,4437639999965 5052613999968 3916735999971 3965843999972 4038129999973 4900344,5427610999974 5464105,4560073,4728158999977 4092587999978 3915443999983 5143114,5394715,5806555
或者直接通过hdfs dfs -tail命令查看
[root@node1 ~]# hdfs dfs -tail /user/root/cite/output/part-r-00000,5655863,5636951,6007282,4842460999829 5046201999831 5417612999832 4358252999839 4129961999840 5979106999841 4396094999850 4304144999856 4180883999858 5297301999861 5052433999880 4882467999885 4953685,4883160,4895239,4949832,4930622,5050721,5052539,5009302,4884673,4809840,4662502,4746000,4739870,5184710999890 4244270999891 4982985,4414829999892 5131331999893 4750077,5093597999895 4382808999897 5368210999899 4194295999901 4373223999904 4484614999908 4738050,4649665999909 4410316999910 4305558999913 4732393,4998735,5067721,5401032999914 546965299992 443998799993 4327613999930 5609215999932 4605176999936 5014973,5642878999940 3876070,4022472999941 5447466999945 5207231,5569166999949 5640640999951 5316622,5374468999957 5755359999961 5782495,5738381,5878901,4171117,4262874,5048788,4871140,4832301,4437639999965 5052613999968 3916735999971 3965843999972 4038129999973 4900344,5427610999974 5464105,4560073,4728158999977 4092587999978 3915443999983 5143114,5394715,5806555[root@node1 ~]#
- Hadoop基础教程-第6章 MapReduce入门(6.4 MapReduce程序框架)(草稿)
- Hadoop基础教程-第6章 MapReduce入门(6.1 MapReduce介绍)(草稿)
- Hadoop基础教程-第6章 MapReduce入门(6.2 解读WordCount)(草稿)
- Hadoop基础教程-第6章 MapReduce入门(6.3 加速WordCount)(草稿)
- Hadoop基础教程-第6章 MapReduce入门(6.5 温度统计)(草稿)
- Hadoop基础教程-第7章 MapReduce进阶(7.1 MapReduce过程)(草稿)
- Hadoop基础教程-第7章 MapReduce进阶(7.2 MapReduce工作机制)(草稿)
- Hadoop基础教程-第7章 MapReduce进阶(7.3 MapReduce API)(草稿)
- Hadoop基础教程-第7章 MapReduce进阶(7.5 MapReduce 连接)
- Hadoop基础教程-第7章 MapReduce进阶(7.6 MapReduce 二次排序)
- Hadoop基础教程-第7章 MapReduce进阶(7.7 MapReduce 全排序)
- Hadoop基础教程-第10章 HBase:Hadoop数据库(10.2 HBase基本概念、框架)(草稿)
- Hadoop基础教程-第7章 MapReduce进阶(7.4 自定义Key类型)
- Hadoop教程(三):HDFS、MapReduce、程序入门实践
- Hadoop教程(三):HDFS、MapReduce、程序入门实践
- Hadoop基础教程-第10章 HBase:Hadoop数据库(10.1 NoSQL介绍)(草稿)
- Hadoop基础教程-第10章 HBase:Hadoop数据库(10.3 HBase安装与配置)(草稿)
- Hadoop基础教程-第10章 HBase:Hadoop数据库(10.4 NTP时间同步)(草稿)
- maven构建多模块
- BOM基础
- 浏览器跨域问题
- JVM调优:选择合适的GC collector (一)
- putty、Xshell远程连接Linux以及密钥认证
- Hadoop基础教程-第6章 MapReduce入门(6.4 MapReduce程序框架)(草稿)
- hibernate
- hdu 2222 AC自动机
- 03-树2 List Leaves (25分)
- 关于C语言中随机函数的使用详解
- 快速排序
- 【算法题】字符的所有组合
- 安卓APP动态调试
- FreeBSD鱼丸系列之二:mount 挂载 windows 共享盘