在hadoop生态中,wordcount是hadoop世界的第一个hello world程序。

wordcount程序是用于对文本中出现的词计数,从而得到词频,本例中的词以空格分隔。

关于mapper、combiner、shuffler、reducer等含义请参照Hadoop权威指南里的说明。

代码参考:https://github.com/asker124143222/wordcount

1、hadoop平台搭建

参照之前的帖子搭一个伪分布式的hadoop就可以。链接:https://www.cnblogs.com/asker009/p/9126354.html

2、新建一个普通console程序,引入maven框架。

引入hadoop核心依赖,注意hadoop平台用的3.1版本,引入的依赖尽量使用这个版本,以免出现版本兼容问题

  1. <dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-core</artifactId>
    <version>1.2.1</version>
    </dependency>
  2.  
  3. <dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>3.1.0</version>
    </dependency>
  4.  
  5. <dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-hdfs</artifactId>
    <version>3.1.0</version>
    </dependency>
  6.  
  7. <dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-hdfs-client</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
    </dependency>

检查版本

  1. [hadoop@hp4411s ~]$ hadoop version
  2. Hadoop 3.1.
  3. Source code repository https://github.com/apache/hadoop -r 16b70619a24cdcf5d3b0fcf4b58ca77238ccbe6d
  4. Compiled by centos on --30T00:00Z
  5. Compiled with protoc 2.5.
  6. From source with checksum 14182d20c972b3e2105580a1ad6990
  7. This command was run using /opt/hadoop/hadoop-3.1./share/hadoop/common/hadoop-common-3.1..jar

3、编写mapper

  1. import org.apache.hadoop.io.IntWritable;
  2. import org.apache.hadoop.io.Text;
  3. import org.apache.hadoop.mapreduce.Mapper;
  4.  
  5. import java.io.IOException;
  6.  
  7. /**
  8. * @Author: xu.dm
  9. * @Date: 2019/1/29 16:44
  10. * @Description: 读取采用空格分隔的字符,并且每个词计数为1
  11. */
  12. public class WordCountMapper extends Mapper<Object, Text, Text, IntWritable> {
  13. @Override
  14. protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
  15. String line = value.toString();
  16. String[] words = line.split(" ");
  17. for (String word : words) {
  18. System.out.println(word);
  19. context.write(new Text(word), new IntWritable(1));
  20. }
  21. }
  22. }
  1.  
  1. Mapper类是一个泛型类型,它有四个形参类型,分别指定map函数的输入键、输入值、输出键、输出值的类型。hadoop没有直接使用Java内嵌的类型,而是自己开发了一套可以优化网络序列化传输的基本类型。这些类型都在org.apache.hadoop.io包中。
  2. Object类型,适用于字段需要使用多种类型的时候,Text类型相当于Java中的String类型,IntWritable类型相当于Java中的Integer类型
  1. context它是mapper的一个内部类继承自MapContext,是为了在map或是reduce任务中跟踪task的状态,记录map执行的上下文。
    mapper类中,这个context可以存储一些job conf的信息,比如job运行时参数等,程序可以在map函数中处理这个信息,这种方式是Hadoop中参数传递中很常见,context作为了mapreduce执行中各个函数的一个桥梁。

4、编写reducer

  1. import org.apache.hadoop.io.IntWritable;
  2. import org.apache.hadoop.io.Text;
  3. import org.apache.hadoop.mapreduce.Reducer;
  4.  
  5. import java.io.IOException;
  6.  
  7. /**
  8. * @Author: xu.dm
  9. * @Date: 2019/1/29 16:44
  10. * @Description:累加由map传递过来的计数
  11. */
  12. public class WordCountReducer extends Reducer<Text,IntWritable,Text,IntWritable> {
  13. @Override
  14. protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
  15. int sum = 0;
  16. for(IntWritable val:values)
  17. {
  18. sum+=val.get();
  19. }
  20. context.write(key,new IntWritable(sum));
  21. }
  22. }

5、关于shuffle过程,shuffle过程是由hadoop系统内部完成,shuffle是在map和reduce之间,对map的结果进行清洗、组合的过程。

借用hadoop权威指南里的一个图来类比说明

假设我们的数据样本是:

那么在map阶段形成的数据是:

  1. hadoop 1
  2. hadoop 1
  3. abc 1
  4. abc 1
  5. test 1
  6. test 1
  7. wow 1
  8. wow 1
  9. wow 1
  10. ... ...

经过shuffle后大概是这样:

  1. abc [1,1]
    hadoop [1,1]
  2. test [1,1]
  3. wow [1,1,1]
  4. ... ...

