Hadoop 编写WordCount
本文发表于本人博客。
前面几次讲了关于Hadoop的环境搭建、HDFS操作,今天接着继续。本来Hadoop源码中就有一个例子WordCount,但是今天我们来自己实现一个加深对这个Mapper、Reducer的理解,如有不对欢迎指正。
我们先来梳理一下思路,对于自定义Mapper以及Reducer,我们先要覆盖其map以及reduce函数,然后按照相关步骤比如设置输入文件目录、输入文件格式化类、设置自定义Mapper、分区、排序、分组、规约、设置自定义Reducer等等。这里我们把输入文件的使用空格分割(也可以用制表符来),下面是自定义Mapper类MyMapper:
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Mapper.Context; public class MyMapper extends Mapper<LongWritable, Text, Text, LongWritable> { @Override
protected void map(LongWritable key, Text value,Context context) throws IOException, InterruptedException {
String[] splied = value.toString().split(" ");
for (int i = 0; i < splied.length; i++) {
String lineWord = splied[i];
context.write(new Text(lineWord), new LongWritable(1));
}
}
}
这里我选择的是新的API,相关库基本是在org.apache.hadoop.mapreduce下,旧API是在org.apache.hadoop.mapred下,包括一些引用库也是这样。自定义MyMapper是泛型继承Mapper,其中参数key\value是Hadoop内部类型,它不支持java的基本类型这里我们需要注意下为什么不选择java的基本类型呢,原因是不需要其它额外是操作,而且本身需要序列化反序列化并提升其性能所以加入了hadoop的类型放弃java的基本类型。关于hadoop key\value跟java基本类型相互转换的问题也很简单,从java基本类型转换至hadoop的key\value的话直接new带参就可以了,从hadoop的key\value类型转换至java的基本类型使用get方法就可以了!如:
LongWritable lw = new LongWritable(1L);
long temp = lw.get();
接下来继续看自定义Reducer类MyReduce:
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.Reducer.Context; public class MyReduce extends Reducer<Text, LongWritable, Text, LongWritable> { @Override
protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
long count = 0L;
for(LongWritable value: values) {
count += value.get();
}
context.write(key, new LongWritable(count));
}
}
这个跟上面类似了,再来看看main方法的如何执行的!
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputFormat;
import org.apache.hadoop.mapreduce.Job;
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.mapreduce.lib.partition.HashPartitioner; import com.sun.org.apache.xpath.internal.axes.HasPositionalPredChecker; public class Test {
static final String OUTPUT_DIR = "hdfs://hadoop-master:9000/mapreduce/output/";
static final String INPUT_DIR = "hdfs://hadoop-master:9000/mapreduce/input/test.txt"; public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = new Job(conf, Test.class.getSimpleName());
deleteOutputFile(OUTPUT_DIR); //1设置输入目录
FileInputFormat.setInputPaths(job, INPUT_DIR);
//2设置输入格式化类
job.setInputFormatClass(TextInputFormat.class);
//3设置自定义Mapper以及键值类型
job.setMapperClass(MyMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
//4分区
job.setPartitionerClass(HashPartitioner.class);
job.setNumReduceTasks(1);
//5排序分组
//6设置在自定义Reduce以及键值类型
job.setReducerClass(MyReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//7设置输出目录
FileOutputFormat.setOutputPath(job, new Path(OUTPUT_DIR));
//8提交job
job.waitForCompletion(true);
} static void deleteOutputFile(String path) throws Exception{
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI(INPUT_DIR),conf);
if(fs.exists(new Path(path))){
fs.delete(new Path(path));
}
}
}
执行的时候先会输出上次执行过的输出目录。然后就按照步骤:
1.设置输入文件目录;
2.输入文件格式化类;
3.设置自定义Mapper以及其键值类型;
4.分区;
5.排序;
6.分组;
7.规约;
8.设置自定义Reducer以及其键值类型;
9.设置输出目录;
10.代码提交至JobTracker。
当然这过程中有些是可以省略的比如输出文件格式化类。从这个例子我们可以得出:既然可以设置自定义Mapper以及自定义Reducer,那么也应该可以设置自定义的输入文件格式化类以及分区、排序、分组、规约等等,这个以后会有相关的笔记现在这里只是写个简单的例子。我们编写一个文件如下并把它上传至hdfs://hadoop-master:9000/mapreduce/input/test.txt:
luoliang me
asura asura.com luoliang
me
然后执行main函数,将会在hdfs://hadoop-master:9000/mapreduce/output/目录下输出一个类似part-*的文件,我们可以使用如下命令查看:
hadoop fs -text /output/part-*
此时会输出:
asura 1
asura.com 1
luoliang 2
me 2
现在文件是输出了也对比下是正确,但是脑子还是一片空白,不知道其怎么做到的,那么这个就是关于mapreduce的原理了,下面我也说说大概其原理:从把代码提交至JobTracker开始,它就会从指定的输入文件路径去获取文件,这里支持多个文件以及二级目录下的多个文件,这里获取就是使用的HDFS api来操作了!把所有文件读取出来之后按照指定的大小进行分割InputSplit,把分割好后的键值FileSplit(比如:<0,"luoliang me">,<13,"asura asura.com luoliang">)再转化为RecordReader(比如<"luoliang",1>,<"luoliang",1>),此时全部转换完毕后会每个都调用map函数,map函数把数据写入到Mapper.Context中,再会对数据进行分区排序分组规约,最后通过shuffle到达reduce端,这其中每个map的输出数量是等于reduce的输入数量。到达reduce端数据已经发生了质变了不在是<"luoliang",1>而是类似变成<"luoliang",{1,1}>这样的键值数据,这是我们需要迭代获取总数量并在写会context中,计算完后输出到指定的目录。在这里由于有重复的单词所以map函数的调用次数跟reduce函数调用次数是不同的。规约这个其实就是自定义reduce,但是这个不是必须有的因为如果是统计关于类似平均数的问题,数据在map端进行规约了,虽然传送时间以及处理时间减少性能提升了但是对于最终结果可能会有影响,所以这个规约要看具体情况才能使用。至于这个shuffle一步还不是怎么了解需要多多再看看。
这次先到这里。坚持记录点点滴滴!
Hadoop 编写WordCount的更多相关文章
- 大数据之路week07--day03(Hadoop深入理解,JAVA代码编写WordCount程序,以及扩展升级)
什么是MapReduce 你想数出一摞牌中有多少张黑桃.直观方式是一张一张检查并且数出有多少张是黑桃. MapReduce方法则是: 1.给在座的所有玩家中分配这摞牌 2.让每个玩家数自己手中的牌有几 ...
- hadoop的wordcount例子运行
可以通过一个简单的例子来说明MapReduce到底是什么: 我们要统计一个大文件中的各个单词出现的次数.由于文件太大.我们把这个文件切分成如果小文件,然后安排多个人去统计.这个过程就是”Map”.然后 ...
- indows Eclipse Scala编写WordCount程序
Windows Eclipse Scala编写WordCount程序: 1)无需启动hadoop,因为我们用的是本地文件.先像原来一样,做一个普通的scala项目和Scala Object. 但这里一 ...
- 5行代码怎么实现Hadoop的WordCount?
初学编程的人,都知道hello world的含义,当你第一次从控制台里打印出了hello world,就意味着,你已经开始步入了编程的大千世界,这和第一个吃螃蟹的人的意义有点类似,虽然这样比喻并不恰当 ...
- Hadoop中wordcount程序
一.测试过程中 输入命令: 首先需要在hadoop集群中添加文件 可以首先进行查看hadoop集群中文件目录 hadoop fs -ls / hadoop fs -ls -R / hadoop fs ...
- [Linux][Hadoop] 运行WordCount例子
紧接上篇,完成Hadoop的安装并跑起来之后,是该运行相关例子的时候了,而最简单最直接的例子就是HelloWorld式的WordCount例子. 参照博客进行运行:http://xiejiangl ...
- 伪分布式环境下命令行正确运行hadoop示例wordcount
首先确保hadoop已经正确安装.配置以及运行. 1. 首先将wordcount源代码从hadoop目录中拷贝出来. [root@cluster2 logs]# cp /usr/local/h ...
- 一个可以跑的Hadoop的WordCount程序
搭个新环境时总要折腾一下,于是干脆记下来. 程序: package com.my; import java.io.IOException; import java.util.Iterator; imp ...
- hadoop执行wordcount例子
1:下载hadoop.http://mirror.esocc.com/apache/hadoop/common/hadoop-1.2.1/hadoop-1.2.1.tar.gz 2:解压. tar - ...
随机推荐
- 赠 看穿一切的var_dump
看穿一切的var_dump同学让我送他一首诗,于是作诗如下: 看穿一切被看穿,莫让年少酿毒烟.骄心当制能补拙,拨开云雾见上仙!
- swift - UISegmentedControl 和 UIWebView 的用法
这两个用法比较简单: 具体代码如下: 一.UISegmentedControl 1.UISegmentedControl的声明 var segment = UISegmentedControl() 2 ...
- 【RF库Collections测试】Copy Dictionary
Name: Copy DictionarySource:Collections <test library>Arguments:[ dictionary ]Returns a copy o ...
- docker run 详解
docker run 用于把镜像启动为容器,语法如下: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 常见用法: [root@localhost ~]$ ...
- php学习九:存取器&魔术方法
当声明属性的时候用到了private,那么的话只能本类中才能访问此属性,其他地方无法使用,这个时候需要给外界提供一些方法来使外界访问 方法一:存取器: 可以提供一个public的方法来使外界对类里面的 ...
- Java中DESKeySpec类
此类位于 javax.crypto.spec 包下.声明如下: public class DESKeySpec extends Object implements KeySpec 此类指定一个 DES ...
- Linux就是这个范儿之第一次亲密接触(2)
原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 .作者信息和本声明.否则将追究法律责 1.2 不一样的图形操作 几乎所有Linux的新用户都会认为Linux的图形界面是相当的绚丽又多彩. ...
- XML的一些点
最近学习Spring会配置许多XML文件,没有系统学习过XML遇到了许多问题,系统的看了一下有些拨云见日的感觉. 推荐学习:http://www.w3school.com.cn/xml/xml_int ...
- 对规范中每个模块只允许一个id的理解
优点: 每个模块只有一个ID,并且在css中不适用ID,ID从模板中传入js中,则该模块的复用灵活性会非常高.想要复用该模块时,只需要改动两个地方.一个是html中的ID,另外一个是写到全局conf. ...
- IE8及以下的数组处理与其它浏览器的不同
在解决search-box的bug时,由于IE8-的数组处理与其它浏览器的不同,而导致报错. 示例:arr=[1,3,3,]; 当数组的最后是一个逗号时: IE9+默认 arr=[1,3,3];也就是 ...