MapReduce-Counter使用

在普通的java程序中我们可以定义一个全局的静态变量,然后我们可以在各个类中去使用,实现累加器的功能,然而在mapruduce中怎么实现这一功能呢,各个map可能运行在不同的JVM中(这里不考虑JVM重用的情况),然而我们可以借助MapReduce提供的Counter功能来实现这一功能,下面我们通过一个实例来说明这一个用法。
实验要求:快速实现文件行数,以及其中错误记录的统计
实验数据:
1
2
error
3
4
5
error
6
7
8
9
10
error
11
12
13
14
error
15
16
17
18
19
解决思路:
定义一个枚举类型,每次调用map函数时,对值进行判断,把判断的结果分别写入不同的Counter,最后输出Counter的值
根据以上步骤下面是实现代码:

map阶段:

  1. import java.io.IOException;  
  2. import org.apache.hadoop.io.IntWritable;  
  3. import org.apache.hadoop.io.LongWritable;  
  4. import org.apache.hadoop.io.Text;  
  5. import org.apache.hadoop.mapreduce.Mapper;  
  6.   
  7. public class MyMapper extends Mapper<LongWritable, Text, LongWritable, IntWritable> {  
  8.     /** 
  9.      * 定义一个枚举类型 
  10.      * @date 2016年3月25日 下午3:29:44  
  11.      * @{tags} 
  12.      */  
  13.     public static enum FileRecorder{  
  14.         ErrorRecorder,  
  15.         TotalRecorder  
  16.     }  
  17.     @Override  
  18.     protected void map(LongWritable key, Text value, Context context)  
  19.             throws IOException, InterruptedException {  
  20.         if("error".equals(value.toString())){  
  21.             /** 
  22.              * 把counter实现累加 
  23.              */  
  24.             context.getCounter(FileRecorder.ErrorRecorder).increment(1);  
  25.         }  
  26.         /** 
  27.          * 把counter实现累加 
  28.          */  
  29.         context.getCounter(FileRecorder.TotalRecorder).increment(1);  
  30.     }  
  31. }  
启动函数:
  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.LongWritable;  
  6. import org.apache.hadoop.mapreduce.Job;  
  7. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  8. import org.apache.hadoop.mapreduce.lib.input.NLineInputFormat;  
  9. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  10. import com.seven.mapreduce.counter.MyMapper.FileRecorder;  
  11. public class JobMain {  
  12.     public static void main(String[] args) throws Exception {  
  13.         Configuration configuration = new Configuration();  
  14.         /** 
  15.          * 使NLineInputFormat来分割一个小文件,近而模拟分布式大文件的处理 
  16.          */  
  17.         configuration.setInt("mapreduce.input.lineinputformat.linespermap"5);   
  18.         Job job = new Job(configuration, "counter-job");  
  19.         job.setInputFormatClass(NLineInputFormat.class);    
  20.         job.setJarByClass(JobMain.class);  
  21.         job.setMapperClass(MyMapper.class);  
  22.         job.setMapOutputKeyClass(LongWritable.class);  
  23.         job.setMapOutputValueClass(IntWritable.class);  
  24.         FileInputFormat.addInputPath(job, new Path(args[0]));  
  25.         Path outputDir = new Path(args[1]);  
  26.         FileSystem fs = FileSystem.get(configuration);  
  27.         if( fs.exists(outputDir)) {  
  28.             fs.delete(outputDir ,true);  
  29.         }  
  30.         FileOutputFormat.setOutputPath(job, outputDir);  
  31.         if(job.waitForCompletion(true) ? truefalse) {  
  32.             System.out.println("Error num:" + job.getCounters().findCounter(FileRecorder.ErrorRecorder).getValue());  
  33.             System.out.println("Total num:" + job.getCounters().findCounter(FileRecorder.TotalRecorder).getValue());  
  34.         }  
  35.     }  
  36. }  
运行结果:



总结:

由上可以看出总共跑了5个map任务,而且通过Counter实现了不同JVM中的全局累加器的功能。关于除自定义Counter以外的其它Counter的含义

