工具:IDEA
在一切开始之前,我们先要确定我们的hadoop环境是否正常,hdfs文件系统是否正常。
如何验证呢?首先,把集群启动,正常显示界面:
进入文件系统:
此时需要创建一个文件夹用于存放一会会用到的文件,我这里取名为input
在hdfs系统创建文件夹有两个方法,其中一个是直接敲命令:hadoop fs -mkdir /input
第二个是在界面上创建:
不管用哪种方式,保证有这么一个文件夹就行了。
然后,创建一个txt文件,随便写几个单词进去,单词之间用空格分开(路径自己选,只要找得到就行):
把刚才创建的这个txt文件放进hdfs文件系统的/input这个文件夹:
hadoop fs -put /root/word.txt /input
验证一下有了没:
进入hadoop的家目录,进一步进入/share/hadoop/mapreduce
里面有个官方的examples给我们做实验。
使用命令:hadoop jar hadoop-mapreduce-examples-3.3.0.jar wordcount /input /output1
(output1是输出文件夹,名字可以自己取)hadoop jar jar包的名字 主类 输入路径 输出路径
如果显示这个:
那么恭喜你,你的环境没有问题,可以走下一步了。如果不成功,那很遗憾,你的hadoop文件系统有问题,可能需要重装或者初始化……
运行完后会多出一个文件夹:
用cat命令查看一下里面的part-r-00000,如果正常显示结果,那就没问题了。
接下来就是用IDEA建项目了。
一、 用IDEA新建一个Maven项目,我的项目名叫words_count
二、 导入hadoop相关jar包,具体要导(以下路径相对于自己的hadoop文件夹而言):
share/hadoop/client下的全部:
share/hadoop/common下的全部:
share/hadoop/common/lib下的全部:
以下路径的全部(注意里面还包含有子文件夹lib,lib里的也要导):
如果不知道怎么导入jar包:
三、 建一个class名为MyMap(可自己取)
内容如下:
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class MyMap extends Mapper<LongWritable, Text, Text, IntWritable> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException,InterruptedException{
String line = value.toString();
String[] words = line.split(" ");
for (String word:words){
context.write(new Text(word),new IntWritable(1));//key value
}
}
}
四、 建一个class名为MyReduce
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class MyReduce extends Reducer<Text, IntWritable, Text ,IntWritable> {
/*
* reduce方法提供给reduce task进程来调用
*
* reduce task会将shuffle阶段分发过来的大量kv数据对进行聚合,聚合的机制是相同key的kv对聚合为一组
* 然后reduce task对每一组聚合kv调用一次我们自定义的reduce方法
* 比如:<hello,1><hello,1><hello,1><tom,1><tom,1><tom,1>
* hello组会调用一次reduce方法进行处理,tom组也会调用一次reduce方法进行处理
* 调用时传递的参数:
* key:一组kv中的key
* values:一组kv中所有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();//这里写成count++应该也没什么毛病,毕竟value的值全都是1
}
//输出这个单词的统计结果
context.write(key,new IntWritable(count));
}
}
五、 建主类WordCountDriver
import org.apache.hadoop.conf.Configuration;
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;
import java.io.IOException;
public class WordCountDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Configuration conf = new Configuration();
Job wordCountJob = Job.getInstance(conf);
wordCountJob.setJarByClass(WordCountDriver.class);
wordCountJob.setMapperClass(MyMap.class);
wordCountJob.setReducerClass(MyReduce.class);
wordCountJob.setMapOutputKeyClass(Text.class);
wordCountJob.setMapOutputValueClass(IntWritable.class);
wordCountJob.setOutputKeyClass(Text.class);
wordCountJob.setMapOutputValueClass(IntWritable.class);
FileInputFormat.setInputPaths(wordCountJob, args[0]);
FileOutputFormat.setOutputPath(wordCountJob, new Path(args[1]));
wordCountJob.waitForCompletion(true);
}
}
六、 跑一下,会报错,正常,不管。
七、 把该项目打成jar包
在打jar包之前,可以把第(二)步中的那些外部依赖删掉再打,这样会快一点。因为我们一开始导入那些hadoop外部依赖的目的只是为了能让编译器通过,现在编译器已经通过了,而我们的虚拟机上本来就有hadoop环境,那些hadoop外部依赖已经不再需要。当然不删也行,只是慢一点而且有点费资源。
设置如下,勾勾打上
点OK,返回IDEA主页面
去到刚才设置的输出路径,就能找到生成的jar包了。
其中只有一个我们要用来运行的jar包,其他的都是陪嫁的环境jar包。为了方便,建议把这一大堆jar包放进一个文件夹里。
八、 把这个生成的含有好多jar包的文件夹传输到自己的hadoop主机上。
九、 在hadoop主机上进入该文件夹
执行命令:Hadoop jar jar包名字 输入路径 输出路径
其中,输入路径和输出路径是相对于hdfs文件系统而言的。
hadoop jar words_count.jar /input /output
执行完毕,查看输出目录下生成了两个新文件:hadoop fs -ls /output
查看那个part-r-00000,就可以看到结果了:hadoop fs -cat /output/part-r-00000
成功啦。
—————可能会遇到的问题—————
解决:把原来已经生成的文件夹删掉