Hadoop中如何统计不同单词总数?是否需统计键的数量?
解答:统计Hadoop单词计数结果中的唯一单词总数
没错!你理解得完全正确——要得到不同单词的总数,就是统计结果里键的数量,因为每个键对应一个唯一的单词,正好匹配你预期的结果5。
下面给你两种实用的实现方案,适配不同的场景:
方案一:修改原WordCount任务,直接输出唯一单词数
如果不想单独处理已生成的结果文件,可以在原有的单词计数逻辑上做小修改,让任务跑完直接给出总数:
修改Reducer代码
原Reducer的作用是累加每个单词的出现次数,现在我们在处理每个单词的同时,悄悄统计唯一单词的数量,最后在任务结束时输出这个总数:
import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> { private IntWritable result = new IntWritable(); private int uniqueWordCount = 0; @Override protected 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); // 每处理一个键(也就是一个唯一单词),计数加1 uniqueWordCount++; } @Override protected void cleanup(Context context) throws IOException, InterruptedException { // 所有单词处理完后,输出唯一单词的总数 context.write(new Text("Unique_Word_Count"), new IntWritable(uniqueWordCount)); } }
运行修改后的任务,结果文件里除了原来的hello 5这类键值对,最后会多一行Unique_Word_Count 5,这就是你要的答案。
方案二:写个轻量MapReduce任务处理已有结果
如果已经有现成的单词计数结果,不想重新跑原任务,可以写一个极简的MapReduce任务专门统计键的数量:
Mapper代码
Mapper不需要做复杂拆分,每读取一行结果,就输出一个固定键和值1:
import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; public class UniqueWordCounterMapper extends Mapper<Object, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text countKey = new Text("Unique_Word_Count"); @Override protected void map(Object key, Text value, Context context) throws IOException, InterruptedException { // 每一行对应一个唯一单词,直接输出1即可 context.write(countKey, one); } }
Reducer代码
Reducer只需要把所有的1累加起来,得到的就是键的总数:
import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; public class UniqueWordCounterReducer extends Reducer<Text, IntWritable, Text, IntWritable> { @Override protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; for (IntWritable val : values) { sum += val.get(); } context.write(key, new IntWritable(sum)); } }
驱动类配置
把这个任务的输入指向原单词计数的结果路径,输出设为新路径即可:
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.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class UniqueWordCounterDriver { public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = Job.getInstance(conf, "unique-word-counter"); job.setJarByClass(UniqueWordCounterDriver.class); job.setMapperClass(UniqueWordCounterMapper.class); job.setCombinerClass(UniqueWordCounterReducer.class); // 可选,加这个能优化计算效率 job.setReducerClass(UniqueWordCounterReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); FileInputFormat.addInputPath(job, new Path(args[1])); // 原单词计数结果的路径 FileOutputFormat.setOutputPath(job, new Path(args[2])); // 新结果的输出路径 System.exit(job.waitForCompletion(true) ? 0 : 1); } }
快速验证小技巧
如果只是想快速得到结果,不用写代码,直接用HDFS命令行统计结果文件的行数就行(每个唯一单词占一行):
hdfs dfs -cat /your/wordcount/result/path/* | wc -l
这条命令会直接返回行数,也就是你要的唯一单词数量,非常适合快速排查。
内容的提问来源于stack exchange,提问作者FlyingBurger
相关产品推荐
相关产品推荐

