编程要求
根据提示,在右侧编辑器的中的 begin-end 间补全 InvertIndex_origin 类中的 map 和 reduce 函数。具体实现如下。
读取 hdfs 中/input
目录下的如下三个文件,文件内容如下:
file1.txt
内容:
mapreduce is simple
file2.txt
内容:
mapreduce is powerful and simple
file3.txt
内容:
mapreduce and mapreduce
使用 mapreduce 处理后把结果输出到 hdfs 的/out
目录下,预期输出内容如下:
and file3.txt:1;file2.txt:1;
is file2.txt:1;file1.txt:1;
mapreduce file1.txt:1;file2.txt:1;file3.txt:2;
powerful file2.txt:1;
simple file2.txt:1;file1.txt:1;
后台会自动把代码打包并执行以下命令提交:
hadoop jar /root/invertedindex-1.0-SNAPSHOT.jar InvertIndex_origin /invertindex /out
测试说明
填写完代码后点击测评,后台会自动运行该程序,并读取输出文件内容,当该内容与预期输出一致,即为通关。
命令行:
#命令行
#启动hdfs
start-dfs.sh
#在本地创建文件夹
cat >file1.txt
mapreduce is simple
cat >file2.txt
mapreduce is powerful and simple
cat >file3.txt
mapreduce and mapreduce
#创建hdfs文件夹
hadoop fs -mkdir /usr/
hadoop fs -mkdir /usr/input
#上传到hdfs
hadoop fs -put file1.txt /usr/input
hadoop fs -put file2.txt /usr/input
hadoop fs -put file3.txt /usr/input
代码文件:
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
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.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class InvertIndex_origin {
public static class Map extends Mapper<Object, Text, Text, Text> {
private Text keyInfo = new Text(); // 存储单词和URL组合
private Text valueInfo = new Text(); // 存储词频
private FileSplit split; // 存储Split对象
// 实现map函数
@Override
public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
// 获得<key,value>对所属的FileSplit对象
split = (FileSplit) context.getInputSplit();
StringTokenizer itr = new StringTokenizer(value.toString());
/**********Begin**********/
while(itr.hasMoreTokens()){
int splitIndex = split.getPath().toString().indexOf("file");//获取文件名 包含file的索引位置
keyInfo.set(itr.nextToken()+":"+split.getPath().toString().substring(splitIndex)); //设定key值
valueInfo.set("1");
context.write(keyInfo, valueInfo);
}
/**********End**********/
}
}
public static class Combine extends Reducer<Text, Text, Text, Text> {
private Text info = new Text();
// 实现reduce函数, 将相同key值的value加起来
// 并将(单词:文件名, value) 转换为 (单词, 文件名:value)
@Override
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
/**********Begin**********/
int sum = 0;
for(Text val:values){
sum += Integer.parseInt(val.toString());
}
int splitIndex = key.toString().indexOf(":");
info.set(key.toString().substring(splitIndex+1)+":"+sum); //新的value值
key.set(key.toString().substring(0, splitIndex));
context.write(key, info);
/**********End**********/
}
}
public static class Reduce extends Reducer<Text, Text, Text, Text> {
private Text result = new Text();
// 实现reduce函数, 将相同单词的value聚合成一个总的value,每个value之间用`;`隔开, 最后以`;`结尾
@Override
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
/**********Begin**********/
String list = new String();
for(Text val:values){
list += val.toString()+";"; //不同的索引文件分隔开来
}
result.set(list);
context.write(key,result);
/**********End**********/
}
}
public static void main(String[] args) throws Exception {
// 第一个参数为 输入文件目录路径, 第二个参数为输出结果路径
Configuration conf = new Configuration();
if (args.length != 2) {
System.err.println("Usage: Inverted Index <in> <out>");
System.exit(2);
}
Job job = new Job(conf, "Inverted Index");
job.setJarByClass(InvertIndex_origin.class);
// 设置Map、Combine和Reduce处理类
job.setMapperClass(Map.class);
job.setCombinerClass(Combine.class);
job.setReducerClass(Reduce.class);
// 设置Map输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
// 设置Reduce输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
// 设置输入和输出目录
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}