以前都是在idea裏面寫好了hadoop程序,然後打成jar包,然後在服務器上通過jar 命令進行MR 程序的執行,這樣的方式不利於調試,下面給出在idea上進行遠程調試hadoop的方法。
平臺
hadoop:2.6.5
OS : OSX
IDE : IDEA
注意細節
不能用maven導包,否則會報如下錯誤:
ERROR security.UserGroupInformation: PriviledgedActionException as:root cause:org.apache.hadoop.ipc.RemoteException:
Server IPC version 9 cannot communicate with client version 4
發現是由於hadoop-core這個包的原因導致的,但是其最高支持1.2.1 筆者沒有找到解決方法。所以想在本地進行調試,只能乖乖的手動導包。
hadoop在IDEA上遠程調試的步驟
1. 導如hadoop所需要的包
這一步簡單的帶過吧,需要導的是common, hdfs, yarn, mapreduce 四個目錄下的lib下的所有包和其目錄下非example的包(多導入沒毛病,)
額,這幾個文件夾在hadoop/share/hadoop/下
2. 更改language level
更改用下圖表示,,很直觀
1.
2.
3.設置app 運行的參數
1. 點擊Edit Configuration->傳建一個application
2. 在右邊的program argument 中輸入服務器上HDFS的輸入路徑和程序的輸出路徑(如果程序中制定了輸入輸出路徑,這裏可以不用設置)
3. 和project directory中輸入:hadoop的路徑(這個hadoop可以從服務器上download一份下來,隨便你放在本地什麼地方)
任然上圖,可以參考一下我的設置
4. 由於每一次執行後,輸出路徑不會自動的刪除,如果我們的輸出路徑不修改,那麼程序會報輸出文件已存在的錯誤,如下:
Exception in thread "main" org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://master1:9000/flow/output already exists
解決方法:
1. 去服務器上吧output paht 給手動刪除了
2.寫代碼
個人喜歡第二種,既然用本地遠程調試了,還跑去服務器上一次一次的刪,太麻煩了。下面給出刪除的代碼,其實就是HDFS的操作:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
/**
* Created by macan on 2017/1/14.
*/
public class HdfsConnection {
private FileSystem fs = null;
public HdfsConnection() throws URISyntaxException, IOException, InterruptedException {
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://master1:9000");
fs = FileSystem.get(new URI("hdfs://master1:9000"), conf, "root");
}
/**
* 刪除HDFS 中指定的目錄
* @param path 需要刪除的目錄
* @param is 是否進行遞歸刪除文件
* @throws IOException
*/
public boolean delete(String path, boolean is) throws IOException {
boolean res = true;
if (exits(path)) {
res = fs.delete(new Path(path), is);
fs.close();
}
return res;
}
/**
* 查看文件是否存在
* @param path 文件路徑
* @return 如果文件存在,返回true,否則返回false
* @throws IOException
*/
public boolean exits(String path) throws IOException {
boolean res = fs.exists(new Path(path));
return res;
}
}
在MR的主程序中調用示例:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
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;
import java.net.URISyntaxException;
/**
* Created by macan on 2017/1/14.
*/
public class FlowCountWithPartitioner {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {
if (args.length < 2){
System.out.println("please input 2 args, one is input path and second is output path");
System.exit(-1);
}
//刪除hdfs上的output 路徑
HdfsConnection hdfs = new HdfsConnection();
hdfs.delete(args[1], true);
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//指定本程序jar包所在的目錄
job.setJarByClass(FlowCountWithPartitioner.class);
//指定本業務的job要使用的mapper/reduce 的業務類
job.setMapperClass(FlowCountMapper.class);
job.setReducerClass(FlowCountReduce.class);
//指定自定義的Partiotioner
job.setPartitionerClass(ProvincePartitioner.class);
//指定相應數量的reducetask,num: 相應的數據分區數量
job.setNumReduceTasks(5);
//指定mapper的輸出數據類型kv
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(FlowBean.class);
//指定最終輸出的數據類型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(FlowBean.class);
//指定job輸出原始文件所在的目錄
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
//將job中設置的相關參數,以及所用的Java類所在的jar包,提交任務給yarn
// job.submit();
//true表示將集羣中運行的結果打印出來
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
重點在22,23 行
總結
Windows上的沒有使用過,改天試一下更新博客(可以看參考),如果有錯誤,請指教