实验:分析和编写 WordCount 程序
原始数据:
a good beginning is half the battle
where there is a will there is a way
思路:读取文件,采用 TextInputformat 读取每一行数据,切割得到每一个单词,进行 map,reduce 后得到每个单词出现的次数,可使用 Combiner。
Map阶段:k1 为文本偏移值,v1 为每行的数据,进行切割,得到 k2 为每个单词。V2 都为 1,然后写到上下文对象中。
Shuffle阶段:这里使用了规约,以减少网络传输量(和 reduce 代码一样),分区、排序、分组采用系统默认。
Reduce阶段:shuffle 后得到新的 k2 和 v2,此时 v2 是一个集合,元素都是1,对他相加就可以得到对应单词出现的次数,即 v3,而 k3 和新的 k2 是一样的。
结果:
没有使用 Combiner
使用 Combiner
可以看到使用规约后,map 后的 <k2,v2> 进行网络传输少了一些,以减少网络开销,当然只有在不改变结果的逻辑才能规约。
其他 MapReduce 实验:
本次实验的代码
Map代码:
package lhr.word_count.homework;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class word_count_Mapper extends Mapper<LongWritable, Text, Text, LongWritable> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
/*
map阶段:
首先将读取到的每一行以空格进行切割得到每个单词,
再将每个单词写到上下文对象,即<k2,v2>,k2的值为每个单词,v2的值为1。
*/
String[] s = value.toString().split(" ");
for (String s1 : s) {
context.write(new Text(s1), new LongWritable(1));
}
}
}
Combiner代码:
package lhr.word_count.homework;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class word_count_combiner extends Reducer<Text, LongWritable, Text, LongWritable> {
@Override
protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
long word_counts = 0;
for (LongWritable value : values) {
word_counts += value.get();
}
context.write(key, new LongWritable(word_counts));
}
}
Reduce代码:
package lhr.word_count.homework;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class word_count_Reducer extends Reducer<Text, LongWritable, Text, LongWritable> {
@Override
protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
/*
reduce阶段:
对shuffle网络传输(分区、排序、规约、分组)过来的新k2,v2进行统计,
将v2中每个1相加,得到该单词出现的次数。
*/
long word_counts = 0;
for (LongWritable value : values) {
word_counts += value.get();
}
context.write(key, new LongWritable(word_counts));
}
}
Main代码:
package lhr.word_count.homework;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import java.net.URI;
public class word_count_Main extends Configured implements Tool {
//指定job任务
@Override
public int run(String[] strings) throws Exception {
//2:配置job任务对象
Job job = Job.getInstance(super.getConf(), "word_count");
//指定jar包主类
job.setJarByClass(word_count_Main.class);
//采用默认的类一行一行读取文件内容
job.setInputFormatClass(TextInputFormat.class);
//指定读取文件的地址,可以本地,也可以集群
// TextInputFormat.addInputPath(job, new Path("hdfs://hadoop11:8020/word_count"));
TextInputFormat.addInputPath(job, new Path("file:///D:\\input0"));
//指定Map阶段的处理方式和数据类型
job.setMapperClass(word_count_Mapper.class);
job.setMapOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//规约,减少网络传输
job.setCombinerClass(word_count_combiner.class);
//指定Reduce阶段的处理方式和数据类型
job.setReducerClass(word_count_Reducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//采用默认的类一行一行存文件内容
job.setOutputFormatClass(TextOutputFormat.class);
//指定输出结果文件的地址,可以本地,也可以集群
// Path path = new Path("hdfs://hadoop11:8020/word_count_result");
Path path = new Path("file:///D:\\output0");
TextOutputFormat.setOutputPath(job, path);
//如果集群输出结果文件存在,删除,方便下次运行
// FileSystem fileSystem = FileSystem.get(new URI("hdfs://hadoop11:8020"), super.getConf(), "root");
// if (fileSystem.exists(path)) {
// fileSystem.delete(path, true);
// }
//等待任务结束
boolean b = job.waitForCompletion(true);
return b ? 0 : 1;
}
public static void main(String[] args) throws Exception {
Configuration configuration = new Configuration();
//启动job任务
int run = ToolRunner.run(configuration, new word_count_Main(), args);
System.exit(run);
}
}