WordCount词频统计

WordCount词频统计

from educoder实训
实训项目地址:https://www.educoder.net/shixuns/aekgf6pz/challenges

本关任务

词频统计是最能体现MapReduce思想的程序,结构简单,上手容易。

词频统计的大致功能是:统计单个或者多个文本文件中每个单词出现的次数,并将每个单词及其出现频率按照<k,v>键值对的形式输出,其基本执行流程如下图所示:

the overall mapreduce word count process

由图可知:

  1. 输入文本(可以不只一个),按行提取文本文档的单词,形成行<k1,v1>键值对,具体形式很多,例如<行数,字符偏移>等;
  2. 通过Spliting将<k1,v1>细化为单词键值对<k2,v2>;
  3. Map分发到各个节点,同时将<k2,v2>归结为list(<k2,v2>);
  4. 在进行计算统计前,先用Shuffing将相同主键k2归结在一起形成<k2,list(v2)>;
  5. Reduce阶段直接对<k2, list(v2)> 进行合计得到list(<k3,v3>)并将结果返回主节点。

主节点对预设文本文档进行词频统计,并将最终结果输出。

注:输入和输出事先已经预定,只要比较输出是否达到预期即可判断是否达到要求。

相关知识

MapReduce采用”分而治之”的思想,把对大规模数据集的操作,分发给一个主节点管理下的各个分节点共同完成,然后通过整合各个节点的中间结果,得到最终结果。MapReduce框架负责处理了并行编程中分布式存储、工作调度、负载均衡、容错均衡、容错处理以及网络通信等复杂问题。将处理过程高度抽象为两个函数:map和reduce。

map负责把任务分解成多个任务;
reduce负责把分解后多任务处理的结果汇总起来。

注:MapReduce处理的数据集必须可以分解成许多小的数据集,而且每一个小数据集都可以完全并行地进行处理。不是关系型数据库,而是结构化的。

map处理阶段

对于给定的待处理文本文档,其map阶段的处理如下:

通过Text对象,获取文本文档的内容。
逐行处理文档,将单词提取出来。
每个单词为key,对应的value设为1,将<k2,v2>对输出。

关键性说明:

  1. map阶段的处理,主要是如何对文本进行逐行的单词分割,从而获取单词,以及将键值对分发到各个节点(此处由hadoop隐性提供,用户先不必关心hdfs存储过程)。

  2. 可以参考的单词分割提取代码模板如下:

public void map(Object key,Text value,Context context)throws IOException,InterruptedException
{
    //对文本内容对象value进行分割
    StringTokenizer itr=new StringTokenizer(valu e.toString());    
    while(itr.hasMoreTokens()) {
        String word=itr.nextToken();/*获取分割好的单词*/
        /*
        可以在该循环体中,使用获取好的单词word变量进行key和value的设定。
        */
    }
}

reduce处理阶段

在Wordcount的reduce阶段,主要是将每个单词的数量统计出来,包括:

在各个节点并行循环统计每个单词出现的次数。
将各个节点的结果汇总以list(<k3,v3>)的形式输出。

reduce函数参考模板:

public void reduce(Object key,Iterable<IntWritable> values,Context context)throws IOException, InterruptedException
{
    int count=0;
    for(IntWritable itr:vlaues)
    {
        count+=itr.get();  /*循环统计*/
    }
    /*统计完成后,将结果输出.....*/
}

编程要求

本关的编程任务是补全右侧代码片段中map和reduce函数中的代码,具体要求及说明如下:

在主函数main中已初始化hadoop的系统设置,包括hadoop运行环境的连接。

在main函数中,已经设置好了待处理文档路径(即input),以及结果输出路径(即output)。

在main函数中,已经声明了job对象,程序运行的工作调度已经设定好。

本关只要求在map和reduce函数的指定区域进行代码编写,其他区域请勿改动。

测试说明

以下是测试样例:

测试输入样例数据集:文本文档test1.txt和test2.txt

