配置HADOOP开发环境
考慮到Windows平臺盡管界面友好,但Hadoop環境配置較"怪異",需借助cygwin,這個過程并不優雅。正好我手上另有一套ubuntu環境,用著也很順手,就在ubuntu中安裝了Eclipse?IDE,在這套環境中配置安裝Hadoop開發環境。
在本地搭建HADOOP開發環境時,三思也在網上參考了很多文章,還是很有感觸,一個是果然天下文章一大抄(好吧我也沒少抄,先抄官方文檔,抄完改名叫筆記,本該汗顏的事兒被俺說的這么義正嚴詞,是否當場就震斷了你們堅強無比的氪合金神經,沒錯我最近在看厚黑學來著,可惜Eclipse配置HADOOP開發環境沒有官方文檔描述,否則我應該能(抄)寫的更嚴謹一些),很多文章的內容看起來都顯得近似,近似也就罷了,只要能有幫助就好,但遺憾不少文章過程描述的并不清晰,抄來抄去更顯得糊里糊涂,咱不能說這些文章完全沒有幫助,不過確實讀的出來,很多人都是一知半解的寫(或抄),我當然也好不到哪去,不過我比較耿直,我直接將這點明說了出來,省得大家瞎惦記,盡管水平很有限,不過我保證將盡最大努力,將整個配置過程清晰地展現出來。做為參考文檔,不管操作者處在什么水平,按照我這個步驟都能將環境配置起來。
另一個是目前我在網上找到的文章,多都是在本地安裝一套Local模式或Pseudo-distributed?模式的?HADOOP環境,并在此基礎上配置Eclipse進行開發。我這里因為是先配置好一套HADOOP測試環境(配置過程參考:[三思筆記]Hadoop安裝手冊),不想重復性地在Eclipse本地再安裝一套HADOOP,因此我希望我的Eclipse能夠直接連接遠程的HADOOP,并基于該套環境進行調試。
1、初始化環境
設定環境如下:
- HADOOP:0.20.2?
- Namenode:hdnode1?-?192.168.30.203?
- Datanode:hdnode{2-5}?-?192.168.30.204-207?
- Developer:ubuntu?-?192.168.10.200?+?eclipse?4.2?juno
從namenode或datanode節點中,復制HADOOP軟件包到Developer環境,因為在代碼開發過程中,需要HADOOP軟件包的支持。
提示:
1、Eclipse可以直接到官網免費下載:www.eclipse.org/downloads
2、建議ubuntu下創建grid用戶,并在grid用戶中配置Eclipse開發環境,可以避免(或者說減少)連接HADOOP時用戶權限等導致的異常。
3、Developer環境的HADOOP并不需額外進行配置,更完全沒有必要將其加入到現有HADOOP環境中;
下載好Eclipse壓縮包,我們要下載的是Eclipse?IDE?for?Java?EE?Developers工具包,下載頁面能夠自動識別操作系統并給出建議的下載地址(Windows平臺會給出windows版本的下載地址,linux平臺則提供linux版本下載),一般用戶只需要選擇32位還是64位即可。
我這里下載的64位linux版本,以grid用戶登錄,將文件解壓縮到適當目錄下:
#?su?-?grid?
$?tar?xvfc?eclipse-jee-juno-SR1-linux-gtk-x86_64.tar.gz?-C?/data/developer/
在當前HADOOP環境中的任意一個節點上,打開hadoop主目錄,找到contrib/eclipse-plugin/hadoop-0.20.2-eclipse-plugin.jar文件,將該文件復制至Eclipse程序目錄的plugins目錄內。
返回到Ubuntu視窗界面,雙擊eclipse程序主目錄下的eclipse,進入Eclipse界面:
2、配置Eclipse開發環境
第一次進入Eclipse會提示你選擇一個工作區,這個路徑下將會做為工程文件的默認保存路徑(保存或創建工程時也可以另外自定義,并且后期也可以進行修改),這里三思將其定義到/data/developer/workspace目錄下。
點擊菜單:Window?->?Open?Perspective?->?Other,選中"Map/Reduce",打開MapReduce視圖:
在右下窗口中能夠找到"Map/Reduce?Locations",正如名稱所代表的,此處用來配置路徑:
在小窗口的空白位置點擊鼠標右鍵,選中"New?Hadoop?Location",彈出窗口如下:
在這里需要用戶指定下列配置:
- Location?name:為配置的路徑指定一個名稱,名稱可以自定義,這里三思將之定義為JSSHadoop;?
- Map/Reduce?Master:根據hadoop環境中namenode節點conf/mapred-site.xml?文件中的配置而定,指定為mapred.job.tracker參數的值;?
- DFS?Master:根據hadoop環境中namenode節點conf/core-site.xml文件中的配置而定,指定為fs.default.name的值;?
- User?name:指定操作用戶,一般默認此處顯示為操作系統用戶名;
配置好后點擊Finish。而后在左側的窗口中就會看到DFS?Locations處多了我們剛剛配置的JSSHadoop:
通過層次點開,就能看到我們在HDFS中保存的目錄和文件了(如果沒有出現,就右鍵Refresh刷新):
通過這個區域,我們就可以讀寫HDFS文件系統中的目錄和文件了。
不過若要調試HADOOP程序,還需要配置參數,指定Hadoop的軟件安裝路徑,注意本步只是要指定Hadoop軟件的路徑,并不是要配置HADOOP環境,只需要下載(或復制)一份hadoop文件即可,在Hadoop?Map/Reduce參數中指定適當的目錄:
至此環境就配置好了,接下來可以創建Map/Reduce項目,進行開發測試。
3、創建項目
點擊菜單:File?->?New?->?Project,在彈出的頁面中選擇Map/Reduce?Project:
選中后彈出頁面如下:
本頁需要用戶指定的內容如下:
- Project?name:指定一個項目名稱,完全自定義;?
- Location:指定項目的存儲路徑,也可以自定義,默認則是保存在啟動Eclipse時指定的工作區文件夾內;?
- MapReduce庫文件安裝路徑:就是HADOOP安裝路徑,使用默認即可;
項目創建后,Eclipse會把相關jar包自動導入。然后我們就可以在這個項目下編寫程序,調試HADOOP了。
4、代碼開發和調試示例
前面部署HADOOP時曾經測試過wordcount程序,這樣我們在Eclipse也調試這一功能。HADOOP提供了這些示例的源代碼,大家可以在HADOOP安裝文件根路徑下的examples目錄下,比如WordCount位于:examples/org/apache/hadoop/examples/WordCount.java
我們新建一個java文件,右鍵選中項目名稱,點擊New?->?Class創建一個新的Java?Class文件,彈出窗口如下:
將示例代碼直接復制進來,而后修改文件頭部包名即可。新創建的WordCount.java文件內容如下:
package?com.jss.hadoop.mapreduce.test;
import?java.io.IOException;
import?java.util.StringTokenizer;
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?org.apache.hadoop.util.GenericOptionsParser;
public?class?WordCount?{
??public?static?class?TokenizerMapper?
???????extends?Mapper<Object,?Text,?Text,?IntWritable>{
????
????private?final?static?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())?{
????????word.set(itr.nextToken());
????????context.write(word,?one);
??????}
????}
??}
??
??public?static?class?IntSumReducer?
???????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;
??????for?(IntWritable?val?:?values)?{
????????sum?+=?val.get();
??????}
??????result.set(sum);
??????context.write(key,?result);
????}
??}
??public?static?void?main(String[]?args)?throws?Exception?{
????Configuration?conf?=?new?Configuration();
????String[]?otherArgs?=?new?GenericOptionsParser(conf,?args).getRemainingArgs();
????if?(otherArgs.length?!=?2)?{
??????System.err.println("Usage:?wordcount?<in>?<out>");
??????System.exit(2);
????}
????Job?job?=?new?Job(conf,?"word?count");
????job.setJarByClass(WordCount.class);
????job.setMapperClass(TokenizerMapper.class);
????job.setCombinerClass(IntSumReducer.class);
????job.setReducerClass(IntSumReducer.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);
??}
}
WordCount如要運行,需要指定兩個參數,即代碼中65行和66行所需指定的路徑。針對這種情況,我們即可以改動代碼,直接在此處寫好目標路徑(同時還需要將53-57行之間的代碼注釋)而后即可直接運行調試;也可以配置WordCount的調試運行環境,為其配置運行參數。這里我們選擇后一種方式。
選擇菜單:Run?->?Run?Configurations?->?Java?Application,點擊窗口左上角處的圖標:
新建一個配置,將彈出的窗口顯示項切換到Arguments選項:
此處需要我們填寫Program?arguments,即指定程序運行所需參數,根據程序設定,此時需要指定兩個參數,一個指定要處理的文件源路徑,另一個是處理后文件的輸出路徑,中間以空格分隔。請根據實際情況指定參數,配置好后,即可點擊Run運行。
如果配置正確,執行成功后,在HDFS中就會創建jssout文件夾,如上圖所示,其中保存的文件,就是對源路徑中數據處理后的輸出結果。
若要操作HDFS中的目錄和文件也是同理,繼續創建文件(過程不演示)FileOper.java,代碼如下:
$?more?/data/developer/workspace/FirstHadoopProject/src/com/jss/hadoop/hdfs/test/FileOper.java?
package?com.jss.hadoop.hdfs.test;
import?java.io.IOException;
import?org.apache.hadoop.conf.Configuration;
import?org.apache.hadoop.fs.FSDataOutputStream;
import?org.apache.hadoop.fs.FSDataInputStream;
import?org.apache.hadoop.fs.FileStatus;
import?org.apache.hadoop.fs.FileSystem;
import?org.apache.hadoop.fs.Path;
public?class?FileOper?{
????????public?static?void?main(String[]?args)?throws?Exception?{
????????????????if?(args.length?<?1)?{
????????????????????????System.out.println("Must?define?parameters!");
????????????????}?else?{
????????????????????????Configuration?conf?=?new?Configuration();
????????????????????????conf.set("fs.default.name",?args[0]);
????????????????????????FileOper.listHDFSFiles(conf);?//?顯示目錄結構
????????????????????????//FileOper.uploadLocal2HDFS(conf,?args[1],?args[2]);?//?上傳文件
????????????????????????//FileOper.createHDFSFile(conf,?args[1],?args[2]);?//?創建文件
????????????????????????//FileOper.deleteHDFSFile(conf,?args[1]);?//?刪除文件
????????????????????????//FileOper.readHDFSFile(conf,?args[1]);?//?讀取文件
????????????????????????//FileOper.makeHDFSDirectory(conf,?args[1]);?//?創建目錄
????????????????????????//FileOper.removeHDFSDirectory(conf,?args[1]);?//?刪除目錄
????????????????}
????????}
????????public?static?void?listHDFSFiles(Configuration?conf)?throws?IOException?{
????????????????FileSystem?fs?=?FileSystem.get(conf);
????????????????FileStatus?files[]?=?fs.listStatus(new?Path("/"));
????????????????for?(FileStatus?file?:?files)?{
????????????????????????System.out.println(file.getPath());
????????????????}
????????}
????????public?static?void?uploadLocal2HDFS(Configuration?conf,?String?s,?String?d)
????????????????????????throws?IOException?{
????????????????FileSystem?fs?=?FileSystem.get(conf);
????????????????Path?src?=?new?Path(s);
????????????????Path?dst?=?new?Path(d);
????????????????fs.copyFromLocalFile(src,?dst);
????????????????fs.close();
????????????????System.out.println("Upload?to?"?+?conf.get("fs.default.name"));
????????}
????????public?static?void?createHDFSFile(Configuration?conf,?String?createFilePath,
????????????????????????String?content)?throws?IOException?{
????????????????FileSystem?fs?=?FileSystem.get(conf);
????????????????FSDataOutputStream?fsos?=?fs.create(new?Path(createFilePath));
????????????????fsos.write(content.getBytes("UTF-8"));
????????????????fsos.close();
????????????????fs.close();
????????????????System.out.println("Succeeded?created?file?"?+?createFilePath);
????????}
????????public?static?boolean?deleteHDFSFile(Configuration?conf,?String?dst)
????????????????????????throws?IOException?{
????????????????FileSystem?fs?=?FileSystem.get(conf);
????????????????Path?path?=?new?Path(dst);
????????????????boolean?isDeleted?=?fs.delete(path,?true);
????????????????fs.close();
????????????????return?isDeleted;
????????}
????????public?static?byte[]?readHDFSFile(Configuration?conf,?String?dst)
????????????????????????throws?Exception?{
????????????????FileSystem?fs?=?FileSystem.get(conf);
????????????????Path?path?=?new?Path(dst);
????????????????if?(fs.exists(path))?{
????????????????????????FSDataInputStream?is?=?fs.open(path);
????????????????????????//?get?the?file?info?to?create?the?buffer
????????????????????????FileStatus?stat?=?fs.getFileStatus(path);
????????????????????????//?create?the?buffer
????????????????????????byte[]?buffer?=?new?byte[Integer.parseInt(String.valueOf(stat
????????????????????????????????????????.getLen()))];
????????????????????????is.readFully(0,?buffer);
????????????????????????is.close();
????????????????????????fs.close();
????????????????????????return?buffer;
????????????????}?else?{
????????????????????????throw?new?Exception("the?file?is?not?found?.");
????????????????}
????????}
????????public?static?void?makeHDFSDirectory(Configuration?conf,?String?dst)
????????????????????????throws?IOException?{
????????????????FileSystem?fs?=?FileSystem.get(conf);
????????????????fs.mkdirs(new?Path(dst));
????????????????fs.close();
????????????????System.out.println("Succeeded?created?directory?"?+?dst);
????????}
????????public?static?void?removeHDFSDirectory(Configuration?conf,?String?dst)
????????????????????????throws?IOException?{
????????????????FileSystem?fs?=?FileSystem.get(conf);
????????????????fs.delete(new?Path(dst),?true);
????????????????fs.close();
????????????????System.out.println("Succeeded?remove?directory?"?+?dst);
????????}
}
FileOper能夠讀取HDFS中的文件目錄結構,操作文件和目錄。程序在執行時,同樣需要指定參數,具體步驟與前面操作WordCount的原理相同,就不一一演示了。
5、配置javadoc
IDE工具之所以易用,就是輔助功能做的好。在開發代碼時,能夠減化操作,或者提供幫助。比如javadoc功能,方便我們快速查詢方法相關描述、示例等幫助信息,那么對于新引入的HADOOP相關包有沒有javadoc支持呢?回答是肯定的,HADOOP軟件包中就帶有這些內容,位于HADOOP軟件根路徑的docs目錄下。
若要啟用hadoop相關包體中各方法的幫助,也可以通過配置實現。右鍵點擊工程中hadoop-0.20.2-core.jar文件,選擇Properties,彈出界面如下,我們選擇Javadoc?Location進行配置:
需要我們在此處指定Javadoc文件的路徑,正如前面所說,HADOOP軟件包中自帶幫助文檔,直接指定到該路徑下,而后點擊OK確認。隨后在開發hdfs/mapreduce代碼時,指定方法名就會自動在一旁顯示出該方法的幫助信息。
總結
以上是生活随笔為你收集整理的配置HADOOP开发环境的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hadoop DFS源码研究之---Ha
- 下一篇: 处理报错:java/lang/NoCla