介紹怎樣在Intellij Idea中通過創建mavenproject配置MapReduce的編程環境。
一、軟件環境
我使用的軟件版本號例如以下:
- Intellij Idea 2017.1
- Maven 3.3.9
- Hadoop偽分布式環境( 安裝教程可參考這里)
二、創建mavenproject
打開Idea,file->new->Project,左側面板選擇mavenproject。(假設僅僅跑MapReduce創建javaproject就可以,不用勾選Creat from archetype,假設想創建webproject或者使用骨架能夠勾選)
設置GroupId和ArtifactId。下一步。
設置project存儲路徑。下一步。
Finish之后,空白project的路徑例如以下圖所看到的。

完整的project路徑例如以下圖所看到的:

三、加入maven依賴
在pom.xml加入依賴。對於hadoop 2.7.3版本號的hadoop,須要的jar包有下面幾個:
- hadoop-common
- hadoop-hdfs
- hadoop-mapreduce-client-core
- hadoop-mapreduce-client-jobclient
log4j( 打印日志)
pom.xml中的依賴例如以下:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-jobclient</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
四、配置log4j
在src/main/resources目錄下新增log4j的配置文件log4j.properties。內容例如以下:
log4j.rootLogger = debug,stdout
### 輸出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
五、啟動Hadoop
啟動Hadoop,執行命令:
cd hadoop-2.7.3/
./sbin/start-all.sh
訪問http://localhost:50070/查看hadoop是否正常啟動。
六、執行WordCount(從本地讀取文件)
在project根目錄下新建input目錄,input目錄下新增dream.txt,隨便寫入一些單詞:
I have a dream
a dream
在src/main/java目錄下新建包。新增FileUtil.java,創建一個刪除output文件的函數,以后就不用手動刪除了。內容例如以下:
package com.mrtest.hadoop;
import java.io.File;
/** * Created by bee on 3/25/17. */
public class FileUtil {
public static boolean deleteDir(String path) {
File dir = new File(path);
if (dir.exists()) {
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
deleteDir(f.getName());
} else {
f.delete();
}
}
dir.delete();
return true;
} else {
System.out.println("文件(夾)不存在!");
return false;
}
}
}
編寫WordCount的MapReduce程序WordCount.java,內容例如以下:
package com.mrtest.hadoop;
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.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;
/** * Created by bee on 3/25/17. */
public class WordCount {
public static class TokenizerMapper extends
Mapper<Object, Text, Text, IntWritable> {
public static final IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context)
throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
this.word.set(itr.nextToken());
context.write(this.word, one);
}
}
}
public static class IntSumReduce extends
Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,
Context context)
throws IOException, InterruptedException {
int sum = 0;
IntWritable val;
for (Iterator i = values.iterator(); i.hasNext(); sum += val.get()) {
val = (IntWritable) i.next();
}
this.result.set(sum);
context.write(key, this.result);
}
}
public static void main(String[] args)
throws IOException, ClassNotFoundException, InterruptedException {
FileUtil.deleteDir("output");
Configuration conf = new Configuration();
String[] otherArgs = new String[]{"input/dream.txt","output"};
if (otherArgs.length != 2) {
System.err.println("Usage:Merge and duplicate removal <in> <out>");
System.exit(2);
}
Job job = Job.getInstance(conf, "WordCount");
job.setJarByClass(WordCount.class);
job.setMapperClass(WordCount.TokenizerMapper.class);
job.setReducerClass(WordCount.IntSumReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
執行完成以后。會在project根目錄下添加一個output目錄。打開output/part-r-00000,內容例如以下:
I 1
a 2
dream 2
have 1
這里在main函數中新增了一個String類型的數組,假設想用main函數的args數組接受參數。在執行時指定輸入和輸出路徑也是能夠的。執行WordCount之前,配置Configuration並指定Program arguments就可以。

七、執行WordCount(從HDFS讀取文件)
在HDFS上新建目錄:
hadoop fs -mkdir /worddir
假設出現Namenode安全模式導致的不能創建目錄提示:
mkdir: Cannot create directory /worddir. Name node is in safe mode.
執行下面命令關閉safe mode:
hadoop dfsadmin -safemode leave
上傳本地文件:
hadoop fs -put dream.txt /worddir
改動otherArgs參數,指定輸入為文件在HDFS上的路徑:
String[] otherArgs = new String[]{"hdfs://localhost:9000/worddir/dream.txt","output"};
