版权声明:本文为博主原创文章,未经博主同意不得转载。

https://blog.csdn.net/jiq408694711/article/details/34181439

前面已经在我的Ubuntu单机上面搭建好了伪分布模式的HBase环境,当中包含了Hadoop的执行环境。

详见我的这篇博文:http://blog.csdn.net/jiyiqinlovexx/article/details/29208703

我的目的主要是学习HBase,下一步打算学习的是将HBase作为Hadoop作业的输入和输出。

可是好像曾经在南大上学时学习的Hadoop都忘记得几乎相同了,所以找到曾经上课做的几个实验:wordCount,PageRank以及InversedIndex。

发现曾经写的实验报告还是蛮具体的。非常easy看懂。恰好曾经做实验用的也是hadoop0.20的版本号,所以依照我曾经写的实验手冊直接操作,熟悉一下Hadoop了。

以下是我曾经写的WordCOunt的实验报告:

一、实验要求:

实验内容与要求
1. 在Eclipse环境下编写WordCount程序,统计全部除Stop-Word(如a, an, of, in, on, the, this, that,…)外全部出现次数k次以上的单词计数。最后的结果依照词频从高到低排序输出
2. 在集群上执行程序,对莎士比亚文集文档数据进行处理
3. 可自行建立一个Stop-Word列表文件。当中包含部分停词就可以,不须要列出全部停词;參数k作为输入參数动态指定(如k=10)
4. 实验结果提交:要求书写一个实验报告,当中包含:
实验设计说明。包含主要设计思路、算法设计、程序和各个类的设计说明
程序执行和实验结果说明和分析
性能、扩展性等方面存在的不足和可能的改进之处
源程序 。执行程序,停词列表文件
执行结果文件

二、实验报告:

Wordcount词频统计实验

2012年4月1日星期日

19:04

1设计思路

Map:

(1)停词存储

由于停词比較少。所以选择将他们全部存储到内存中,停词不能有反复,还须要高速訪问。所以选择hashset来存储

(2)map

对于map传进来的每一行文本。首先用正在表达式将英文标点符号全部题换成空格,然后在循环分析每个单词,假设这个单词不包含在停词集合中。则将其key设为单词本身,值设置为1。并发射出去。

Reduce:

在reduce中对每个key,将其全部value累加起来。

假设value不小于某个词频。则将其output出去。

 

2遇到的问题

(1)hadoop API问题

(2)在hadoop的map中读取hdfs文件内容

(3)怎样按词频从高究竟输出;

解决1

參考非常多资料。找到正确使用的API,总之感觉hadoop不同版本号之间API非常混乱。

在API方面有两个点花费我非常多时间。一是map和reduce的初始化函数setup。二是向map和reduce传递參数直接通过configuration来进行,有点相似于JSP中的session。

解决2

開始我在map之外定义一个全局变量,開始的时候将停词文件路径复制给这个全局变量。可是在map里面无法读取这个文件的内容。不知道怎么回事。

然后我们在网上查了一下,发现有一个分布式缓存文件的类DistributedCache。

主要先是获取停词文件的路径,将其增加到cache中去,DistributedCache.addCacheFile(newPath(args[++i]).toUri(), conf);

然后在map中用DistributedCache.getLocalCacheFiles(context.getConfiguration());读取该文件路径,这样就能够读取停词文件的内容了。

解决3

词频要在reduce完毕之后才干计算出来。也就是说尽管map之后将键值对分发到reduce之前会依照键值进行一个sort的过程,可是我们也无法借助将key

value掉换的方法一次进行。

我们小组一起讨论,想到了在第一次mapreduce统计完词频之后再进行一次mapreduce来依照词频对全部键值对排序。统计结果(中间结果)存放到暂时文件夹中。

在第二次mapreduce的过程中:

(1)InverseMapper:

在网上查了一下,hadoop本身就有一个将键值对颠倒顺序的了一个mapper。名字叫做InverseMapper,在交换了键值之后。另一个问题。

(2)setSortComparatorClass:

