MapReduce処理に適したgz圧縮方式


最近hadoopの準備をしていますが、テストクラスタは普通の6つの仮想マシンしかなく、1 Gメモリ、100 Gハードディスクごとにあります.だからyarnがリソーススケジューリングを行うときは葛藤し、ハードディスクのスペースも限られています.ジョブを実行する際には、できるだけ入力データを圧縮することが望ましい.
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未満の差がある.考える要素は少ないですが、ここでは大まかなアルゴリズムを書いただけで、需要を満たしています.