文档test1.txt中的内容为:

tale as old as time
 true as it can be
 beauty and the beast

文档test2.txt中的内容为:

 ever just the same
 ever as before
beauty and the beast

预期输出result.txt文档中的内容为:
and 2
as 4
beast 2
beauty 2
before 1
can 1
ever 2
it 1
just 1
old 1
same 1
tale 1
the 3
time 1
true 1

注:由于启动服务、编译等耗时,以及MapReduce过程资源消耗较大,评测时间较长(30s左右)!

请耐心等待!相信自己!通往成功的路上不会太久!

建议完成本关后尝试在本机上根据相关指导搭建环境运行程序,这样理解更深刻!

合抱之木,生于毫末;九层之台,起于累土!复杂源于简单,要想铸就高楼大厦必须打牢基础!

开始你的任务吧,祝你成功!

如果你觉得这一关的内容对你有帮助,请你在下面点赞。

代码参考


    import java.io.IOException; import java.util.StringTokenizer;     
    import org.apache.hadoop.conf.Configuration; 
    import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; 
    import org.apache.hadoop.io.Text; import   
    org.apache.hadoop.mapreduce.Job; import   
    org.apache.hadoop.mapreduce.Mapper; import   
    org.apache.hadoop.mapreduce.Reducer; import   
    org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import   
    org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import   
    org.apache.hadoop.util.GenericOptionsParser;   public class
    WordCount    { 	/*  	* MapReduceBase类:实现Mapper和Reducer接口的基类      	*
    Mapper接口:   	*   
    WritableComparable接口:实现WritableComparable的类可以相互比较。所有被用作key的类要实现此接口。 
       	*/     public static class TokenizerMapper 
          extends Mapper<Object, Text, Text, IntWritable>{  	/* 	*LongWritable,IntWritable,Text是Hadoop中实现的用于封装Java数据类型的类,这些类实现了WritableComparable接口,
       	*都能够被串行化,便于在分布式环境中进行数据交换,可以视为long,int,String数据类型的替代。 	*/    private final static IntWritable one = new IntWritable(1);   
    private Text word = new Text();//Text实现了BinaryComparable类,可以作为key值
       
       	/* 	* Mapper接口中的map方法:  	* void map(K1 key, V1 value,    OutputCollector<K2,V2> output, Reporter reporter) 	*   
    映射一个单个的输入<K1,V1>对到一个中间输出<K2,V2>对  	*   
    中间输出对不需要和输入对是相同的类型,输入对可以映射到0个或多个输出对。 	 	*   
    OutputCollector接口:收集Mapper和Reducer输出的<K,V>对。  	*   
    OutputCollector接口的collect(k, v)方法:增加一个(k,v)对到output  	* Reporter   
    用于报告整个应用的运行进度
        */  
           public void map(Object key, Text value, Context context
                       ) throws IOException, InterruptedException {
                           
       
       	/*
       	 * 原始数据(以test1.txt为例):
      	 * 	tale as old as time 		true as it can be 		beauty and the beast 		map阶段,数据如下形式作为map的输入值:key为偏移量 			<0  tale as old as time>
    			<21 world java hello> 			<39 you me too>	
       	 */
       	 
       	 /**
       	   * 解析(Spliting)后以得到键值对<K2,V2>(仅以test1.txt为例)
            * 格式如下:前者是键值,后者数字是值
            * tale 1
            * as 1
            * old 1
            * as 1
            * time 1
            * true 1
            * as 1
            * it 1
            * can 1
            * be 1
            * beauty 1
            * and 1
            * the 1
            * beast 1
            * 这些键值对作为map的输出数据
            */
       
       	//****请补全map函数内容****// 	/*********begin*********/
           StringTokenizer itr = new StringTokenizer(value.toString()); 
         while (itr.hasMoreTokens()) {
           word.set(itr.nextToken());
           context.write(word, one);
         }
       
       	/*********end**********/
           }   }    public static class IntSumReducer 
          extends Reducer<Text,IntWritable,Text,IntWritable> {    private IntWritable result = new IntWritable();
       
       	 /* 	 *    reduce过程是对输入键值对洗牌(Shuffing)形成<K2,list(V2)>格式数据(仅以test1.txt为例): 	 *  
    (tablie [1]) 	 * (as [1,1,1]) 	 * (old [1]) 	 * (time [1]) 	 * (true
    [1]) 	 * (it [1]) 	 * (can [1]) 	 * (be [1]) 	 * (beauty [1]) 	 *   
    (and [1]) 	 * (the [1]) 	 * (beast [1]) 	 * 作为reduce的输入 	 *  	 */   
    public void reduce(Text key, Iterable<IntWritable> values, 
                          Context context
                          ) throws IOException, InterruptedException {    //****请补全reduce对<k2, list(v2)> 进行合计得到list(<k3,v3>)过程****//
    	/*********begin*********/
       
         int sum = 0;
         for (IntWritable val : values) {
           sum += val.get();
         }
         result.set(sum);
         context.write(key, result);
       
       	/*********end**********/
       
       	//****请将list(<k3,v3>)统计输出****//
       
       	/*********begin*********/
       
       	/*********end**********/ 	} }   public static void main(String[]    args) throws Exception { 	  /**
          * JobConf:map/reduce的job配置类,向hadoop框架描述map-reduce执行的工作 
          * 构造方法:JobConf()、JobConf(Class exampleClass)、JobConf(Configuration conf)等 
          */      Configuration conf = new Configuration();    String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
    	/* 	* 需要配置输入和输出的HDFS的文件路径参数 	* 可以使用"Usage:    wordcount <in>
    <out>"实现程序运行时动态指定输入输出 	*/    if (otherArgs.length != 2) {
       	     System.err.println("Usage: wordcount <in> <out>");
         System.exit(2);    }    Job job = new Job(conf, "word count");//Job(Configuration conf,String jobName)设置job名称   
    job.setJarByClass(WordCount.class);//为job设置Mapper类
         /*********begin*********/
         //****请为job设置Mapper类****//    job.setMapperClass(TokenizerMapper.class);
           job.setCombinerClass(IntSumReducer.class);//为job设置Combiner类
      
         //****请为job设置Reduce类****//    job.setReducerClass(IntSumReducer.class);
         //****请设置输出key的参数类型****//    job.setOutputKeyClass(Text.class);
         //****请设置输出value的类型****//
             job.setOutputValueClass(IntWritable.class);
         /*********end**********/
           FileInputFormat.addInputPath(job, new Path(otherArgs[0]));//为map-reduce任务设置InputFormat实现类,设置输入路径   
    FileOutputFormat.setOutputPath(job, new
    Path(otherArgs[1]));//为map-reduce任务设置OutputFormat实现类,设置输出路径   
    System.exit(job.waitForCompletion(true) ? 0 : 1);   } }