hadoop中默认对IntWritable类型的key是以升序排列的,我们是要依照降序,所以重写sort过程中进行key值比較所參考的比較类。使用setSortComparatorClass方法设置比較类。

(3)setNumReduceTasks(1):

至于reduce部分我们无须指定不论什么reduce。由于不须要做不论什么操作。仅仅须要指定将全部键值对发送到一个reduce就可以。

 

3执行过程

首先利用scp命令将停词文件以及wordcount的可执行jar传输到集群的mater01节点上面去。然后使用ssh命令登录到该节点:

 

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaml5aXFpbmxvdmV4eA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

然后在hdfs上面我们小组的文件夹下创建一个wordcount文件夹。以及子文件夹input。

然后使用hadoopfs -put命令将停词文件复制到该文件夹下:

然后以节点上本来就有的/data/shakespear文件夹以下的数据作为输入,将我们小组的/wordcount/output(不存在)作为输入。执行參数为-skip指定听此文件路径,-greater指定要统计的最低词频的单词。来执行wordcount:

在wordcount/output文件夹以下生成结果文件part-r-00000。打开之后发现结果和预期全然一致。词频从高到低,最低词频为10,而且在统计之前已经将标点符号去掉。

能够用hadoop fs -get /wordcount/output/part-r-00000 .命令下载到当前文件夹。

也能够打开浏览器:http://localhost:50070/dfshealth.jsp。选择Browse the filesystem来直接查看HDFS上面文件的内容。

在浏览器中打开:http://localhost:50030/jobtracker.jsp,查看工作执行状态以及结果:

 

4源程序,停词文件,可执行jar文件均參见本文件夹里。

=====================================================================================================

注意,我由于如今是在本机上面执行Hadoop作业,而不是像曾经那样在远端master机器上面跑。所以有些地方不一样。

比方利用scp将wordcount.jar传到master机器上,以及用ssh登陆这些都不须要。

可是停词文本集合还是要上传到HDFS。还有之前实验莎士比亚文集的数据是老师已经放在HDFS上了,所以不须要我们上传,这些要自己将莎士比亚文集的数据上传到HDFS。命令是:

hadoop fs -put /shakespeare /data/shakespare

三、源代码:

说实话。看着曾经的图片。发现跑起来蛮快的,可是如今单机真心慢。。

