【问题标题】:Hadoop: compress file in HDFS?Hadoop:在 HDFS 中压缩文件?
【发布时间】:2011-08-22 20:16:59
【问题描述】:

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

【问题讨论】:

    标签: compression hadoop


    【解决方案1】:

    对我来说,编写 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
    

    另外一点,我没有在流式作业中指定减速器,但你当然可以。它将强制对所有行进行排序,这对于大文件可能需要很长时间。可能有一种方法可以通过覆盖分区器来解决这个问题,但我没有费心去弄清楚。不幸的是,您最终可能会得到许多不能有效利用 HDFS 块的小文件。这是研究Hadoop Archives

    的原因之一

    【讨论】:

    • 为什么用“cut -f 2”而不是“cat”?
    • 映射器的输入是键和由制表符分隔的值。键是文件中行的字节偏移量,值是行的文本。 cut -f 2 仅输出值。
    • 如何压缩hdfs中的文件夹?
    • 下面的答案其实是用了cat命令,是正确的答案。
    • 上述命令在压缩输出的每一行末尾给出了额外的“制表符”。
    【解决方案2】:

    我建议您编写一个 MapReduce 作业,正如您所说,它只使用身份映射器。当您使用它时,您应该考虑将数据写入序列文件以提高性能加载。您还可以将序列文件存储在块级和记录级压缩中。你应该看看什么最适合你,因为两者都针对不同类型的记录进行了优化。

    【讨论】:

      【解决方案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
      

      【讨论】:

      • 只是想确保我理解这些命令。第一个生成 gzip 文件的输出,但实际文件不是 *.gz 格式,所以第二个命令是重命名它?
      • 不,第一个命令会生成压缩的 *.gz part 文件(其中很多)。第二个命令用于将这些部分文件连接到一个单独的“compressed.gz”文件中。
      • 上述命令在压缩输出的每一行末尾给出了额外的tab 字符
      【解决方案4】:

      这是我用过的:

      /*
       * 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,所以可能会慢一些。

      【讨论】:

      • 这是压缩输入目录中的每个单独文件,还是压缩将所有文件视为一个大文件并对其进行压缩,然后输出可能更少的文件?如果是后一种情况,有没有办法指定猪一次应该尝试压缩多少数据,例如一次 3Gb?
      • 是的,它会将整个输入目录加载到单个别名中并输出为 ${OUT_DIR}/part-m-*.bz2。如果你想要一个 3Gb 的输入目录然后控制 IN_DIR
      【解决方案5】:

      @奇特拉 由于声誉问题,我无法发表评论

      这是一个命令中的所有内容:您可以直接将其缩减为一个压缩文件,而不是使用第二个命令

      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 个 1.05 MB 的文件

      【讨论】:

        【解决方案6】:

        我知道这是旧线程,但如果有人关注此线程(如我),知道以下两种方法中的任何一种都会在每行末尾为您提供 tab (\t) 字符

         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"
        
        
        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
        

        hadoop-streaming.jar adds x'09' at the end of each line,我找到了解决方法,我们需要设置以下 2 个参数来分别使用您使用的分隔符(在我的情况下是 ,)

         -Dstream.map.output.field.separator=, \
         -Dmapred.textoutputformat.separator=, \
        

        要执行的完整命令

        hadoop jar <HADOOP_HOME>/jars/hadoop-streaming-2.6.0-cdh5.4.11.jar \
                -Dmapred.reduce.tasks=1 \
                -Dmapred.output.compress=true \
                -Dmapred.compress.map.output=true \
         -Dstream.map.output.field.separator=, \
         -Dmapred.textoutputformat.separator=, \
                -Dmapred.output.compression.codec=org.apache.hadoop.io.compress.Lz4Codec \
                -input file:////home/admin.kopparapu/accenture/File1_PII_Phone_part3.csv \
                -output file:///home/admin.kopparapu/accenture/part3 \
         -mapper /bin/cat \
                -reducer /bin/cat \
                -inputformat org.apache.hadoop.mapred.TextInputFormat \
                -outputformat org.apache.hadoop.mapred.TextOutputFormat
        

        【讨论】:

          【解决方案7】:

          好吧,如果您压缩单个文件,您可能会节省一些空间,但您不能真正使用 Hadoop 的功能来处理该文件,因为解压缩必须由单个 Map 任务顺序完成。如果您有很多文件,则有Hadoop Archive,但我不确定它是否包含任何类型的压缩。我能想到的主要压缩用例是压缩 Maps 的输出以发送到 Reduces(节省网络 I/O)。

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

          【讨论】:

          • Hadoop 已集成压缩库,请参阅cloudera.com/blog/2009/06/…
          • 有趣。我以为你在谈论输入被压缩,而不是压缩输出,对不起。你关心输出文件中数据的排序吗?如果您不关心输出文件的排序,您可以轻松地使用文件系统 API 并将 FSDataOutputStream 包装在 LZO 压缩过滤器中。如果你这样做了,那么 FileOutputFormat.setCompressOutput() 和 setOutputCompressorClass()。它就在 Javadoc 中,通过 Google 在 10 秒内找到。
          猜你喜欢
          • 1970-01-01
          • 2023-03-09
          • 2020-09-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-25
          • 2017-06-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多