java程序员的大数据之路(5):HDFS压缩与解压缩

背景

好久没有更新了,原因是公司项目上线,差点被祭天。在这种惊心动魄的时候还是要抽时间做一点自己喜欢做的事情的,然而进度比预期慢了许多。

正式开始

接下来就开始记录最近的学习成果啦!
在Hadoop集群中,网络资源是非常珍贵的。因此对文件进行压缩是非常必要的,除此之外。压缩文件的另一个好处就是可以节省磁盘空间。

压缩方法介绍

我们在对文件进行压缩时,要仔细考虑使用哪种压缩方法最合适。常见的压缩格式有

表5-1
压缩格式工具算法文件扩展名是否包含多个文件是否可切分
DEFLATEN/ADEFLATE.deflate
GzipgzipDEFLATE.gz
bzip2bzip2bzip2.bz2
LZOLzopLZO.lzo

相比较之下,bzip2比gzip更高效,但压缩速度要慢一些。LZO压缩速度比gzip更快,但效率不高。
在Hadoop中,一个对CompressionCodec接口的实现代表一个codec。例如,GzipCodec包装了gzip的压缩和解压缩方法。(实际上每个Codec都包含了这两个方法)
我们可以利用CompressionCodec中的方法对数据进行压缩和解压。
上表中“是否可切分”一列,表示压缩算法是否支持切分。可切分的压缩格式更加适合MapReduce。gzip格式使用DEFLATE来存储压缩过的数据,DEFLATE将数据作为一系列压缩过的块进行存储。问题是,每块的开始没有指定用户在数据流中任意点定位到下一个块的起始位置,而是其自身与数据流同步。因此,gzip并不支持文件切分。但是,bzip2文件提供不同数据块之间的同步标识,因而它是支持切分的。

在MapReduce中使用压缩

主要代码

这里举一个查询每年最高气温的例子,对输出数据进行压缩。
Map

public class MaxTemperatureMapper extends MapReduceBase
    implements Mapper<LongWritable, Text, Text, IntWritable>{

    private static final int MISSING = 9999;

    public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException {
        String data = value.toString();
        String year = "";
        int airTemperature = 0;
        if(data != null && data.length() > 0) {
            String[] temp = data.split(",");
            year = temp[0];
            airTemperature = Integer.parseInt(temp[1]);
        }
        output.collect(new Text(year),new IntWritable(airTemperature));
    }
}

Reduce

public class MaxTemperatureReducer extends MapReduceBase
    implements Reducer<Text, IntWritable, Text, IntWritable>{

    public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException {
        int maxValue = Integer.MIN_VALUE;
        while (values.hasNext()) {
            maxValue = Math.max(maxValue, values.next().get());
        }
        output.collect(key, new IntWritable((maxValue)));
    }
}

Compression

public class MaxTemperatureWithCompression {
    public static void main(String[] args) throws IOException {
        if (args.length != 2) {
            System.err.println("Usage: MaxTemperatureWithCompression <input path> " +
                    "<output path>");
            System.exit(-1);
        }
        JobConf conf = new JobConf(MaxTemperatureWithCompression.class);
        conf.setJobName("Max temperature with output compression");

        FileInputFormat.addInputPath(conf, new Path(args[0]));
        FileOutputFormat.setOutputPath(conf, new Path(args[1]));

        conf.setOutputKeyClass(Text.class);
        conf.setOutputValueClass(IntWritable.class);

        conf.setBoolean("mapred.output.compress", true);
        conf.setClass("mapred.output.compression.codec", GzipCodec.class, CompressionCodec.class);

        conf.setMapperClass(MaxTemperatureMapper.class);
        conf.setCombinerClass(MaxTemperatureReducer.class);
        conf.setReducerClass(MaxTemperatureReducer.class);

        JobClient.runJob(conf);
    }
}
运行结果

这里写图片描述
上图中,output目录下的结果为未设置要使用的压缩类,即Hadoop默认使用的是DEFLATE压缩,扩展名为.deflate。output1目录下的结果是设置使用Gzip压缩。

需要注意

验证过程中,需要注意的是,一定根据map和reduce方法的参数设置setOutputKeyClass和setOutputValueClass,否则会抛出类型转换异常,因为Hadoop默认的输出Key和Value类型分别是LongWritable和Text。
本例中map和reduce输出类型相同,如果不同,也可以单独设置中间结果的输出类型:

   conf.setMapOutputKeyClass(Text.class);
   conf.setMapOutputValueClass(IntWritable.class);

总结

要对MapReduce进行压缩,需要把mapred.output.compress属性设置为true,另外需要设置mapred.output.compression.codec属性。如果要对map的输出结果进行压缩,则需要设置mapred.compress.map.output和mapred.map.output.compression.codec。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值