停词文本文件和莎士比亚文集数据有时间上传到百度云盘,这里先把代码贴出来供大家參考。

  1. /**
  2. * WordCount
  3. * jiyq@seg.nju.edu.cn - 季义钦
  4. * 统计输入文件各个单词出现频率
  5. * 统计的时候对于“停词”(从文本文件读入)将不參与统计
  6. * 最后按统计的词频从高究竟输出
  7. *
  8. * 特别主import某个类的时候。确定你是要用哪个包所属的该类
  9. *
  10. * */
  11. import java.io.BufferedReader;
  12. import java.io.FileReader;
  13. import java.io.IOException;
  14. import java.util.*;
  15. import org.apache.hadoop.filecache.DistributedCache;
  16. import org.apache.hadoop.fs.FileSystem;
  17. import org.apache.hadoop.fs.Path;
  18. import org.apache.hadoop.conf.*;
  19. import org.apache.hadoop.io.*;
  20. import org.apache.hadoop.mapreduce.*;
  21. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  22. import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat;
  23. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
  24. import org.apache.hadoop.mapreduce.lib.map.InverseMapper;
  25. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  26. import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;
  27. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
  28. public class WordCount {
  29. /**
  30. * Map: 将输入的文本数据转换为<word-1>的键值对
  31. * */
  32. public static class WordCountMap extends Mapper<LongWritable, Text, Text, IntWritable> {
  33. String regex = "[.,\"!--;:?'\\]]"; //remove all punctuation
  34. Text word = new Text();
  35. final static IntWritable one = new IntWritable(1);
  36. HashSet<String> stopWordSet = new HashSet<String>();
  37. /**
  38. * 将停词从文件读到hashSet中
  39. * */
  40. private void parseStopWordFile(String path){
  41. try {
  42. String word = null;
  43. BufferedReader reader = new BufferedReader(new FileReader(path));
  44. while((word = reader.readLine()) != null){
  45. stopWordSet.add(word);
  46. }
  47. } catch (IOException e) {
  48. e.printStackTrace();
  49. }
  50. }
  51. /**
  52. * 完毕map初始化工作
  53. * 主要是读取停词文件
  54. * */
  55. public void setup(Context context) {
  56. Path[] patternsFiles = new Path[0];
  57. try {
  58. patternsFiles = DistributedCache.getLocalCacheFiles(context.getConfiguration());
  59. } catch (IOException e) {
  60. e.printStackTrace();
  61. }
  62. if(patternsFiles == null){
  63. System.out.println("have no stopfile\n");
  64. return;
  65. }
  66. //read stop-words into HashSet
  67. for (Path patternsFile : patternsFiles) {
  68. parseStopWordFile(patternsFile.toString());
  69. }
  70. }
  71. /**
  72. * map
  73. * */
  74. public void map(LongWritable key, Text value, Context context)
  75. throws IOException, InterruptedException {
  76. String s = null;
  77. String line = value.toString().toLowerCase();
  78. line = line.replaceAll(regex, " "); //remove all punctuation
  79. //split all words of line
  80. StringTokenizer tokenizer = new StringTokenizer(line);
  81. while (tokenizer.hasMoreTokens()) {
  82. s = tokenizer.nextToken();
  83. if(!stopWordSet.contains(s)){
  84. word.set(s);
  85. context.write(word, one);
  86. }
  87. }
  88. }
  89. }
  90. /**
  91. * Reduce: add all word-counts for a key
  92. * */
  93. public static class WordCountReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
  94. int min_num = 0;
  95. /**
  96. * minimum showing words
  97. * */
  98. public void setup(Context context) {
  99. min_num = Integer.parseInt(context.getConfiguration().get("min_num"));
  100. System.out.println(min_num);
  101. }
  102. /**
  103. * reduce
  104. * */
  105. public void reduce(Text key, Iterable<IntWritable> values, Context context)
  106. throws IOException, InterruptedException {
  107. int sum = 0;
  108. for (IntWritable val : values) {
  109. sum += val.get();
  110. }
  111. if(sum < min_num) return;
  112. context.write(key, new IntWritable(sum));
  113. }
  114. }
  115. /**
  116. * IntWritable comparator
  117. * */
  118. private static class IntWritableDecreasingComparator extends IntWritable.Comparator {
  119. public int compare(WritableComparable a, WritableComparable b) {
  120. return -super.compare(a, b);
  121. }
  122. public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
  123. return -super.compare(b1, s1, l1, b2, s2, l2);
  124. }
  125. }
  126. /**
  127. * main: run two job
  128. * */
  129. public static void main(String[] args){
  130. boolean exit = false;
  131. String skipfile = null; //stop-file path
  132. int min_num = 0;
  133. String tempDir = "wordcount-temp-" + Integer.toString(new Random().nextInt(Integer.MAX_VALUE));
  134. Configuration conf = new Configuration();
  135. //获取停词文件的路径。并放到DistributedCache中
  136. for(int i=0;i<args.length;i++)
  137. {
  138. if("-skip".equals(args[i]))
  139. {
  140. DistributedCache.addCacheFile(new Path(args[++i]).toUri(), conf);
  141. System.out.println(args[i]);
  142. }
  143. }
  144. //获取要展示的最小词频
  145. for(int i=0;i<args.length;i++)
  146. {
  147. if("-greater".equals(args[i])){
  148. min_num = Integer.parseInt(args[++i]);
  149. System.out.println(args[i]);
  150. }
  151. }
  152. //将最小词频值放到Configuration中共享
  153. conf.set("min_num", String.valueOf(min_num)); //set global parameter
  154. try{
  155. /**
  156. * run first-round to count
  157. * */
  158. Job job = new Job(conf, "jiq-wordcountjob-1");
  159. job.setJarByClass(WordCount.class);
  160. //set format of input-output
  161. job.setInputFormatClass(TextInputFormat.class);
  162. job.setOutputFormatClass(SequenceFileOutputFormat.class);
  163. //set class of output's key-value of MAP
  164. job.setOutputKeyClass(Text.class);
  165. job.setOutputValueClass(IntWritable.class);
  166. //set mapper and reducer
  167. job.setMapperClass(WordCountMap.class);
  168. job.setReducerClass(WordCountReduce.class);
  169. //set path of input-output
  170. FileInputFormat.addInputPath(job, new Path(args[0]));
  171. FileOutputFormat.setOutputPath(job, new Path(tempDir));
  172. if(job.waitForCompletion(true)){
  173. /**
  174. * run two-round to sort
  175. * */
  176. //Configuration conf2 = new Configuration();
  177. Job job2 = new Job(conf, "jiq-wordcountjob-2");
  178. job2.setJarByClass(WordCount.class);
  179. //set format of input-output
  180. job2.setInputFormatClass(SequenceFileInputFormat.class);
  181. job2.setOutputFormatClass(TextOutputFormat.class);
  182. //set class of output's key-value
  183. job2.setOutputKeyClass(IntWritable.class);
  184. job2.setOutputValueClass(Text.class);
  185. //set mapper and reducer
  186. //InverseMapper作用是实现map()之后的数据对的key和value交换
  187. //将Reducer的个数限定为1, 终于输出的结果文件就是一个
  188. /**
  189. * 注意,这里将reduce的数目设置为1个。有非常大的文章。
  190. * 由于hadoop无法进行键的全局排序,仅仅能做一个reduce内部
  191. * 的本地排序。
  192. 所以我们要想有一个依照键的全局的排序。
  193. * 最直接的方法就是设置reduce仅仅有一个。
  194. */
  195. job2.setMapperClass(InverseMapper.class);
  196. job2.setNumReduceTasks(1); //only one reducer
  197. //set path of input-output
  198. FileInputFormat.addInputPath(job2, new Path(tempDir));
  199. FileOutputFormat.setOutputPath(job2, new Path(args[1]));
  200. /**
  201. * Hadoop 默认对 IntWritable 按升序排序,而我们须要的是按降序排列。
  202. * 因此我们实现了一个 IntWritableDecreasingComparator 类, 
  203. * 并指定使用这个自己定义的 Comparator 类对输出结果中的 key (词频)进行排序
  204. * */
  205. job2.setSortComparatorClass(IntWritableDecreasingComparator.class);
  206. exit = job2.waitForCompletion(true);
  207. }
  208. }catch(Exception e){
  209. e.printStackTrace();
  210. }finally{
  211. try {
  212. //delete tempt dir
  213. FileSystem.get(conf).deleteOnExit(new Path(tempDir));
  214. if(exit) System.exit(1);
  215. System.exit(0);
  216. } catch (IOException e) {
  217. e.printStackTrace();
  218. }
  219. }
  220. }
  221. }

