文章目錄
0.參考資料:
http://radarradar.javaeye.com/blog/289257
http://blog.chinaunix.net/u3/99156/showart_2157576.html
1.思路:1.1過濾
MapReduce的第一操作就是要讀取檔案,不過我們經常會發現一個文本中會有一些我們不需要的字元,比如特殊字元。一般需要進行詞頻統計的都是單詞或者是數字,所以那些非0-9, a-z, A-Z的字元基本都是垃圾字元,我們需要進行統計,這是我們可以通過一個Regex來進行過濾,當每次多去一行文字的時候,我們將所有非0-9, a-z, A-Z的垃圾字元都替換為空白格,這樣就清楚了垃圾字元。在我們最後的詞頻統計結果中,就不會出現這些特殊字元了。
1.2降序
定義一個使用者排序比較的靜態內部類,通過這個類來控制詞頻統計最後的排序結果。我們這裡所使用的靜態內部類是IntWritableDecreasingComparator。需要注意的是必須在main函數中主動聲明使用這個比較子。
2.代碼執行個體View Code
package org.apache.hadoop.examples;import java.io.IOException;import java.util.Random;import java.util.StringTokenizer;import org.apache.hadoop.conf.Configuration;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.input.SequenceFileInputFormat;import org.apache.hadoop.mapreduce.lib.map.InverseMapper;import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;import org.apache.hadoop.util.GenericOptionsParser;public class WordCount2 { public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); private String pattern = "[^//w]"; // Regex,代表不是0-9, a-z, A-Z的所有其它字元,其中還有底線 public void map(Object key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString().toLowerCase(); // 全部轉為小寫字母 line = line.replaceAll(pattern, " "); // 將非0-9, a-z, A-Z的字元替換為空白格 StringTokenizer itr = new StringTokenizer(line); 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); } } private static class IntWritableDecreasingComparator 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 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); } Path tempDir = new Path("wordcount-temp-" + Integer.toString( new Random().nextInt(Integer.MAX_VALUE))); //定義一個臨時目錄 Job job = new Job(conf, "word count"); job.setJarByClass(WordCount2.class); try{ 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, tempDir);//先將詞頻統計任務的輸出結果寫到臨時目 //錄中, 下一個排序任務以臨時目錄為輸入目錄。 job.setOutputFormatClass(SequenceFileOutputFormat.class); if(job.waitForCompletion(true)) { Job sortJob = new Job(conf, "sort"); sortJob.setJarByClass(WordCount2.class); FileInputFormat.addInputPath(sortJob, tempDir); sortJob.setInputFormatClass(SequenceFileInputFormat.class); /*InverseMapper由hadoop庫提供,作用是實現map()之後的資料對的key和value交換*/ sortJob.setMapperClass(InverseMapper.class); /*將 Reducer 的個數限定為1, 最終輸出的結果檔案就是一個。*/ sortJob.setNumReduceTasks(1); FileOutputFormat.setOutputPath(sortJob, new Path(otherArgs[1])); sortJob.setOutputKeyClass(IntWritable.class); sortJob.setOutputValueClass(Text.class); /*Hadoop 預設對 IntWritable 按升序排序,而我們需要的是按降序排列。 * 因此我們實現了一個 IntWritableDecreasingComparator 類, * 並指定使用這個自訂的 Comparator 類對輸出結果中的 key (詞頻)進行排序*/ sortJob.setSortComparatorClass(IntWritableDecreasingComparator.class); System.exit(sortJob.waitForCompletion(true) ? 0 : 1); } }finally{ FileSystem.get(conf).deleteOnExit(tempDir); } }}