2011-08-22 77 views
12

我最近在Hadoop中设置了LZO压缩。在HDFS中压缩文件最简单的方法是什么?我想压缩文件,然后删除原件。我应该使用IdentityMapper和使用LZO压缩的IdentityReducer创建MR作业吗?Hadoop:在HDFS中压缩文件?

回答

6

我建议你写一个MapReduce作业,就像你说的那样,它只是使用Identity映射器。当你处理它时,你应该考虑将数据写入序列文件以提高性能加载。您还可以按块级和记录级压缩存储序列文件。呦应该看看什么对你最有效,因为两者都针对不同类型的记录进行了优化。

-3

那么,如果你压缩一个文件,你可能会节省一些空间,但你不能真正使用Hadoop的能力来处理该文件,因为解压缩必须由一个Map任务顺序完成。如果你有很多文件,有Hadoop Archive,但我不确定它包含任何类型的压缩。压缩的主要用例我能想到的是压缩要发送到Reduces的地图的输出(保存在网络I/O上)。

哦,要回答你的问题更完整,你可能需要实现自己的RecordReader和/或InputFormat,以确保整个文件被单个Map任务读取,并且它使用了正确的解压过滤器。

+0

Hadoop集成了压缩库,请参阅http://www.cloudera.com/blog/2009/ 06 /并行LZO-可分离的压缩换的hadoop /。 – schmmd

+0

有趣。我以为你在谈论输入被压缩,而不是压缩输出,对不起。你关心输出文件中数据的排序吗?如果您不关心输出文件的排序,您可以轻松使用文件系统API并将FSDataOutputStream包装在LZO压缩过滤器中。如果你这样做,那么FileOutputFormat.setCompressOutput()和setOutputCompressorClass()。在Javadoc中是正确的,通过Google在10秒内发现它。 – Drizzt321

19

对我来说,编写一个Hadoop Streaming作业来压缩文件的开销较低。

这是我运行命令:

hadoop jar $HADOOP_HOME/contrib/streaming/hadoop-streaming-0.20.2-cdh3u2.jar \ 
    -Dmapred.output.compress=true \ 
    -Dmapred.compress.map.output=true \ 
    -Dmapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec \ 
    -Dmapred.reduce.tasks=0 \ 
    -input <input-path> \ 
    -output $OUTPUT \ 
    -mapper "cut -f 2" 

我也通常会藏匿在一些情况下,一个临时文件夹输出出错:

OUTPUT=/tmp/hdfs-gzip-`basename $1`-$RANDOM 

,还应注意,我不知道在流式作业中指定reducer,但您当然可以。它将强制所有行进行排序,这可能需要很长时间才能处理大文件。可能有一种方法可以通过重写分区程序来解决这个问题,但我没有想到这一点。这个不幸的部分是,你可能会得到很多小文件不能有效利用HDFS块。这是查看的一个原因Hadoop Archives

+0

为什么“cut -f 2”而不是“猫”? – dranxo

+2

映射器的输入是一个键和一个由制表符分隔的值。关键是文件中行的字节偏移量,值是行的文本。 'cut -f 2'只输出数值。 –

+0

我如何压缩hdfs中的文件夹? – subhashlg26

3

来自Jeff Wu的流式命令以及压缩文件的串联将给出单个压缩文件。当一个非java映射器被传递给流式作业,并且输入格式为文本流式输出时,只输出值而不输出密钥。

hadoop jar contrib/streaming/hadoop-streaming-1.0.3.jar \ 
      -Dmapred.reduce.tasks=0 \ 
      -Dmapred.output.compress=true \ 
      -Dmapred.compress.map.output=true \ 
      -Dmapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec \ 
      -input filename \ 
      -output /filename \ 
      -mapper /bin/cat \ 
      -inputformat org.apache.hadoop.mapred.TextInputFormat \ 
      -outputformat org.apache.hadoop.mapred.TextOutputFormat 
hadoop fs -cat /path/part* | hadoop fs -put - /path/compressed.gz 
+0

只是想确保我理解这些命令。第一个产生gzip文件的输出,但实际文件不是* .gz格式,所以第二个命令是重命名它? – nevets1219

+0

不,第一个命令生成压缩的* .gz **部分**文件(其中很多)。第二个命令是将这些部分文件连接成一个'compressed.gz'文件。 – daemon12

+0

上面的命令在压缩输出的每一行的末尾提供了额外的'tab'字符 – daemon12

3

这是我用过的:

/* 
* Pig script to compress a directory 
* input: hdfs input directory to compress 
*   hdfs output directory 
* 
* 
*/ 

set output.compression.enabled true; 
set output.compression.codec org.apache.hadoop.io.compress.BZip2Codec; 

--comma seperated list of hdfs directories to compress 
input0 = LOAD '$IN_DIR' USING PigStorage(); 

--single output directory 
STORE input0 INTO '$OUT_DIR' USING PigStorage(); 

虽然它不是LZO所以它可能是有点慢。

+0

这会压缩输入目录中的每个单独文件,还是压缩将所有文件视为一个大文件并对其进行压缩,然后进行输出很少的文件?如果是后一种情况,是否有一种方法可以指定每次应该尝试压缩多少数据,例如,一次3Gb? – AatG

+0

是的,它会将整个输入目录加载到一个别名中,并输出为$ {OUT_DIR}/part-m - *。bz2。如果你想要一个3Gb输入目录然后控制IN_DIR – dranxo

4

@Chitra 我不能因信誉问题发表评论

这里的一切都在一个命令:在使用第二个命令相反的,你可以减少成一个压缩文件直接

hadoop jar share/hadoop/tools/lib/hadoop-streaming-2.7.3.jar \ 
     -Dmapred.reduce.tasks=1 \ 
     -Dmapred.output.compress=true \ 
     -Dmapred.compress.map.output=true \ 
     -Dmapred.output.compression.codec=org.apache.hadoop.io.compress.BZip2Codec \ 
     -input /input/raw_file \ 
     -output /archives/ \ 
     -mapper /bin/cat \ 
     -reducer /bin/cat \ 
     -inputformat org.apache.hadoop.mapred.TextInputFormat \ 
     -outputformat org.apache.hadoop.mapred.TextOutputFormat 

因此,你通过只有一个压缩文件获得大量空间

例如,假设我有4个10MB的文件(纯文本,JSON格式)

该地图只给我4个文件的650 KB 如果我映射和减少我有1.05 MB的文件