纯代码

import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class WordCount {
  public static class TokenizerMapper 
       extends Mapper<Object, Text, Text, IntWritable>{
    private final static IntWritable one = new IntWritable(1);
    private Text word = new Text();
    public void map(Object key, Text value, Context context
                    ) throws IOException, InterruptedException {
      StringTokenizer itr = new StringTokenizer(value.toString());
      while (itr.hasMoreTokens()) {
        word.set(itr.nextToken());
        context.write(word, one);
      }
    }
  }
  public static class IntSumReducer 
       extends Reducer<Text,IntWritable,Text,IntWritable> {
    private IntWritable result = new IntWritable();
    public void reduce(Text key, Iterable<IntWritable> values, 
                       Context context
                       ) throws IOException, InterruptedException {
      int sum = 0;
      for (IntWritable val : values) {
        sum += val.get();
      }
      result.set(sum);
      context.write(key, result);
    }
  }
  public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();
    String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
    if (otherArgs.length != 2) {
      System.err.println("Usage: wordcount <in> <out>");
      System.exit(2);
    }
    Job job = new Job(conf, "word count");
    job.setJarByClass(WordCount.class);
    job.setMapperClass(TokenizerMapper.class);
    job.setCombinerClass(IntSumReducer.class);
    job.setReducerClass(IntSumReducer.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(IntWritable.class);
    FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
    FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
    System.exit(job.waitForCompletion(true) ? 0 : 1);
  }
}
  • 25
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Hadoop WordCount是一种基于Hadoop框架的词频统计方法,它可以对大规模的文本数据进行分布式处理,实现高效的词频统计。该方法的基本原理是将文本数据分割成若干个小块,然后分别在不同的计算节点上进行处理,最后将结果合并起来得到最终的词频统计结果。Hadoop WordCount已经成为了大规模数据处理领域中的经典案例,被广泛应用于各种数据分析和挖掘任务中。 ### 回答2: Hadoop是一个开源的分布式数据处理框架,它可以对大规模数据进行处理、存储和分析,其中最著名的应用就是MapReduce模型。而词频统计Wordcount)是MapReduce模型的入门案例,它用于统计输入文本中每个单词出现的频率。 首先,需要将文本数据划分成小的数据块(input splits),每个数据块被分配给集群中的某个节点。然后,MapReduce框架会将每个数据块传递给map函数,map函数负责将每个数据块中的单词拆分并输出为一个键值对(key-value pair),其中key是单词,value是1。例如,对于输入数据“hello world hello”,map函数将输出三个键值对:{hello,1},{world,1},{hello,1}。 随后,MapReduce框架将键值对按照key进行排序,并分成若干个分区(partition)。每个分区中的键值对被传递给reduce函数,reduce函数将每个单词的出现次数相加,并输出为一个新的键值对,其中key是单词,value是该单词在文本中出现的总次数。例如,对于上面的三个键值对,reduce函数将输出一个键值对:{hello,2},以此统计出单词hello在文本中出现了两次。 最终,MapReduce框架将reduce函数的输出写入到指定的输出路径中,完成词频统计。 总的来说,Hadoop Wordcount词频统计是一个经典的分布式计算案例,在学习Hadoop分布式计算和MapReduce模型时,都会选择这个案例作为入门练习。通过使用Hadoop Wordcount,可以更好地理解MapReduce框架及其编程模型,掌握Big Data相关知识。 ### 回答3: Hadoop WordCount是一种分布式计算框架,其用于在Hadoop集群上进行词频计数。词频计数是一种常见的数据处理任务,用于计算给定文本中每个单词出现的次数。因此,Hadoop WordCount被广泛用于大规模文本数据处理,例如Web爬虫数据、语音识别数据以及社交媒体数据等。 实现Hadoop WordCount涉及三个过程:Map、Shuffle和Reduce。在Map过程中,输入数据按照键值对的形式传递给Map函数进行处理,此时的键值对是文本中的每行(或者文本块)。Map函数对输入数据进行处理,将每个单词解析出来,并将它们作为键,值为1建立键值对输出。在Shuffle过程中,将输出的键值对根据键进行分组,Shuffle过程将把同一个键的不同值聚合在一起。在Reduce过程中,将每个键的所有值进行合并,并且计算每个键出现的次数。最后得到的结果是每个单词在文本中出现的次数,它们被保存在一个输出文件中。 Hadoop WordCount的概念是易于理解的,而它的框架实现使得它很容易就可以扩展到大型文本数据集的处理。这种框架实现是通过多个计算节点分配任务来实现的,每个节点都可以独立地进行任务处理,不需要在集群中的任何节点中进行全局通信和同步。因此,它可以在不过多耗费时间和资源的情况下快速地处理大量数据。 总体而言,Hadoop WordCount是一种非常实用且高效的数据处理方法,它不仅在数据的处理速度上具有优势,在容错能力和数据可扩展性方面也表现出色。随着大数据的发展,它将在数据处理和分析的未来中扮演重要的角色。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值