本文发表于本人博客

前面几次讲了关于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. 【VR】Leap Motion 官网文档 FingerModel (手指模型)

    前言: 感谢关注和支持这个Leap Motion系列翻译的朋友们,非常抱歉因为工作原因非常久没有更新,今后这个翻译还会继续(除非官方直接给出中文文档).本篇献给大家的是 <FingerModel ...

  2. 超全面的JavaWeb笔记day15<mysql数据库>

    1.数据库的概述 2.SQL 3.DDL 4.DML 5.DCL 6.DQL MySQL 数据库 1 数据库概念(了解) 1.1 什么是数据库 数据库就是用来存储和管理数据的仓库! 数据库存储数据的优 ...

  3. Loadrunner windows计数器

    object (对象) Counters (计数器名称) Description (描述) 参考值 Memory Available Mbytes 可用物理内存数.如果该值很小(4MB或更小),则说明 ...

  4. 【RF库Collections测试】Dictionary Should Contain Sub Dictionary

    Name:Dictionary Should Contain Sub DictionarySource:Collections <test library>Arguments:[ dict ...

  5. /etc/redhat-release

    该文件用于记录 RedHat 的发行版本信息 [root@localhost ~]$ cat /etc/redhat-release CentOS release 6.5 (Final)

  6. Oracle的闪回操作

    Oracle10g中引入了闪回技术,但这并不意味着所有的表都能闪回成功,当没有足够的磁盘空间,Oracle将使用回收站中的磁盘空间,而且位图连接索引和引用完整性约束也不受回收站的保护. recycle ...

  7. webstorm编译less和scss

    Webstorm 配置less编译的Arguments参数: $FileName$ $FileParentDir$\ccy\ccy1\ccy2\$FileNameWithoutExtension$.c ...

  8. PHP之语句

    前面的话 任何 PHP 脚本都是由一系列语句构成的.一条语句可以是一个赋值语句,一个函数调用,一个循环,一个条件语句或者甚至是一个什么也不做的语句(空语句).语句通常以分号结束.此外,还可以用花括号将 ...

  9. CSS- ie6,ie7,ie8 兼容性写法,CSS hack写法

    css ie6,ie7,ie8 兼容性写法,CSS hack写法 margin-bottom:40px;       /*ff的属性*/margin-bottom:140px\9;    /* IE6 ...

  10. LeetCode——Search a 2D Matrix II

    Description: Write an efficient algorithm that searches for a value in an m x n matrix. This matrix ...