最近在学习mapreduce编程方面的知识,刚开始学习,所以障碍感觉还是有很多的。有不少地方不明白,看来还是要好好的看一下mapreduce的实现机制,以及提供的函数接口的功能是什么。
package an.hadoop.tf;
//计算文件的TF值
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.Mapper.Context;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class ComputeTF {
public static class Mapper_TF extends Mapper <LongWritable, Text, Text , Text>{
String file_name ="";
int word_count = 0;
static Text one = new Text("1");
String word;
//每个map也只是一个文件吗?其实是在执行循环,就是循环的在执行这个map 而不是一次调用
//file-name 和word-count 都能作为对一个文件的全局量,所以应该是每个文件都会初始化一次file-name
//也对,任务是分配到不同的map上执行的,也就说会调用多次map来做
public void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
//这个分裂输入
FileSplit split = (FileSplit) context.getInputSplit();
//split应该输入文件
String str = split.getPath().toString();
file_name = str.substring(str.lastIndexOf("/")+1); //获取文件名
//分词
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word = file_name ;
word += " ";
word += itr.nextToken(); //将文件名加单词作为key es: test1 hello 1
word_count++;
context.write(new Text(word), one);
}
}//map
public void cleanup(Context context) throws IOException,
InterruptedException {
//Map的最后,我们将单词的总数写入。下面需要用总单词数来计算。
String str = "";
str += word_count;
context.write(new Text(file_name + " " + "!"), new Text(str));
//主要这里值使用的 "!"是特别构造的。 因为!的ascii比所有的字母都小。
}
}//mapper
public static class Reduce_TF extends Reducer<Text, Text, Text, Text> {
float all = 0;
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
int index = key.toString().indexOf(" ");
//因为!的ascii最小,所以在map阶段的排序后,!会出现在第一个
if (key.toString().substring(index + 1, index + 2).equals("!")){
for (Text val : values) {
//获取总的单词数。
all = Integer.parseInt(val.toString());
}
//这个key-value被抛弃
return;
}
float sum = 0; //统计某个单词出现的次数
for (Text val : values) {
sum += Integer.parseInt(val.toString());
}
//跳出循环后,某个单词数出现的次数就统计完了,所有 TF(词频) = sum / all
float tmp = sum / all;
String value = "";
value += tmp; //记录词频
//将key中单词和文件名进行互换。es: test1 hello -> hello test1
String p[] = key.toString().split(" ");
String key_to = "";
key_to += p[1];
key_to += " ";
key_to += p[0];
context.write(new Text(key_to), new Text(value));
}
}//reducer
//一定要加上这个reduce才行,也不是太明白为什么
public static class Reduce_Part1 extends Reducer<Text, Text, Text, Text> {
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
for (Text val : values) {
context.write(key, val);
}
}
}
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: TF-IDF <in> <out>");
System.exit(2);
}
int file_number = 5;
Job job = new Job(conf, "comute tf-idf");
//设置对应的主类,map、reduce和combine类
job.setJarByClass(ComputeTF.class);
job.setMapperClass(Mapper_TF.class);
job.setCombinerClass(Reduce_TF.class);
job.setReducerClass(Reduce_Part1.class);
//mapreduce的输出数据格式
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
//job.setPartitionerClass(MyPartitoner.class); //使用自定义MyPartitoner
//输入输出路径设置
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}//compute-tf
希望各位能够多多指点,以及给推荐一下需要学习的资料