HDFSで1_fileName.txt
からN_fileName.txt
までの命名規則で利用可能な1000以上のファイルがあります。各ファイルのサイズは1024 MBです。これらのファイルを1つ(HDFS)にマージして、ファイルの順序を維持する必要があります。 5_FileName.txt
は4_fileName.txt
の後にのみ追加する必要があると言います
この操作を実行するための最良かつ最速の方法は何ですか。
データノード間で実際のデータをコピーせずにこのマージを実行する方法はありますか? e-gの場合:このファイルのブロックの場所を取得し、これらのブロックの場所でNamenodeに新しいエントリ(FileName)を作成しますか?
これを行う効率的な方法はありません。すべてのデータを1つのノードに移動してから、HDFSに戻す必要があります。
これを実行するコマンドラインスクリプトレットは次のようになります。
hadoop fs -text *_fileName.txt | hadoop fs -put - targetFilename.txt
これにより、グロブに一致するすべてのファイルが標準出力に送られます。次に、そのストリームをputコマンドにパイプし、targetFilename.txtという名前のHDFSファイルにストリームを出力します。
あなたが持っている唯一の問題は、あなたが行ったファイル名の構造です-幅を固定し、数字の部分にゼロパッドを入れた場合、それは簡単ですが、現在の状態では予期しない辞書順(1、10、100、1000)になります、11、110など)ではなく、番号順(1、2、3、4など)。この問題を回避するには、スクリプトレットを次のように修正します。
hadoop fs -text [0-9]_fileName.txt [0-9][0-9]_fileName.txt \
[0-9][0-9[0-9]_fileName.txt | hadoop fs -put - targetFilename.txt
この操作を実行するAPIメソッド org.Apache.hadoop.fs.FileUtil.copyMerge があります。
public static boolean copyMerge(
FileSystem srcFS,
Path srcDir,
FileSystem dstFS,
Path dstFile,
boolean deleteSource,
Configuration conf,
String addString)
srcDir
のすべてのファイルをアルファベット順に読み取り、その内容をdstFileに追加します。
火花が使えれば。それはのように行うことができます
sc.textFile("hdfs://...../part*).coalesce(1).saveAsTextFile("hdfs://...../filename)
sparkは分散方式で機能するため、これが機能することを願っています。ファイルを1つのノードにコピーする必要はありません。注意してくださいが、sparkファイルが非常に大きい場合は遅くなります。
ファイルの順序は重要であり、辞書式順序は目的を満たさないため、おそらく定期的に実行できるこのタスクのマッパープログラムを作成することをお勧めします。オフコースにはレデューサーがありません。これをHDFSマップタスクとして書き込むと、データノード間でデータをあまり移動することなく、これらのファイルを1つの出力ファイルにマージできるため効率的です。ソースファイルはHDFSにあり、マッパータスクはデータアフィニティを試みるため、異なるデータノード間でファイルを移動せずにファイルをマージできます。
マッパープログラムには、カスタムInputSplit(入力ディレクトリでファイル名を取得し、必要に応じて順序を付ける)とカスタムInputFormatが必要です。
マッパーは、hdfs appendまたはbyte []で書き込むことができる生の出力ストリームを使用できます。
私が考えているマッパープログラムの大まかなスケッチは次のようなものです。
public class MergeOrderedFileMapper extends MapReduceBase implements Mapper<ArrayWritable, Text, ??, ??>
{
FileSystem fs;
public void map(ArrayWritable sourceFiles, Text destFile, OutputCollector<??, ??> output, Reporter reporter) throws IOException
{
//Convert the destFile to Path.
...
//make sure the parent directory of destFile is created first.
FSDataOutputStream destOS = fs.append(destFilePath);
//Convert the sourceFiles to Paths.
List<Path> srcPaths;
....
....
for(Path p: sourcePaths) {
FSDataInputStream srcIS = fs.open(p);
byte[] fileContent
srcIS.read(fileContent);
destOS.write(fileContent);
srcIS.close();
reporter.progress(); // Important, else mapper taks may timeout.
}
destOS.close();
// Delete source files.
for(Path p: sourcePaths) {
fs.delete(p, false);
reporter.progress();
}
}
}
PySparkの実装を書いたのは、これをよく使用するためです。
HadoopのcopyMerge()
をモデルにしており、これを実現するために同じ下位レベルのHadoop APIを使用しています。
https://github.com/Tagar/abalon/blob/v2.3.3/abalon/spark/sparkutils.py#L335
ファイル名のアルファベット順を保持します。