4
  1. 同じレデューサーからの2つの異なるタイプの出力を2つの異なるディレクトリに書き込みたい。

hadoopの複数出力機能を使用して異なるファイルに書き込むことはできますが、どちらも同じ出力フォルダーに移動します。

同じreduceから別のフォルダに各ファイルを書き込みたい。

これを行う方法はありますか?

たとえば「hello/testfile」を2番目の引数として入れてみると、無効な引数が表示されます。そのため、別のフォルダに書き込むことができません。

  1. 上記のケースが不可能な場合、マッパーが入力フォルダーから特定のファイルのみを読み取ることは可能ですか?

私を助けてください。

前もって感謝します!


返信いただきありがとうございます。上記の方法を使用して、ファイルを正常に読み取ることができます。しかし、分散モードでは、そうすることができません。レデューサーでは、次のように設定しました。

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

(複数の出力を使用し、Job Confで:使用してみました

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

と同様

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

ただし、次のエラーが発生します。

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

4 に答える 4

2

質問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);

お役に立てれば!ありがとうございました。

于 2016-05-20T17:11:07.517 に答える
1

はい、入力フォーマットが特定のファイルのみを処理するように指定できます。

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

コードを修正する場合は、ジョブが正常に完了したときに_SUCCESSファイルを両方のフォルダーに書き込む必要があることに注意してください。これは必須ではありませんが、誰かがそのフォルダーの出力が完了したかどうかを判断できるメカニズムであり、エラーのために「切り捨てられました」。

于 2012-07-14T11:38:48.887 に答える
1

MultipleOutputsコードをコードベースにコピーし、許可される文字の制限を緩和します。とにかく制限の正当な理由がわかりません。

于 2012-07-14T04:07:33.273 に答える
0

はい、これを行うことができます。あなたがする必要があるのは、レデューサーから出てくる特定のキー/値のペアのファイル名を生成することです。

メソッドをオーバーライドすると、取得したキーと値のペアなどに応じてファイル名を返すことができます。これがその方法を示すリンクです。

https://www.google.co.in/url?sa=t&rct=j&q3%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

于 2012-07-14T18:24:17.283 に答える