shuffle对Map的结果进行排序并传输到Reduce进行处理 Map的结果并直接存放到硬盘,而是利用缓存做一些预排序处理 Map会调用Combiner,压缩,按key进行分区、排序等,尽量减少结果的大小 每个Map完成后都会通知Task,

然后Reduce就可以进行处理,shuffle其实就是性能关键点。shuffle的结果传递给reduce,reduce根据需求决定如何处理这些数据,本例中就是简单的求和。

6、程序入口,任务调度执行等

  1. import org.apache.hadoop.conf.Configuration;
  2. import org.apache.hadoop.fs.FileSystem;
  3. import org.apache.hadoop.fs.Path;
  4. import org.apache.hadoop.io.IntWritable;
  5. import org.apache.hadoop.io.Text;
  6. import org.apache.hadoop.mapreduce.Job;
  7. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  8. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  9.  
  10. public class WordCount {
  11.  
  12. public static void main(String[] args) throws Exception {
  13. if(args.length!=2)
  14. {
  15. System.err.println("使用格式:WordCount <input path> <output path>");
  16. System.exit(-1);
  17. }
  18. //Configuration类代表作业的配置,该类会加载mapred-site.xml、hdfs-site.xml、core-site.xml等配置文件。
  19. Configuration conf =new Configuration();
  20.  
  21. Path outPath = new Path(args[1]);
  22. //FileSystem里面包括很多系统,不局限于hdfs
  23. FileSystem fileSystem = outPath.getFileSystem(conf);
  24. //删除输出路径
  25. if(fileSystem.exists(outPath))
  26. {
  27. fileSystem.delete(outPath,true);
  28. }
  29.  
  30. Job job = Job.getInstance(conf,"word count"); // new Job(conf, "word count");
  31. job.setJarByClass(WordCount.class);
  32.  
  33. job.setMapperClass(WordCountMapper.class);
  34. //Combiner最终不能影响reduce输出的结果
  35. // job.setCombinerClass(WordCountReducer.class);
  36. job.setReducerClass(WordCountReducer.class);
  37.  
  38. //一般情况下mapper和reducer的输出的数据类型是一样的,如果不一样,可以单独指定mapper的输出key、value的数据类型
  39. //job.setMapOutputKeyClass(Text.class);
  40. //job.setMapOutputValueClass(IntWritable.class);
    //输入类型通过InputFormat类来控制
  41. //hadoop默认的是TextInputFormat和TextOutputFormat,本例就是对文本进行处理所以可以不用配置。
  42. //job.setInputFormatClass(TextInputFormat.class);
  43. //job.setOutputFormatClass(TextOutputFormat.class);
  44.  
  45. job.setOutputKeyClass(Text.class);
  46. job.setOutputValueClass(IntWritable.class);
  47.  
  48. //指定的这个路径可以是单个文件、一个目录或符合特定文件模式的一系列文件。
  49. //从方法名称可以看出,可以通过多次调用这个方法来实现多路径的输入。
  50. FileInputFormat.addInputPath(job,new Path(args[0]));
  51.  
  52.      //在运行job前,这个目录不应该存在,如果存在hadoop会拒绝执行。这种预防措施的目的是防止数据丢失(长时间的job被意外覆盖)
  53. FileOutputFormat.setOutputPath(job,new Path(args[1]));
  54.  
  55. System.exit(job.waitForCompletion(true) ? 0 : 1);
  56. }
  57. }

7、放入hadoop平台中执行

  1. 1、打成wordcount.jar
  2. 2、上传jar包到hadoop用户目录下
  3. 3、在hadoop用户目录下,用vi生成一个测试文档wc.input,里面随意填入一些词,用空格分隔词。本例中是:
    [hadoop@hp4411s ~]$ cat wc.input
    hadoop hadoop abc abc test test wow
    wow wow
    dnf dnf dnf dnf
    wow
    hd cd
    ef hs
    xudemin wow wow
    xudemin dnf dnf
    dnf mytest
  4. 4、将wc.input上传到hdfs文件系统中的/demo/input
    hadoop fs -mkdir -p /demo/input
    hadoop fs -put wc.input /demo/input
    hadoop fs -ls /demo/input
  5.  
  6. 5、用hadoop执行jar包,输出结果到/demo/output,注意output目录不能存在,hadoop会自己建立这个目录,这是hadoop内部的一个机制,如果有这个目录,程序无法执行。
    hadoop jar wordcount.jar /demo/input /demo/output
  7.  
  8. 6、查看运行结果,目录下有_SUCCESS文件,表示执行成功,结果在part-r-00000
    [hadoop@hp4411s ~]$ hadoop fs -ls /demo/output
    Found 2 items
    -rw-r--r--   1 hadoop supergroup          0 2019-01-30 03:42 /demo/output/_SUCCESS
    -rw-r--r--   1 hadoop supergroup         73 2019-01-30 03:42 /demo/output/part-r-00000
  9.  
  10. 7、查看part-r-00000
    [hadoop@hp4411s ~]$ hadoop fs -cat /demo/output/part-r-00000
    abc    2
    cd    1
    dnf    7
    ef    1
    hadoop    2
    hd    1
    hs    1
    mytest    1
    test    2
    wow    6
    xudemin    2

