千家信息网

一个适合MapReduce处理的gz压缩方式

发表于:2025-12-03 作者:千家信息网编辑
千家信息网最后更新 2025年12月03日,最近在筹备hadoop,测试集群只有普通的6个虚拟机,每个1G内存,100G硬盘。所以在yarn进行资源调度的时候比较纠结,硬盘空间也有限。在执行作业的时候就希望能够尽量对输入数据进行压缩。hadoo
千家信息网最后更新 2025年12月03日一个适合MapReduce处理的gz压缩方式

最近在筹备hadoop,测试集群只有普通的6个虚拟机,每个1G内存,100G硬盘。所以在yarn进行资源调度的时候比较纠结,硬盘空间也有限。在执行作业的时候就希望能够尽量对输入数据进行压缩。


hadoop可以直接处理gz格式的压缩文件,但不会产生split,而是不论多大都直接交给一个Mapper去做,因为gz在算法上不支持split。虽然bzip2支持split,但压缩速度又比较慢,gz可以说是最常用的压缩方式了。


一开始想当然的尝试压缩分卷,结果当然是失败,因为不管分多少个卷,gz还是要以一个整体来进行解压。


因为我只是处理文本数据,而且都是基于文本行,每一行之间不像xml那样会具有什么嵌套关系,所以动手写了一个压缩程序,在对大文件进行压缩的时候,如果产生的压缩文件大于一个设定值,那就再新建一个文件继续压缩。

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:\temp\test.txt D:\temp test 64


这样产生的压缩文件每一个都会小于64MB,最多相差不到100k。考虑的因素比较少,这里只是把大致的算法写了一下,倒是满足需求了。


0