標籤:
問題描述:
在hadoop中處理多個檔案,其中每個檔案一個map。
我使用的方法為產生一個檔案,檔案中包含所有要壓縮的檔案在HDFS上的完整路徑。每個map 任務獲得一個路徑名作為輸入。
在eclipse中調試時,map中處理hdfs上的檔案用到的FileSystem對象為整個class中的靜態成員變數,在eclipse中運行沒有錯誤,打包成jar提交到叢集運行,就會在map函數中
FileStatus fileStatus = tmpfs.getFileStatus(inputdir);
這一句報錯 java.lang.NullPointerException 卡了2天,不知到是哪錯了。
昨天下午才想到應
該
是
tmpfs是一個Null 物件,沒有賦值。
雖然tmpfs 在最外層的類中聲明為靜態變數,並且在main函數中有賦值,然而在map函數內還是NullPointer。
之後改為在map函數內部給
tmpfs賦值就解決了問題。
這也驗證了eclipse中調試運行程式是在本地運行,只不過是調用了hadoop的類庫,在8088連接埠的監控網頁上也看不到提交應用的資訊。
必須打包成jar,用bin/hadoop jar運行才能真正提交到叢集運行。而且main函數內部初始化的靜態變數,在map中還是未初始化狀態,猜測是叢集上啟動並執行map任務,和本地的main函數是互相獨立的關係。
改正後的代碼:
1 @Override 2 public void map(Object key, Text value, 3 Context context) 4 throws 5 IOException, InterruptedException { 6 Configuration conf = context. getConfiguration(); 7 FileSystem tmpfs = FileSystem.get(URI.create("hdfs://192.168.2.2:9000"), conf); 8 9 Path inputdir = new Path(value.toString()); //擷取待處理的檔案的Path對象10 FileStatus fileStatus = tmpfs.getFileStatus(inputdir);11 12 //做相應處理13 14 context.write(new Text(value.toString()), new Text(" "));15 }
Configuration conf = context. getConfiguration();//通過context擷取job中配置的Configuration對象
FileSystem tmpfs = FileSystem.get(URI.create("hdfs://192.168.2.2:9000"), conf); //需要在map函數內部賦值
附錄:
如何處理多個檔案,其中每個檔案一個map?
例如這樣一個問題,在叢集上壓縮(zipping)一些檔案,你可以使用以下幾種方法:
- 使用Hadoop Streaming和使用者編寫的mapper指令碼程式:
- 產生一個檔案,檔案中包含所有要壓縮的檔案在HDFS上的完整路徑。每個map 任務獲得一個路徑名作為輸入。
- 建立一個mapper指令碼程式,實現如下功能:獲得檔案名稱,把該檔案拷貝到本地,壓縮該檔案並把它發到期望的輸出目錄。
- 使用現有的Hadoop架構:
- 在main函數中添加如下命令:
FileOutputFormat.setCompressOutput(conf, true); FileOutputFormat.setOutputCompressorClass(conf, org.apache.hadoop.io.compress.GzipCodec.class); conf.setOutputFormat(NonSplitableTextInputFormat.class); conf.setNumReduceTasks(0);
- 編寫map函數:
public void map(WritableComparable key, Writable value, OutputCollector output, Reporter reporter) throws IOException { output.collect((Text)value, null); }
- 注意輸出的檔案名稱和原檔案名稱不同
[hadoop] map函數中使用FileSystem對象出現java.lang.NullPointerException的原因及解決辦法