1 package mapred; 2 3 import java.io.IOException; 4 import java.util.StringTokenizer; 5 import org.apache.hadoop.conf.Configuration; 6 7 import org.apache.hadoop.fs.Path; 8 import org.apache.hadoop.io.IntWritable; 9 import org.apache.hadoop.io.Text; 10 import org.apache.hadoop.io.WritableComparable; 11 import org.apache.hadoop.mapreduce.Job; 12 import org.apache.hadoop.mapreduce.Mapper; 13 14 import org.apache.hadoop.mapreduce.Reducer; 15 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 16 import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat; 17 18 import org.apache.hadoop.mapreduce.lib.map.InverseMapper; 19 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 20 import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat; 21 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; 22 23 public class WordCount { 24 25 // 自定义Mapper静态内部Class 继承父类 Mapper类,进一步实现map过程 26 public static class TokenizerMapper extends 27 Mapper<Object, Text, Text, IntWritable> { 28 public void map(Object key, Text value, Context context) 29 throws IOException, InterruptedException { 30 System.out.println(key); 31 // Key 32 Text keyOut; 33 // 定义整数1, 每个单词计数一次 34 IntWritable valueOut = new IntWritable(1); 35 36 // 构造一个用来解析输入value值的StringTokenizer对象 37 StringTokenizer token = new StringTokenizer(value.toString()); 38 while (token.hasMoreTokens()) { 39 // 返回从当前位置到下一个分割符的字符串 40 keyOut = new Text(token.nextToken()); 41 // map过程输出键值对:输出每个被拆分出来的单词,以及计数1 42 context.write(keyOut, valueOut); 43 } 44 } 45 } 46 47 // 自定义Reducer Class 继承父类 Reducer类,进一步实现reduce过程 48 public static class IntSumReducer extends 49 Reducer<Text, IntWritable, Text, IntWritable> { 50 private IntWritable result = new IntWritable(); 51 52 public void reduce(Text key, Iterable<IntWritable> values, 53 Context context) throws IOException, InterruptedException { 54 int sum = 0; 55 for (IntWritable val : values) { 56 sum += val.get(); 57 } 58 result.set(sum); 59 context.write(key, result); 60 } 61 } 62 63 // 自定义实现降序 64 // Hadoop默认对IntWritable按升序排序,重写IntWritable.Comparator类实现降序 65 private static class IntWritableDecreaseingComparator extends IntWritable.Comparator { 66 @Override 67 public int compare(WritableComparable a, WritableComparable b) { 68 return -super.compare(a, b);// 比较结果取负数即可降序 69 } 70 @Override 71 public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { 72 return -super.compare(b1, s1, l1, b2, s2, l2); 73 } 74 } 75 76 // 入口 77 public static void main(String[] args) throws Exception { 78 // 任何作用的配置信息必须通过Configuration传递,通过Configuration可以实现在多个mapper和多个reducer任务之间共享信息 79 Configuration conf = new Configuration(); 80 81 // 定义一个临时目录:hdfs://localhost:9000/wordcount1 是hdfs上不存在的目录(hdfs://localhost:9000/肯定存在) 82 // 自定义一个临时目录,如果目录存在请先删除目录后,再运行 83 Path tempDir = new Path("hdfs://localhost:9000/wordcount1"); 84 85 try { 86 // 创建作业 job 87 Job job = Job.getInstance(conf, "word count "); 88 89 // 通过传入的WordCount类Class 设置job的jar包 90 job.setJarByClass(WordCount.class); 91 92 // 设置Mapper类Class 93 job.setMapperClass(TokenizerMapper.class); 94 // 设置Combine类Class 95 job.setCombinerClass(IntSumReducer.class); 96 // 设置Reducer类Class 97 job.setReducerClass(IntSumReducer.class); 98 99 // 自定义分区 100 job.setNumReduceTasks(2); 101 102 // 指定输出类型 103 job.setOutputKeyClass(Text.class);// 设置输出Key类Class 104 job.setOutputValueClass(IntWritable.class);// 设置输出Value类Class 105 106 // 指定统计作业输出格式,和排序作业的输入格式应对应 107 job.setOutputFormatClass(SequenceFileOutputFormat.class); 108 109 // 指定待统计文件目录 110 FileInputFormat.addInputPath(job, new Path("hdfs://localhost:9000/words")); 111 112 // 先将词频统计作业的输出结果写到临时目录中,下一个排序作业以临时目录为输入目录 113 FileOutputFormat.setOutputPath(job, tempDir); 114 115 // 提交job 116 // waitForCompletion提交作业后,每秒会轮询作业进度,如果发现和上次报告后有改变,就把进度报告到控制台, 117 // 作业完成后,如果成功就显示作业计数 118 boolean result = job.waitForCompletion(true); 119 if (result) { 120 // 创建作业 sortJob 121 Job sortJob = Job.getInstance(conf, "sort"); 122 sortJob.setJarByClass(WordCount.class); 123 124 // 指定临时目录作为排序作业的输入 125 FileInputFormat.addInputPath(sortJob, tempDir); 126 127 // Hadoop 默认的是TextInputFormat和TextOutputFormat,此处可以显示地配置 128 sortJob.setInputFormatClass(SequenceFileInputFormat.class); 129 130 // 由Hadoop库提供,作用是实现map()后的数据对key和value交换 131 sortJob.setMapperClass(InverseMapper.class); 132 133 // 将Reducer的个数限定为1,最终输出的结果文件就是一个 134 sortJob.setNumReduceTasks(1); 135 136 // 最终输出目录,如果目录存在请先删除目录后,再运行 137 FileOutputFormat.setOutputPath(sortJob, new Path("hdfs://localhost:9000/wordcount2")); 138 139 // 设置输出Key类Class 140 sortJob.setOutputKeyClass(IntWritable.class); 141 // 设置输出Value类Class 142 sortJob.setOutputValueClass(Text.class); 143 // 一般情况下,mapper和reducer输出的数据类型是一样的,所以可以用上面两条命令; 144 // 如果不一样,可以用下面两条命令单独指定mapper输出的key、value数据类型 145 // job.setMapOutputKeyClass(Text.class); 146 // job.setMapOutputValueClass(IntWritable.class); 147 148 sortJob.setOutputFormatClass(TextOutputFormat.class); 149 // Hadoop 默认的是TextInputFormat和TextOutputFormat,此处可以显示地配置 150 // job.setInputFormatClass(TextInputFormat.class); 151 // job.setOutputFormatClass(TextOutputFormat.class); 152 153 // Hadoop默认对IntWritable按升序排序,重写IntWritable.Comparator类实现降序 154 sortJob.setSortComparatorClass(IntWritableDecreaseingComparator.class); 155 156 // 提交sortJob 157 // waitForCompletion提交作业后,每秒会轮询作业进度,如果发现和上次报告后有改变,就把进度报告到控制台, 158 // 作业完成后,如果成功就显示作业计数 159 boolean result2 = sortJob.waitForCompletion(true); 160 if (result2) { 161 System.out.println("***********ok************"); 162 } 163 } 164 } catch (Exception ex) { 165 ex.printStackTrace(); 166 } 167 } 168 } 169 170 // 查看指定路径文件 171 // hadoop fs -ls hdfs://localhost:9000/ 172 // 返回结果,如下: 173 //Found 5 items 174 //-rw-r--r-- 3 jiangshan supergroup 573545760 2021-09-08 15:48 hdfs://localhost:9000/SBSNTEST111.txt 175 //-rw-r--r-- 3 jiangshan supergroup 28 2021-09-08 16:01 hdfs://localhost:9000/testcreate 176 //drwxr-xr-x - jiangshan supergroup 0 2021-09-08 19:39 hdfs://localhost:9000/wordcount1 177 //drwxr-xr-x - jiangshan supergroup 0 2021-09-08 19:39 hdfs://localhost:9000/wordcount2 178 //-rw-r--r-- 3 jiangshan supergroup 163254798 2021-09-08 16:56 hdfs://localhost:9000/words 179 180 // 查看指定路径文件 181 // hadoop fs -ls hdfs://localhost:9000/wordcount1 182 // 返回结果,如下: 183 //Found 3 items 184 //-rw-r--r-- 3 jiangshan supergroup 0 2021-09-08 19:54 hdfs://localhost:9000/wordcount1/_SUCCESS 185 //-rw-r--r-- 3 jiangshan supergroup 27888 2021-09-08 19:54 hdfs://localhost:9000/wordcount1/part-r-00000 186 //-rw-r--r-- 3 jiangshan supergroup 27364 2021-09-08 19:54 hdfs://localhost:9000/wordcount1/part-r-00001 187 188 // 查看指定路径文件 189 // hadoop fs -ls hdfs://localhost:9000/wordcount2 190 // 返回结果,如下: 191 //Found 2 items 192 //-rw-r--r-- 3 jiangshan supergroup 0 2021-09-08 19:54 hdfs://localhost:9000/wordcount2/_SUCCESS 193 //-rw-r--r-- 3 jiangshan supergroup 36850 2021-09-08 19:54 hdfs://localhost:9000/wordcount2/part-r-00000 194 195 // 将路径指定文件的内容输出到stdout 196 // hadoop fs -cat hdfs://localhost:9000/testcreate 197 // 返回结果,文本文件内容 198 // Hello Hadoop 888@Chinasofti