若有什么疑问和不吝赐教。欢迎交流。联系邮箱: jiq408694711@163.com  季义钦

作为兴趣点,眼下本人正在研究HBase和Hadoop

Hadoop基础学习(一)分析、编写并执行WordCount词频统计程序的更多相关文章

  1. 初学Hadoop之WordCount词频统计

    1.WordCount源码 将源码文件WordCount.java放到Hadoop2.6.0文件夹中. import java.io.IOException; import java.util.Str ...

  2. Hadoop基础学习框架

    我们主要使用Hadoop的2个部分:分布式文件存储系统(HDFS)和MapReduce计算模型. 关于这2个部分,可以参考一下Google的论文:The Google File System 和 Ma ...

  3. JAVA基础-输入输出:1.编写TextRw.java的Java应用程序,程序完成的功能是:首先向TextRw.txt中写入自己的学号和姓名,读取TextRw.txt中信息并将其显示在屏幕上。

    1.编写TextRw.java的Java应用程序,程序完成的功能是:首先向TextRw.txt中写入自己的学号和姓名,读取TextRw.txt中信息并将其显示在屏幕上. package Test03; ...

  4. hadoop基础学习

    MR系类: ①hadoop生态 >MapReduce:分布式处理 >Hdfs:hadoop distribut file system >其他相关框架 ->unstructur ...

  5. 【jQuery基础学习】08 编写自定义jQuery插件

    目的:虽然jQuery各种各样的功能已经很完善了,但是我们还是要学会自己去编写插件.这样我们可以去封装一些项目中经常用到的专属的代码,以便后期维护和提高开发效率. jQuery插件的类型: 封装对象方 ...

  6. hadoop基础学习---数据管理策略

    上图中的ABCDE都代表默认大小64M的数据块 nameNode与dataNode之间有一个心跳机制,datanode每隔多秒钟定期的发送心跳到nameNode

  7. hadoop基础学习---基本概念

    1.组成部分HDFS和MapReduce 2.HDFS这几架构

  8. Eclipse上运行第一个Hadoop实例 - WordCount(单词统计程序)

    需求 计算出文件中每个单词的频数.要求输出结果按照单词的字母顺序进行排序.每个单词和其频数占一行,单词和频数之间有间隔. 比如,输入两个文件,其一内容如下: hello world hello had ...

  9. 第六篇:Eclipse上运行第一个Hadoop实例 - WordCount(单词统计程序)

    需求 计算出文件中每个单词的频数.要求输出结果按照单词的字母顺序进行排序.每个单词和其频数占一行,单词和频数之间有间隔. 比如,输入两个文件,其一内容如下: hello world hello had ...

