マッパー出力の一部を、HDFS のフォルダー A などのフォルダーに書き込みたいとします。出力の他の部分は、reducer で処理してもらいたいです。これは可能ですか?複数の出力について認識しています。これは複数の出力を使用して可能ですか?
ありがとう!
はい、MultipleOutputs を使用することは可能です。docs によると、map ステージ中に MultipleOutputs を介して渡された出力はレデューサーによって無視されるため、これはまさにあなたが望むものです。GitHubに小さな例を書いています。お役に立てば幸いです。
マッパー実装から HDFS に出力を直接書き込むことができます。コンテキストの構成を使用して FileSystem オブジェクトを作成し、ファイルを作成して書き込み、閉じることを忘れないでください。
public void cleanup(Context context) {
FileSystem fs = FileSystem.get(context.getConfiguration());
PrintStream ps = new PrintStream(fs.create(
new Path("/path/to/output", "map-output")));
ps.println("test");
ps.close();
}
その他の考慮事項 - 各ファイルには HDFS で一意の名前を付ける必要があるため、ファイル名の末尾にマッパー ID 番号を付けることができますが、投機的実行を理解する必要もあります (マッパー タスク インスタンスが 2 つの場所で実行されている可能性があるため、両方の場所)。 HDFS の同じファイルに書き込もうとしています)。
出力コミッターは、タスク ID と試行番号を使用して tmp HDFS ディレクトリにファイルを作成し、そのタスク試行のコミット時に正しい場所とファイル名に移動するだけなので、通常はこれを抽象化します。投機的実行をオフにするか、HDFS に複数のファイルを 1 つずつ作成せずにマップ側 (データがローカル ファイル システムに書き込まれる) を実行している場合、この問題を回避する方法はありません。
したがって、より「完全な」ソリューションは次のようになります。
FileSystem fs = FileSystem.get(context.getConfiguration());
PrintStream ps = new PrintStream(fs.create(new Path(
"/path/to/output", String.format("map-output-%05d-%d",
context.getTaskAttemptID().getTaskID().getId(),
context.getTaskAttemptID().getId()))));
ps.println("test");
ps.close();
MultipleOutputs は側面を減らすのに役立ちますが、出力コミッターがなく、作業ディレクトリが HDFS にないため、マップ側では機能しないと思います。
もちろん、これがマッパーのみのジョブである場合は、MultipleOutputs が機能します。したがって、別のアプローチは、マップのみのジョブを実行し、出力の必要な部分を (ID マッパーを使用して) セカンダリ ジョブで使用することです。これは、移動するデータの量によって異なります。