本文发表于本人博客

前面几次讲了关于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的更多相关文章

  1. 大数据之路week07--day03(Hadoop深入理解,JAVA代码编写WordCount程序,以及扩展升级)

    什么是MapReduce 你想数出一摞牌中有多少张黑桃.直观方式是一张一张检查并且数出有多少张是黑桃. MapReduce方法则是: 1.给在座的所有玩家中分配这摞牌 2.让每个玩家数自己手中的牌有几 ...

  2. hadoop的wordcount例子运行

    可以通过一个简单的例子来说明MapReduce到底是什么: 我们要统计一个大文件中的各个单词出现的次数.由于文件太大.我们把这个文件切分成如果小文件,然后安排多个人去统计.这个过程就是”Map”.然后 ...

  3. indows Eclipse Scala编写WordCount程序

    Windows Eclipse Scala编写WordCount程序: 1)无需启动hadoop,因为我们用的是本地文件.先像原来一样,做一个普通的scala项目和Scala Object. 但这里一 ...

  4. 5行代码怎么实现Hadoop的WordCount?

    初学编程的人,都知道hello world的含义,当你第一次从控制台里打印出了hello world,就意味着,你已经开始步入了编程的大千世界,这和第一个吃螃蟹的人的意义有点类似,虽然这样比喻并不恰当 ...

  5. Hadoop中wordcount程序

    一.测试过程中 输入命令: 首先需要在hadoop集群中添加文件 可以首先进行查看hadoop集群中文件目录 hadoop fs -ls / hadoop fs -ls -R / hadoop fs ...

  6. [Linux][Hadoop] 运行WordCount例子

    紧接上篇,完成Hadoop的安装并跑起来之后,是该运行相关例子的时候了,而最简单最直接的例子就是HelloWorld式的WordCount例子.   参照博客进行运行:http://xiejiangl ...

  7. 伪分布式环境下命令行正确运行hadoop示例wordcount

    首先确保hadoop已经正确安装.配置以及运行. 1.     首先将wordcount源代码从hadoop目录中拷贝出来. [root@cluster2 logs]# cp /usr/local/h ...

  8. 一个可以跑的Hadoop的WordCount程序

    搭个新环境时总要折腾一下,于是干脆记下来. 程序: package com.my; import java.io.IOException; import java.util.Iterator; imp ...

  9. hadoop执行wordcount例子

    1:下载hadoop.http://mirror.esocc.com/apache/hadoop/common/hadoop-1.2.1/hadoop-1.2.1.tar.gz 2:解压. tar - ...

随机推荐

  1. 超全面的JavaWeb笔记day09<Servlet&GenericServlet&HttpServlet&ServletContext>

    1.Servlet概述 2.Servlet接口 3.GenericServlet 4.HttpServlet 5.Servlet细节 6.ServletContext(重要) Servlet概述 生命 ...

  2. cocos2d-x游戏引擎核心之五——触摸事件和触摸分发器机制

    一.触摸事件 为了处理屏幕触摸事件,Cocos2d-x 提供了非常方便.灵活的支持.在深入研究 Cocos2d-x 的触摸事件分发机制之前,我们利用 CCLayer 已经封装好的触摸接口来实现对简单的 ...

  3. 什么是"抓包"?怎样"抓包"?

    你是网络管理员吗?你是不是有过这样的经历:在某一天的早上你突然发现网络性能急剧下降,网络服务不能正常提供,服务器访问速度极慢甚至不能访问,网络交换机端口指示灯疯狂地闪烁.网络出口处的路由器已经处于满负 ...

  4. poj_2441 状态压缩dp

    题目大意 N头牛,M个谷仓,每个牛c都有它喜欢的若干个谷仓,现在要将这N头牛安排进谷仓,使得每个牛都位于它喜欢的谷仓,而每个谷仓只能有一头牛.求安排的方案总数.N, M <= 20 题目分析 将 ...

  5. 重装Delphi10.2的IDE必要设置

    重装Delphi10.2的IDE必要设置: 1,Tools->Options Editor Options->Display 右侧的 Right margin: 设为200 这个设置是为右 ...

  6. replace方法的深入理解

    “abc”.replace(/b/, "$`") // $`将正则匹配到的字符替换为匹配到的字符左边的字符 aac “abc”.replace(/b/, "$'" ...

  7. java.util.ConcurrentModificationException 多线程访问ArrayList引起

    http://blog.csdn.net/androiddevelop/article/details/21509345   Java ConcurrentModificationException ...

  8. 统计文件中单词的个数---Shell及python版

    最近在看shell中有个题目为统计单词的个数,使用了awk功能,代码如下 #!/bin/bash ];then echo "Usage:basename $0 filename" ...

  9. Android dialog 全屏

    Android中让Dialog全屏: 一.在style中定义样式: <?xml version="1.0" encoding="utf-8"?> & ...

  10. IDEA 配置

    配置sublime主题: 击链接 http://www.riaway.com,选择并下载自己喜欢的主题 file -->import setting  到刚刚下载的主题jar包,之后导入,重起i ...