随机推荐

  1. 2016北京集训测试赛(十六)Problem C: ball

    Solution 这是一道好题. 考虑球体的体积是怎么计算的: 我们令\(f_k(r)\)表示\(x\)维单位球的体积, 则 \[ f_k(1) = \int_{-1}^1 f_{k - 1}(\sq ...

  2. asp.net获取请求的协议头是否启动了SSL(Https)

    方法: HttpContext.Current.Request.IsSecureConnection SLL:True HttpContext.Current.Request.Url.ToString ...

  3. 排序算法之高速排序(Java)

    //高速排序 public class Quick_Sort { // 排序的主要算法 private int Partition(int[] data, int start, int end) { ...

  4. MFC 消息类型

    标准(窗口)消息:窗口消息一般与窗口内部运作有关,如创建窗口,绘制窗口,销毁窗口,通常,消息是从系统发到窗口,或从窗口发到系统.发送函数SendMessage()或者PostMessage().除WM ...

  5. oracle如何获得新插入记录的id

    .对于提交(最后一次操作commit了)的话可以查询那个提交段 SELECT 列名1,列名2…… FROM 表名 VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAX ...

  6. 115. distinct subsequence leetcode python

    Given a string S and a string T, count the number of distinct subsequences of T in S. A subsequence ...

  7. HashSet和SortSet对比--c#学习笔记

    微软在 .NET 3.5 新增了一个 HashSet 类,在 .NET 4 新增了一个 SortedSet 类. .NET Collection 函数库的 HashSet.SortedSet 这两个泛 ...

  8. vs2010 assistx安装教程

    参照此篇教程. 安装目录你可能找不到,因为那些文件是系统隐藏文件,打开隐藏即可. 然后,将此.exe安装到上面的目录下,然后,还需要进行一个破解,即需要将从网上下载的补丁放进去. 把目录下的VA_X. ...

  9. java 逻辑运算符 短路(条件操作)

    两个数字计算时都会先把数字转换成二进制后再进行换算,二进制就是由0和1组成的数字  http://yxwang0615.iteye.com/blog/1084288    

  10. swiper的理解

    参考:Swiper中文网 Swiper使用方法: <!DOCTYPE html> <html> <head> <meta charset="UTF- ...