8、关于combiner,上述执行job的时候,程序注释了一段代码// job.setCombinerClass(WordCountReducer.class);

在Hadoop中,有一种处理过程叫Combiner,与Mapper和Reducer在处于同等地位,但其执行的时间介于Mapper和Reducer之间,其实就是Mapper和Reducer的中间处理过程,Mapper的输出是Combiner的输入,Combiner的输出是Reducer的输入。

combiner是什么作用?

  1. 因为hadoop的数据实际上是分布在各个不同的datanode,在mapper后,数据需要在从datanode上传输,如果数据很大很多,则会在网络上花费不少时间,而combiner可以先对数据进行处理,减少传输量。
    处理的方式是自定义的,本例中,每次map运行之后,会对输出按照key进行排序,然后把输出传递给本地的combiner(按照作业的配置与Reducer一样),进行本地聚合。
    combiner可以先对数据累加,实际上是执行了WordCountReducer类的内容,但是combine因为不是最后阶段,所以它只是帮组程序先累加了部分数据(本地的),并没有累加所有数据。
    实际已经减少了mapper传递的kv数据量,最终到reducer阶段需要累加的数据已经减少了。
  2.  
  3. 注意:combine是不会改变最终的reducer的结果,它是一个优化手段

用hadoop权威指南里天气数据的例子更深入解释:

  1. 例如获取历年的最高温度例子,以书中所说的1950年为例,在两个不同分区上的Mapper计算获得的结果分别如下:
  2.  
  3. 第一个Mapper结果:(1950, [0, 10, 20])
  4.  
  5. 第二个Mapper结果:(1950, [25, 15])
  6.  
  7. 如果不考虑Combiner,按照正常思路,这两个Mapper的结果将直接输入到Reducer中处理,如下所示:
  8.  
  9. MaxTemperature:(1950, [0, 10, 20, 25, 15])
  10.  
  11. 最终获取的结果是25
  12.  
  13. 如果考虑Combiner,按照正常思路,这两个Mapper的结果将分别输入到两个不同的Combiner中处理,获得的结果分别如下所示:
  14.  
  15. 第一个Combiner结果:(1950, [20])
  16.  
  17. 第二个Combiner结果:(1950, [25])
  18.  
  19. 然后这两个Combiner的结果会输出到Reducer中处理,如下所示
  20.  
  21. MaxTemperature:(1950, [20, 25])
  22.  
  23. 最终获取的结果是25
  24.  
  25. 由上可知:这两种方法的结果是一致的,使用Combiner最大的好处是节省网络传输的数据,这对于提高整体的效率是非常有帮助的。
  26.  
  27. 但是,并非任何时候都可以使用Combiner处理机制,例如不是求历年的最高温度,而是求平均温度,则会有另一种结果。同样,过程如下,
  28.  
  29. 如果不考虑Combiner,按照正常思路,这两个Mapper的结果将直接输入到Reducer中处理,如下所示:
  30.  
  31. AvgTemperature:(1950, [0, 10, 20, 25, 15])
  32.  
  33. 最终获取的结果是14
  34.  
  35. 如果考虑Combiner,按照正常思路,这两个Mapper的结果将分别输入到两个不同的Combiner中处理,获得的结果分别如下所示:
  36.  
  37. 第一个Combiner结果:(1950, [10])
  38.  
  39. 第二个Combiner结果:(1950, [20])
  40.  
  41. 然后这两个Combiner的结果会输出到Reducer中处理,如下所示
  42.  
  43. AvgTemperature:(1950, [10, 20])
  44.  
  45. 最终获取的结果是15
  46.  
  47. 由上可知:这两种方法的结果是不一致的,所以在使用Combiner时,一定是优化的思路,但是不能影响到最终结果。
 