原文地址:http://blog.csdn.net/doegoo/article/details/50981196

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TF-IDF(Term Frequency-Inverse Document Frequency)是一种用于信息检索和文本挖掘的常用技术,它能够评估一个词语在一个文档集合中的重要程度。 在Hadoop MapReduce框架下实现TF-IDF,需要完成以下步骤: 1. 计算每个文档中每个单词出现的次数(Term Frequency,即TF)。 2. 计算每个单词在整个文档集合中出现的文档数(Inverse Document Frequency,即IDF)。 3. 计算每个单词在每个文档中的TF-IDF值。 下面是一个基于Hadoop MapReduce实现TF-IDF的示例: 1. 计算每个文档中每个单词出现的次数 首先,我们需要将文档集合分成若干个小文件,每个小文件包含若干个文档。在Map阶段,我们需要将每个小文件中的每个文档转换成键值对形式,其中键为文档ID,值为文档内容。然后,在Reduce阶段,我们需要对每个文档进行分词,并计算每个单词在该文档中出现的次数。 Map阶段: ```java public class TFMapper extends Mapper<LongWritable, Text, Text, Text> { private Text docID = new Text(); private Text wordCount = new Text(); public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] parts = value.toString().split("\\t"); String docContent = parts[1]; String[] words = docContent.split(" "); Map<String, Integer> wordCounts = new HashMap<String, Integer>(); for (String word : words) { if (wordCounts.containsKey(word)) { wordCounts.put(word, wordCounts.get(word) + 1); } else { wordCounts.put(word, 1); } } for (String word : wordCounts.keySet()) { docID.set(parts[0]); wordCount.set(word + ":" + wordCounts.get(word)); context.write(docID, wordCount); } } } ``` Reduce阶段: ```java public class TFReducer extends Reducer<Text, Text, Text, Text> { private Text wordCount = new Text(); public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException { Map<String, Integer> wordCounts = new HashMap<String, Integer>(); for (Text value : values) { String[] parts = value.toString().split(":"); String word = parts[0]; int count = Integer.parseInt(parts[1]); if (wordCounts.containsKey(word)) { wordCounts.put(word, wordCounts.get(word) + count); } else { wordCounts.put(word, count); } } StringBuilder sb = new StringBuilder(); for (String word : wordCounts.keySet()) { sb.append(word + ":" + wordCounts.get(word) + " "); } wordCount.set(sb.toString()); context.write(key, wordCount); } } ``` 2. 计算每个单词在整个文档集合中出现的文档数 在Map阶段,我们需要将每个文档中的单词转换成键值对形式,其中键为单词,值为文档ID。然后,在Reduce阶段,我们需要对每个单词进行统计,得到每个单词在多少个文档中出现过。 Map阶段: ```java public class IDFMapper extends Mapper<LongWritable, Text, Text, Text> { private Text word = new Text(); private Text docID = new Text(); public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] parts = value.toString().split("\\t"); String[] words = parts[1].split(" "); for (String w : words) { word.set(w); docID.set(parts[0]); context.write(word, docID); } } } ``` Reduce阶段: ```java public class IDFReducer extends Reducer<Text, Text, Text, DoubleWritable> { private DoubleWritable idf = new DoubleWritable(); public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException { Set<String> docs = new HashSet<String>(); for (Text value : values) { docs.add(value.toString()); } double df = docs.size(); double N = context.getConfiguration().getLong("totalDocs", 1L); double idfValue = Math.log(N / df); idf.set(idfValue); context.write(key, idf); } } ``` 3. 计算每个单词在每个文档中的TF-IDF值 在Map阶段,我们需要将每个文档中的单词转换成键值对形式,其中键为文档ID和单词,值为单词在该文档中出现的次数和该单词的IDF值。然后,在Reduce阶段,我们需要对每个文档中的所有单词进行统计,得到每个单词在该文档中的TF-IDF值。 Map阶段: ```java public class TFIDFMapper extends Mapper<LongWritable, Text, Text, Text> { private Text docID = new Text(); private Text wordCountIDF = new Text(); public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] parts = value.toString().split("\\t"); String[] wordCounts = parts[1].split(" "); for (String wc : wordCounts) { String[] subParts = wc.split(":"); String word = subParts[0]; int count = Integer.parseInt(subParts[1]); double idf = Double.parseDouble(subParts[2]); docID.set(parts[0] + ":" + word); wordCountIDF.set(count + ":" + idf); context.write(docID, wordCountIDF); } } } ``` Reduce阶段: ```java public class TFIDFReducer extends Reducer<Text, Text, Text, DoubleWritable> { private DoubleWritable tfidf = new DoubleWritable(); public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException { int count = 0; double idf = 0.0; for (Text value : values) { String[] parts = value.toString().split(":"); count += Integer.parseInt(parts[0]); idf = Double.parseDouble(parts[1]); } tfidf.set(count * idf); context.write(key, tfidf); } } ``` 最后,在Driver中将上述三个阶段串联起来,即可完成TF-IDF的计算。 ```java public class TFIDFDriver { public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job1 = Job.getInstance(conf, "TF"); job1.setJarByClass(TFIDFDriver.class); job1.setInputFormatClass(TextInputFormat.class); job1.setOutputFormatClass(TextOutputFormat.class); job1.setMapperClass(TFMapper.class); job1.setCombinerClass(TFReducer.class); job1.setReducerClass(TFReducer.class); job1.setOutputKeyClass(Text.class); job1.setOutputValueClass(Text.class); FileInputFormat.addInputPath(job1, new Path(args[0])); FileOutputFormat.setOutputPath(job1, new Path(args[1])); job1.waitForCompletion(true); Job job2 = Job.getInstance(conf, "IDF"); job2.setJarByClass(TFIDFDriver.class); job2.setInputFormatClass(TextInputFormat.class); job2.setOutputFormatClass(TextOutputFormat.class); job2.setMapperClass(IDFMapper.class); job2.setReducerClass(IDFReducer.class); job2.setOutputKeyClass(Text.class); job2.setOutputValueClass(DoubleWritable.class); FileInputFormat.addInputPath(job2, new Path(args[1])); FileOutputFormat.setOutputPath(job2, new Path(args[2])); job2.getConfiguration().setLong("totalDocs", job2.getCounters().findCounter("org.apache.hadoop.mapred.Task$Counter", "MAP_INPUT_RECORDS").getValue()); job2.waitForCompletion(true); Job job3 = Job.getInstance(conf, "TF-IDF"); job3.setJarByClass(TFIDFDriver.class); job3.setInputFormatClass(TextInputFormat.class); job3.setOutputFormatClass(TextOutputFormat.class); job3.setMapperClass(TFIDFMapper.class); job3.setReducerClass(TFIDFReducer.class); job3.setOutputKeyClass(Text.class); job3.setOutputValueClass(DoubleWritable.class); FileInputFormat.addInputPath(job3, new Path(args[1])); FileOutputFormat.setOutputPath(job3, new Path(args[3])); job3.waitForCompletion(true); } } ``` 以上就是基于Hadoop MapReduce实现TF-IDF的方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值