質問1:出力ファイルを別のディレクトリに書き込む-次のアプローチを使用して行うことができます。
1. MultipleOutputsクラスの使用:
MultipleOutputsを使用して複数の名前付き出力ファイルを作成できるのは素晴らしいことです。ご存知のように、これをドライバーコードに追加する必要があります。
MultipleOutputs.addNamedOutput(job, "OutputFileName", OutputFormatClass, keyClass, valueClass);
APIは、これを実現するために2つのオーバーロードされた書き込みメソッドを提供します。
multipleOutputs.write("OutputFileName", new Text(Key), new Text(Value));
ここで、出力ファイルを個別の出力ディレクトリに書き込むには、ベース出力パスに追加のパラメータを指定したオーバーロードされた書き込みメソッドを使用する必要があります。
multipleOutputs.write("OutputFileName", new Text(key), new Text(value), baseOutputPath);
各実装でbaseOutputPathを変更することを忘れないでください。
2.ドライバークラスのファイルの名前を変更/移動します。
これはおそらく、複数のディレクトリに出力を書き込むための最も簡単なハックです。複数の出力を使用して、すべての出力ファイルを単一の出力ディレクトリに書き込みます。ただし、ファイル名はカテゴリごとに異なる必要があります。
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:入力フォルダーから特定のファイルを読み取る:
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);
お役に立てれば!ありがとうございました。