MapReduce処理に適したgz圧縮方式
最近hadoopの準備をしていますが、テストクラスタは普通の6つの仮想マシンしかなく、1 Gメモリ、100 Gハードディスクごとにあります.だからyarnがリソーススケジューリングを行うときは葛藤し、ハードディスクのスペースも限られています.ジョブを実行する際には、できるだけ入力データを圧縮することが望ましい.
hadoopはgz形式の圧縮ファイルを直接処理することができるが、splitは生成されず、gzはアルゴリズム的にsplitをサポートしないため、多くの場合Mapperに直接渡すことができる.bzip 2はsplitをサポートしているが、圧縮速度が遅く、gzは最も一般的な圧縮方式と言える.
最初は当たり前のように分巻を圧縮しようとしたが、結果はもちろん失敗した.何巻に分けてもgzは全体で解凍しなければならないからだ.
私はテキストデータを処理するだけで、しかもテキスト行に基づいているので、各行の間にxmlのようにネスト関係がないので、大きなファイルを圧縮するときに、発生した圧縮ファイルが1つの設定値より大きい場合は、新しいファイルを作成して圧縮を続けます.
コマンドラインパラメータ:D:temptest.txt D:\temp test 64
このようにして生成される圧縮ファイルは、それぞれ64 MB未満であり、最大100 k未満の差がある.考える要素は少ないですが、ここでは大まかなアルゴリズムを書いただけで、需要を満たしています.
hadoopはgz形式の圧縮ファイルを直接処理することができるが、splitは生成されず、gzはアルゴリズム的にsplitをサポートしないため、多くの場合Mapperに直接渡すことができる.bzip 2はsplitをサポートしているが、圧縮速度が遅く、gzは最も一般的な圧縮方式と言える.
最初は当たり前のように分巻を圧縮しようとしたが、結果はもちろん失敗した.何巻に分けてもgzは全体で解凍しなければならないからだ.
私はテキストデータを処理するだけで、しかもテキスト行に基づいているので、各行の間にxmlのようにネスト関係がないので、大きなファイルを圧縮するときに、発生した圧縮ファイルが1つの設定値より大きい場合は、新しいファイルを作成して圧縮を続けます.
package util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;
public class CompressUtils
{
/**
* GZIP
* @param inputFile
* @param outputDir
* @param outputFileName
* @param splitSize
*/
public static void compressToSplitsUseGZIP(File inputFile, File outputDir, String outputFileName, int splitSize)
throws Exception
{
String separator = System.getProperty("line.separator");
int split = 0;
long limit = splitSize * 1024 * 1024L;
File outputSplit = new File(outputDir, outputFileName + split + ".gz");
outputSplit.createNewFile();
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile), "UTF-8"));
PrintWriter out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(outputSplit)), false);
String line = null;
long fileLength = outputSplit.length();
long maxInc = 0L;
while (true)
{
line = br.readLine();
if (line == null)
{
break;
}
if (fileLength + maxInc > limit)
{
if (out != null)
{
out.close();
out = null;
outputSplit = new File(outputDir, outputFileName + (++split) + ".gz");
outputSplit.createNewFile();
fileLength = outputSplit.length();
out = new PrintWriter(new GZIPOutputStream(
new FileOutputStream(outputSplit)), false);
}
}
for (byte b : line.getBytes())
{
out.write(b);
}
for (byte b : separator.getBytes())
{
out.write(b);
}
out.flush();
long currentLength = outputSplit.length();
long inc = currentLength - fileLength;
if (inc >= maxInc)
{
maxInc = inc;
}
fileLength = currentLength;
}
br.close();
try
{
out.close();
}
catch (Exception e)
{
}
}
public static void main(String[] args)
throws Exception
{
File inputFile = new File(args[0]);
File outputDir = new File(args[1]);
String outputFileName = args[2];
int splitSize = Integer.parseInt(args[3]);
compressToSplitsUseGZIP(inputFile, outputDir, outputFileName, splitSize);
}
}
コマンドラインパラメータ:D:temptest.txt D:\temp test 64
このようにして生成される圧縮ファイルは、それぞれ64 MB未満であり、最大100 k未満の差がある.考える要素は少ないですが、ここでは大まかなアルゴリズムを書いただけで、需要を満たしています.