MapReduce实现改进版WordCount词频统计

新手入门MapReduce实现改进版WordCount词频统计

一、实验任务要求

本实验是为了实现改进版的词频统计WordCount。要求根据所给的英文名著数据集和停用词表,统计英文名著数据集中词频,过滤掉停用词,将统计结果按照词频降序排序,词频相同的词按照字典序排序。

英文名著数据集和停用词表再此处(提取码:ceij)

二、实验工具和环境配置说明

电脑安装了Vmware软件,搭建Centos7系统环境,配置了Hadoop2.7.4单机伪分布环境并安装eclipse编程软件,使用Java语言完成实验任务。

三、步骤

首先我们对实验任务进行划分,将实验任务划分为两个子任务:词频统计和排序,针对两个子任务job分别进行设计。

1.词频统计

(1)首先,我们在这个任务阶段需要英文名著数据集和停用词表,统计是针对英文名著数据集,但要过滤掉停用词,所以map阶段要判断接收到的词是不是停用词,不是则输出。这就要保证每个map都能使用停用词表,所以,就要使用map中的Setup把这个停用词表变成一个全局变量;
在这里插入图片描述
在main函数里的第一个job中加入缓存文件停用词表stopwords.txt。
在这里插入图片描述
在Mapper中的设置一个空列表li,在Mapper中的setup阶段读缓存文件,将其中的每一个停用词加入到列表中。
(2)获得了全局变量停用词列表后,接下来就要获得文章的每个词,判断词如果不是停用词,输出<key=词,value=词频1>。
在这里插入图片描述
将英文名著按行读取,使用空格等标点符号分割成一个个词,将词化为小写,如果词不在停用词列表中,输出。
(3)Reducer收到词,将key即相同的词merge合并累计词频。
在这里插入图片描述

2.排序

(1)首先,我们排序是对任务一的词频文件进行排序,由任务一job1,我们已经获得了统计好的词频文件存储在test文件夹中,将词频统计job1的输出路径作为排序job2的输入路径;
在这里插入图片描述
在这里插入图片描述

(2)然而我们排序不是简单的按词的字典序排序,也不是按照词频排序,而是将二者综合在一起排序,所以我们要自定义排序方式,由于MapReduce是根据key来排序,所以我们要自定义key的数据类型从而自定义排序方式。
在这里插入图片描述
我自定义了一个数据类型myclass,其中两个变量x代表词频,y代表词。
在这里插入图片描述
排序方式定义为按词频降序,词频相同按照词的字典序排序。

(3)Mapper中读取词和词频,构造输出<key,value>为类型为myclass,IntWritable。
在这里插入图片描述
(4)Reducer把输出的key再改回词。
在这里插入图片描述

实验结果与展示:

(按词频排序)
(词频相同字典序排序)
所有代码如下:


import java.io.BufferedReader;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.nio.file.FileStore;
import java.nio.file.PathMatcher;
import java.nio.file.WatchService;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.nio.file.spi.FileSystemProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.filecache.DistributedCache;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
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();
    static List<String> li = new ArrayList<String>();
	@Override
	protected void setup(Context context)throws IOException, InterruptedException {//获取缓存文件路径的数组
		Path [] paths = DistributedCache.getLocalCacheFiles(context.getConfiguration());
		System.out.println(paths);
		BufferedReader sb = new BufferedReader(new FileReader(paths[0].toUri().getPath()));
		//读取BufferedReader里面的数据
		String tmp = null;
		while ( (tmp = sb.readLine()) != null) {
			String ss []= tmp.split(" ");
			for (String s : ss) {
				li.add(s);
			}
		}
			//关闭sb对象
		sb.close();
		System.out.println("+++++++"+li);
		}
		
    public void map(Object key, Text value, Context context
                    ) throws IOException, InterruptedException {
      StringTokenizer itr = new StringTokenizer(value.toString()," \'\",!.?(){}-:;@#&*/[]`s<>_");
      while (itr.hasMoreTokens()) {
    	  String tmpword = itr.nextToken();
    	  if(!li.contains(tmpword.toLowerCase())){
    		  word.set(tmpword.toLowerCase());
    	      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 class myclass implements WritableComparable<myclass> {
		public int x;
		public String y;

		public int getX() {
			return x;
		}

		public String getY() {
			return y;
		}

		public void readFields(DataInput in) throws IOException {
			x = in.readInt();
			y = in.readUTF();

		}

		public void write(DataOutput out) throws IOException {
			out.writeInt(x);
			out.writeUTF(y);

		}

		public int compareTo(myclass p) {
			if (this.x > p.x) {
				return -1;
			} else if (this.x < p.x) {
				return 1;
			} else {
				if (this.getY().compareTo(p.getY()) < 0) {
					return -1;
				} else if (this.getY().compareTo(p.getY()) > 0) {
					return 1;
				} else {
					return 0;
				}

			}
		}

	}

	public static class Mysorter extends IntWritable.Comparator {
		public int compare(WritableComparable a, WritableComparable b) {
			return -super.compare(a, b);
		}

		public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
			return -super.compare(b1, s1, l1, b2, s2, l2);
		}
	}

  public static class TokenizerMapper1 
  extends Mapper<Object, Text, myclass, IntWritable>{
	  //private Text keyInfo = new Text();  
	  private IntWritable valueInfo = new IntWritable();
	  @Override
 
	  public void map(Object key, Text value, Context context
               ) throws IOException, InterruptedException {
        StringTokenizer itr = new StringTokenizer( value.toString());
		  String[] word = value.toString().split("\\s+");
		  myclass keyInfo = new myclass();
		  keyInfo.x=Integer.parseInt(word[word.length-1]);
		  keyInfo.y=word[word.length-2];
		  //keyInfo.set( word[0]);		  
		  valueInfo.set(Integer.parseInt(word[word.length-1]));
		  	context.write(keyInfo, valueInfo);   
		  	
	  }
}

  public static class IntSumReducer1 
  extends Reducer<myclass,IntWritable,Text,IntWritable> {
	  
	  private IntWritable valueInfo = new IntWritable();
	  private Text keyInfo = new Text(); 
	  public void reduce(myclass key, Iterable<IntWritable> values, 
                  Context context
                  ) throws IOException, InterruptedException {
		  keyInfo.set(key.y);
		  valueInfo.set(key.x);
		  context.write(keyInfo,valueInfo);
	  }
  }
  
  public static void main(String[] args) throws Exception {
	  //任务一
    Configuration conf = new Configuration();
    //FileSystem hdfs= FileSystem.get(conf);
    //conf.set("stop", "hdfs://localhost:9000/input/stopwords.txt");
    //DistributedCache.addCacheFile(new URI("hdfs://localhost:9000/discache"), conf);
    //String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
    String[] otherArgs = new String[]{"hdfs://localhost:9000/input/index/data",
			"hdfs://localhost:9000/output/test"};
    if (otherArgs.length < 2) {
      System.err.println("Usage: wordcount <in> [<in>...] <out>");
      System.exit(2);
    }
    Job job1 = Job.getInstance(conf, "word count");
    job1.setJarByClass(WordCount.class);
    //设置分布式缓存文件
  	job1.addCacheFile(new URI("hdfs://localhost:9000/input/stopwords/stopwords.txt"));
    job1.setMapperClass(TokenizerMapper.class);
    job1.setCombinerClass(IntSumReducer.class);
    job1.setReducerClass(IntSumReducer.class);
    job1.setOutputKeyClass(Text.class);
    job1.setOutputValueClass(IntWritable.class);
    for (int i = 0; i < otherArgs.length - 1; ++i) {
      FileInputFormat.addInputPath(job1, new Path(otherArgs[i]));
    }
    FileOutputFormat.setOutputPath(job1,
      new Path(otherArgs[otherArgs.length - 1]));
	job1.waitForCompletion(true);
	//任务2
	Configuration conf1 = new Configuration();
	Job job2 = Job.getInstance(conf1, "sort");
	job2.setMapperClass(TokenizerMapper1.class);
	job2.setReducerClass(IntSumReducer1.class);
	job2.setMapOutputKeyClass(myclass.class);
   job2.setMapOutputValueClass(IntWritable.class);
	job2.setOutputKeyClass(Text.class);
	job2.setOutputValueClass(IntWritable.class);
	//job1.setSortComparatorClass(Mysorter.class);
	FileInputFormat.addInputPath(job2, new Path(otherArgs[otherArgs.length - 1]));
	
	FileOutputFormat.setOutputPath(job2,
	  new Path("hdfs://localhost:9000/output/sort"));
    System.exit(job2.waitForCompletion(true) ? 0 : 1);
  }
}
  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值