2012-07-14 54 views
4
  1. 我想從同一個減速寫兩個不同類型的輸出,爲兩個不同的目錄。

我能夠使用hadoop中的多輸出功能寫入不同的文件,但他們都轉到相同的輸出文件夾。寫輸出到不同的文件夾的Hadoop

我想寫從相同的每個文件減小到一個不同的文件夾中。

是否有這樣做的方法嗎?

如果我嘗試把例如「你好/ testfile的」,作爲第二個參數,它顯示invaid說法。所以我不能寫入不同的文件夾。

  1. 如果上述情況是不可能的,那麼映射器是否可以從輸入文件夾中只讀取特定文件?

請幫幫我。

在此先感謝!


感謝您的回覆。我可以使用上述方法成功讀取文件。但在分佈式模式下,我無法這樣做。在減速機,我有 組:

mos.getCollector("data", reporter).collect(new Text(str_key), new Text(str_val));

(使用多個輸出,並且在工作CONF: 我嘗試使用

FileInputFormat.setInputPaths(conf2, "/home/users/mlakshm/opchk285/data-r-00000*");

以及

FileInputFormat.setInputPaths(conf2, "/home/users/mlakshm/opchk285/data*");

但是,它g艾夫斯以下錯誤:

cause:org.apache.hadoop.mapred.InvalidInputException: Input Pattern hdfs://mentat.cluster:54310/home/users/mlakshm/opchk295/data-r-00000* matches 0 files 

回答

1

複製MultipleOutputs代碼到你的代碼庫,並放寬對允許字符的限制。無論如何,我看不出任何有效的限制原因。

+0

您能詳細解答一下答案嗎?你如何複製MultipleOutputs代碼? – 2012-07-14 12:33:08

+0

感謝您的回覆 – 2012-07-14 15:36:58

+0

它的工作!我可以輸出到不同的文件夾... – 2012-07-14 16:03:44

1

是的,你可以指定輸入格式僅處理某些文件:

FileInputFormat.setInputPaths(job, "/path/to/folder/testfile*"); 

如果你修改代碼,記得_SUCCESS文件應寫入成功作業完成後兩個文件夾 - 而這ISN」這是一種機制,通過這種機制,人們可以確定該文件夾中的輸出是否完整,而不是因爲錯誤而被「截斷」。

+0

嗨克里斯感謝您的回覆。我能夠在單一模式下讀取特定文件。但在分佈式模式下,我收到以下錯誤: – 2012-07-14 14:31:55

+0

在reducer中,我已設置:\t \t \t \t mos.getCollector(「data」,reporter).collect(new Text(str_key),new Text(str_val)); (使用多個輸出,並在作業Conf: 我試過使用\t \t FileInputFormat.setInputPaths(conf2,「/ home/users/mlakshm/opchk285/data-r-00000 *」);以及\t \t FileInputFormat.setInputPaths( conf2,「/ home/users/mlakshm/opchk285/data *」);但是,它給出了以下錯誤:原因:org.apache.hadoop.mapred.InvalidInputException:輸入模式hdfs://mentat.cluster:54310/home/users/mlakshm/opchk295/data-r-00000 *匹配0個文件 – 2012-07-14 15:06:52

+0

「hadoop fs -ls/home/users/mlakshm/opchk285」列表是什麼? – 2012-07-14 20:46:44

0

是的,你可以做到這一點。所有你需要做的是爲從reducer中出來的特定鍵/值對生成文件名。

如果覆蓋的方法,你可以根據什麼鍵/值對你,等返回的文件名。這是顯示如何做到這一點的鏈接。

https://www.google.co.in/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CFMQFjAA&url=https%3A%2F%2Fsites.google.com%2Fsite%2Fhadoopandhive%2Fhome%2Fhow-to-write-output-to-multiple-named-files-in-hadoop-using-multipletextoutputformat&ei=y7YBULarN8iIrAf4iPSOBg&usg=AFQjCNHbd8sRwlY1-My2gNYI0yqw4254YQ

2

問題1:編寫文件輸出到不同的目錄 - 你可以用下面的方法做:

1.使用MultipleOutputs類:

它的偉大您可以使用MultipleOutput創建多個命名輸出文件。如您所知,我們需要在您的驅動程序代碼中添加此項。

MultipleOutputs.addNamedOutput(job, "OutputFileName", OutputFormatClass, keyClass, valueClass); 

API提供兩個重載寫入方法來實現這一點。

multipleOutputs.write("OutputFileName", new Text(Key), new Text(Value)); 

現在,寫輸出文件分離輸出目錄,你需要使用一個重載write方法與基本輸出路徑的額外參數。

multipleOutputs.write("OutputFileName", new Text(key), new Text(value), baseOutputPath); 

請記住在您的每個實施中更改您的baseOutputPath。

2.重命名/移動在驅動程序類文件:

這可能是寫輸出到多個目錄中的最簡單的黑客攻擊。使用multipleOutputs並將所有輸出文件寫入單個輸出目錄。但是每個類別的文件名稱需要不同。

假設您想要創建3組不同的輸出文件的,第一步是在驅動程序中註冊一個名爲輸出文件:

MultipleOutputs.addNamedOutput(job, "set1", OutputFormatClass, keyClass, valueClass); 
MultipleOutputs.addNamedOutput(job, "set2", OutputFormatClass, keyClass, valueClass); 
MultipleOutputs.addNamedOutput(job, "set3", OutputFormatClass, keyClass, valueClass); 

此外,創建不同的輸出目錄或你想要的目錄結構在驅動程序代碼,與實際輸出目錄一起:

Path set1Path = new Path("/hdfsRoot/outputs/set1"); 
Path set2Path = new Path("/hdfsRoot/outputs/set2"); 
Path set3Path = new Path("/hdfsRoot/outputs/set3"); 

最後重要的一步就是重新命名根據他們的名字輸出文件。如果工作成功,

FileSystem fileSystem = FileSystem.get(new Configuration); 
if (jobStatus == 0) { 

     // Get the output files from the actual output path 
     FileStatus outputfs[] = fileSystem.listStatus(outputPath); 

     // Iterate over all the files in the output path 
     for (int fileCounter = 0; fileCounter < outputfs.length; fileCounter++) { 

      // Based on each fileName rename the path. 
      if (outputfs[fileCounter].getPath().getName().contains("set1")) { 
       fileSystem.rename(outputfs[fileCounter].getPath(), new Path(set1Path+"/"+anyNewFileName)); 
      } else if (outputfs[fileCounter].getPath().getName().contains("set2")) { 
       fileSystem.rename(outputfs[fileCounter].getPath(), new Path(set2Path+"/"+anyNewFileName)); 
      } else if (outputfs[fileCounter].getPath().getName().contains("set3")) { 
       fileSystem.rename(outputfs[fileCounter].getPath(), new Path(set3Path+"/"+anyNewFileName)); 
      } 
     } 
    } 

注意:這不會增加任何重要的開銷,因爲我們只是從一個目錄移動到另一個目錄。選擇任何特定的方法取決於您的實施的性質。總之,這種方法基本上將所有使用不同名稱的輸出文件寫入同一個輸出目錄,並且當作業成功完成時,我們重命名基本輸出路徑並將文件移動到不同的輸出目錄。

問題2:從輸入文件夾(S)讀取特定文件:

你絕對可以使用MultipleInputs類目錄中讀取特定的輸入文件。

根據您的輸入路徑/文件名稱,您可以將輸入文件傳遞給相應的Mapper實現。

案例1:如果所有的輸入文件是在一個單獨的目錄:

FileStatus inputfs[] = fileSystem.listStatus(inputPath); 
for (int fileCounter = 0; fileCounter < inputfs.length; fileCounter++) { 
    if (inputfs[fileCounter].getPath().getName().contains("set1")) { 
     MultipleInputs.addInputPath(job, inputfs[fileCounter].getPath(), TextInputFormat.class, Set1Mapper.class); 
    } else if (inputfs[fileCounter].getPath().getName().contains("set2")) { 
     MultipleInputs.addInputPath(job, inputfs[fileCounter].getPath(), TextInputFormat.class, Set2Mapper.class); 
    } else if (inputfs[fileCounter].getPath().getName().contains("set3")) { 
     MultipleInputs.addInputPath(job, inputfs[fileCounter].getPath(), TextInputFormat.class, Set3Mapper.class); 
    } 
} 

案例2:如果所有的輸入文件不在一個目錄:

我們可以即使輸入文件位於不同目錄中,也基本上使用上述相同的方法。遍歷基本輸入路徑並檢查文件路徑名稱以獲得匹配條件。或者,如果文件位於完全不同的位置,最簡單的方法是單獨添加到多個輸入。

MultipleInputs.addInputPath(job, Set1_Path, TextInputFormat.class, Set1Mapper.class); 
MultipleInputs.addInputPath(job, Set2_Path, TextInputFormat.class, Set2Mapper.class); 
MultipleInputs.addInputPath(job, Set3_Path, TextInputFormat.class, Set3Mapper.class); 

希望這有助於!謝謝。