hadoop的第一个hello world程序(wordcount)的更多相关文章

  1. Hadoop入门程序WordCount的执行过程

    首先编写WordCount.java源文件,分别通过map和reduce方法统计文本中每个单词出现的次数,然后按照字母的顺序排列输出, Map过程首先是多个map并行提取多个句子里面的单词然后分别列出 ...

  2. (转载)Hadoop示例程序WordCount详解

    最近在学习云计算,研究Haddop框架,费了一整天时间将Hadoop在Linux下完全运行起来,看到官方的map-reduce的demo程序WordCount,仔细研究了一下,算做入门了. 其实Wor ...

  3. 第一个MapReduce程序——WordCount

    通常我们在学习一门语言的时候,写的第一个程序就是Hello World.而在学习Hadoop时,我们要写的第一个程序就是词频统计WordCount程序. 一.MapReduce简介 1.1 MapRe ...

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

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

  5. hadoop第一个程序WordCount

    hadoop第一个程序WordCount package test; import org.apache.hadoop.mapreduce.Job; import java.io.IOExceptio ...

  6. Hadoop Map/Reduce 示例程序WordCount

    #进入hadoop安装目录 cd /usr/local/hadoop #创建示例文件:input #在里面输入以下内容: #Hello world, Bye world! vim input #在hd ...

  7. hadoop笔记之MapReduce的应用案例(WordCount单词计数)

    MapReduce的应用案例(WordCount单词计数) MapReduce的应用案例(WordCount单词计数) 1. WordCount单词计数 作用: 计算文件中出现每个单词的频数 输入结果 ...

  8. 在Hadoop 2.3上运行C++程序各种疑难杂症(Hadoop Pipes选择、错误集锦、Hadoop2.3编译等)

    首记 感觉Hadoop是一个坑,打着大数据最佳解决方案的旗帜到处坑害良民.记得以前看过一篇文章,说1TB以下的数据就不要用Hadoop了,体现不 出太大的优势,有时候反而会成为累赘.因此Hadoop的 ...

  9. Hadoop(三):MapReduce程序(python)

    使用python语言进行MapReduce程序开发主要分为两个步骤,一是编写程序,二是用Hadoop Streaming命令提交任务. 还是以词频统计为例 一.程序开发1.Mapper for lin ...

随机推荐

  1. Homebrew安装Redis找不到redis.conf文件

    使用Homebrew安装redis完成后,使用命令 redis-server 启动redis,如下图所示: 启动信息中存在一条警告信息:没有指定的配置文件 然而在安装目录中并没有发现redis.con ...

  2. 一个只有十行的精简MVVM框架

    本文来自网易云社区. 前言 MVVM模式相信做前端的人都不陌生,去网上搜MVVM,会出现一大堆关于MVVM模式的博文,但是这些博文大多都只是用图片和文字来进行抽象的概念讲解,对于刚接触MVVM模式的新 ...

  3. Objective-C 类和对象

    面向对象 面向对象(Object-Oriented)是基于面向过程(procedure-oriented)而言的 面向对象 强调对象<指挥者> OC, Java语言就是面向对象 面向过程 ...

  4. 树莓派 Raspberry Pi 与 micro:bit起手式

    本文将学习如何在Raspberry Pi上安装MicroPython编辑器mu,并将MicroPython中编写的程序从您的Raspberry Pi推送到micro:bit. 您需要: 硬件, 带有S ...

  5. 【转】: 探索Lua5.2内部实现:虚拟机指令(2) MOVE & LOAD

    name args desc OP_MOVE A B R(A) := R(B) OP_MOVE用来将寄存器B中的值拷贝到寄存器A中.由于Lua是register based vm,大部分的指令都是直接 ...

  6. [Clr via C#读书笔记]Cp6类型和成员基础

    Cp6类型和成员基础 成员 常量:字段(静态字段和实例字段):实例构造器:类型构造器(用于静态字段的构造):方法(静态方法和实例方法):操作符重载(本质是一个方法):转换操作符:属性(本质还是方法): ...

  7. Spring Boot - Filter实现简单的Http Basic认证

    Copy自http://blog.csdn.net/sun_t89/article/details/51916834 @SpringBootApplicationpublic class Spring ...

  8. HDU 4300 Clairewd’s message (next函数的应用)

    题意:给你一个明文对密文的字母表,在给你一段截获信息,截获信息前半段是密文,后半段是明文,但不清楚它们的分界点在哪里,密文一定是完整的,明文可能是残缺的,求完整的信息串(即完整的密文+明文串). 题解 ...

  9. Coins and Queries(map迭代器+贪心)

    题意 n个硬币,q次询问.第二行给你n个硬币的面值(保证都是2的次幂!).每次询问组成b块钱,最少需要多少个硬币? Example Input 5 42 4 8 2 4851410 Output 1- ...

  10. iOS- 网络请求的两种常用方式【GET & POST】的区别

    GET和POST 网络请求的两种常用方式的实现[GET & POST] –GET的语义是获取指定URL上的资源 –将数据按照variable=value的形式,添加到action所指向的URL ...