文件一 package hadooptext; import java.io.IOException; 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.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; /** * 基本上等于yarn集群(分配运算资源)的客户端 * 封装mr程序运行参数,指定jar包交给yarn * @author lws * */ public class wordCountDriver { public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { Configuration conf = new Configuration();//传来了默认参数 //启动参数封装为job对象 Job job = Job.getInstance(conf); //程序一般经过打包之后运行,设置jar包所在目录 //job.setJar("");写死路径 //指定本程序jar所在的本地路径 job.setJarByClass(wordCountDriver.class);//类一旦运行就可以找到类所在的路径 //给job指定使用的mapper类 job.setMapperClass(wordcountmapper.class); //给job指定使用的reduce类 job.setReducerClass(wordcountreducer.class); //指定mapper输出数据类型 job.setMapOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); //指定reduce输出数据类型(最终输出数据类型) job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); //指定job的输入文件目录(hdfs文件系统的目录) FileInputFormat.addInputPath(job, new Path(args[0]));//此处可以写死,也可以通过满函数的args 来传参 // 判断output文件夹是否存在,如果存在则删除 Path path = new Path(args[1]);// 取第1个表示输出目录参数(第0个参数是输入目录) FileSystem fileSystem = path.getFileSystem(conf);// 根据path找到这个文件 if (fileSystem.exists(path)) { fileSystem.delete(path, true);// true的意思是,就算output有东西,也一带删除 } //指定job输出结果所在目录(hdfs文件系统的目录) FileOutputFormat.setOutputPath(job, new Path(args[1])); //把job配置的参数,和job用的jar目录交给yarn,让yarn来运行 //job.submit(); //等待结果返回 boolean result = job.waitForCompletion(true); System.exit(result?0:1); } } 文件二 package hadooptext; import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; /** * KEYID 默认情况下为mr 框架读到一行文本的起始偏移量 (long类型) * 序列化之后通过网络传输,但是 serizalizable 框架序列化之后又有冗余为 * 了减少冗余使用hadoop精简版序列化接口 LongWritable,其本质数据类型为Long * * VALUEIN 默认情况下为mr框架读到一行文本的内容(使用org.apache.hadoop.io.Text类型【原因同上】本质String类型) * * KEYOUT 默认情况下为用户自定义逻辑运算之后的输出数据的键(key)此处为String 所以同上用Text * * VALUEOUT 默认情况下为用户自定义逻辑运算之后的输出数据的键值(value)此处为Integer同上用IntWritable * author lws * */ public class wordcountmapper extends Mapper<longwritable text="" text="" intwritable="">{ /** * map 阶段的业务处理逻辑写在该map()方法之内 * maptask会对每一行的输入数据都调用一次该map()方法 */ @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { //把maptask传递来的内容转化为String 类型便于操作 String line = value.toString(); //空格切割该行的文本 String[] words = line.split(" "); //把单词作为key次数1作为value输出到reduce中去,可以根据单词到某个reduce for (String word : words) { //前面已经定义输出的key为Text类型输出的value为IntWritable类型 //所以word要封装为Text类型,1要封装为IntWritable类型 context.write(new Text(word), new IntWritable(1)); } //maptask不会立即把该行运算的结果发给reduce,而是写入某个文件中,到最后发 } } </longwritable> 文件三 package hadooptext; import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; /** * (KEYIN VALUEIN)输入的数据和maptask输出的数据类型对应所以为(Text,IntWritable) * KEYOUT和VALUEOUT为自定义的reduce业务逻辑处理之后输出的类型(单词Text,次数IntWritable) * @author lws * */ public class wordcountreducer extends Reducer<text intwritable="" text="" intwritable="">{ /** * key 是相同单词键值对的key(map处理之后有很多相同键值对<**,1>reduce根据传递来的第一个键值对的的键,迭代所传递来的每一个相同键值对的value) */ @Override protected void reduce(Text key, Iterable<intwritable> values,Context context) throws IOException, InterruptedException { int count=0; for (IntWritable value : values) { count += value.get(); } context.write(key, new IntWritable(count)); /** * 业务输出的key,value会被写入一个目标(写入hdfs文件系统的几个【根据reducetask个数而定】文件中去) * 每一个文件包含一部分单词----------所以要告诉它写入什么文件()至于怎么告诉,就看带有猪脚光环的main方法 */ } } </intwritable></text> 运行截图如下: 运行最后状态如下图 查询输出结果如下如: