# WordCount **Repository Path**: Mr-Nan05/word-count ## Basic Information - **Project Name**: WordCount - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-12-04 - **Last Updated**: 2021-12-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # README 宋超群 171860642 mr.nan0505@qq.com ### 实验简介 使用最朴素的思想,编写MapReduce程序对莎士比亚文集的数据文件进行词频统计,并将每个作品的前100个高频单词与所有作品的前100个高频单词输出到不同文件中(忽略大小写,忽略标点符号(punctuation.txt),忽略停词(stop-word-list.txt),忽略数字,单词长度>=3)。 ### 设计思路 思想非常朴素,即在每一次统计过程中,在wordcount的基础job基础上,增加一个新的job,对wordcount的输出结果使用二叉搜索树进行排序,并将排序结果的前100条结果保存在新的文件中即可。 ###### 文件路径如下 ![image-20211207103947889](README.assets/image-20211207103947889.png) 我将所有的数据文件都放在/input路径下,然后将任务分为两步: - countEachSingleFile(),对/input目录下每一个单独的文件进行上述处理,并将每一个文件的不同结果保存在不同的目录下,以原始文件名来命名结果目录 ![image-20211207103220258](README.assets/image-20211207103220258.png) ![image-20211207103300711](README.assets/image-20211207103300711.png) - countAllFiles(),对/input目录下所有文件当做输入,并将统计并输出到一个结果文件中 ![image-20211207103333362](README.assets/image-20211207103333362.png) ![image-20211207103409073](README.assets/image-20211207103409073.png) ###### WordCount任务的思路介绍 - 首先将需要特殊处理的字符或单词文件添加到任务的CacheFile中 ```java String punctuations = "hdfs://172.18.0.2:9000/punctuation.txt"; String stopWordList = "hdfs://172.18.0.2:9000/stop-word-list.txt"; job.addCacheFile(new Path(punctuations).toUri()); job.addCacheFile(new Path(stopWordList).toUri()); job.getConfiguration().setBoolean("WordCount.skip.patterns", true); ``` - 在Map的过程中,首先将标点与停词分别存放到不同的Set中 ```java parseskipFile(patternsToSkip, patternsFileName); patternsToSkip.add("[0-9]*"); //将标点与数字存放到patternsToSkip中 parseskipFile(patternsStopWords, patternsFileName); //将停词存放到patternsStopWords中 ``` - 在进行统计的时候将标点、数字替换成空白,而停词是一个单词,直接忽略不进行处理即可 ```java String line = value.toString().toLowerCase() //大写转为小写 for (String pattern : patternsToSkip) { //对标点、数字进行处理 line = line.replaceAll(pattern, ""); } //对停词和单词长度进行控制 if(!patternsStopWords.contains(word.toString()) && word.getLength() >= 3) { //省略 } ``` - 最后在reduce中将结果写在目标目录文件中即可 ###### Sort+TopK任务的思路介绍 - 使用TreeMap将读取词频统计文件,将词频作为Key,单词作为Value进行存放,存放过程中会根据词频自动进行排序,在此过程中通过控制存放单词的个数来达到统计TopK的效果 ```java for (Text text : values) { context.write(text, key); tm.put(new MyInt(key.get()), text.toString()); //TreeMap以对内部数据进行了排序,最后一个必定是最小的 if (tm.size() > k) { tm.remove(tm.lastKey()); //维持Map大小为K } } ``` - 最后在写文件的过程中,将排名加入进去即可 ```java Set> set = tm.entrySet(); int rank = 0; for (Entry entry : set) { //写文件过程,将自增的rank加入其中 mos.write("topKMOS", new Text(++rank + "\t" + entry.getValue()), new IntWritable(entry.getKey().getValue()), path); } ``` - 运行效果截图示例如下(所有文件的统计结果): ![image-20211207111234496](README.assets/image-20211207111234496.png) ![image-20211207111243473](README.assets/image-20211207111243473.png) ### 效果截图 ![image-20211207103024993](README.assets/image-20211207103024993.png) ![image-20211207103220258](README.assets/image-20211207103220258.png) ![image-20211207103300711](README.assets/image-20211207103300711.png) ![image-20211207103333362](README.assets/image-20211207103333362.png) ![image-20211207103409073](README.assets/image-20211207103409073.png) ### 个人感想 本次实验大部分时间花在运行测试上了,整个程序运行过程可达1小时以上,在不使用MapReduce的情况下,确实可以很容易使用很笨的方式处理出相同的结果,花费的时间甚至会短很多,因为本次实验并没有完全发挥出MapReduce的优势。 我认为这也是本次实验的目的之一,在实验过程中可以对比MapReduce与普通程序的优劣,以及各自擅长的事情;比如对于单个文件分别处理的话普通程序可以做得更好更快,但是对于大量文件大量数据进行处理MapReduce具有天然的优势。 我认为本作业另一个目的是为了下一次作业做铺垫,即在MapReduce程序中有另一个功能天然地适合处理类似的数据,也就是建立倒排索引,根据每个单词查到对应的文件,根据单词与文件,又能查到对应的词频,一次处理的结果就可以解决本次问题。