web-dev-qa-db-fra.com

Comment décompresser des fichiers .gz dans un nouveau répertoire dans hadoop?

J'ai un tas de fichiers .gz dans un dossier en hdfs. Je veux décompresser tous ces fichiers .gz dans un nouveau dossier en hdfs. Comment dois-je procéder?

16
Monica

Je peux penser à y parvenir de 3 manières différentes.

  1. en utilisant la ligne de commande Linux

    La commande suivante a fonctionné pour moi.

    hadoop fs -cat /tmp/Links.txt.gz | gzip -d | hadoop fs -put - /tmp/unzipped/Links.txt
    

    Mon fichier compressé est Links.txt.gz
    La sortie est stockée dans /tmp/unzipped/Links.txt

  2. en utilisant Java

    Dans Hadoop The Definitve Guide book, il y a une section sur Codecs. Dans cette section, il existe un programme pour décompresser la sortie à l'aide de CompressionCodecFactory. Je reproduis ce code tel quel:

    package com.myorg.hadooptests;
    
    import org.Apache.hadoop.conf.Configuration;
    import org.Apache.hadoop.fs.FileSystem;
    import org.Apache.hadoop.fs.Path;
    import org.Apache.hadoop.io.IOUtils;
    import org.Apache.hadoop.io.compress.CompressionCodec;
    import org.Apache.hadoop.io.compress.CompressionCodecFactory;
    
    import Java.io.InputStream;
    import Java.io.OutputStream;
    import Java.net.URI;
    
    public class FileDecompressor {
        public static void main(String[] args) throws Exception {
            String uri = args[0];
            Configuration conf = new Configuration();
            FileSystem fs = FileSystem.get(URI.create(uri), conf);
            Path inputPath = new Path(uri);
            CompressionCodecFactory factory = new CompressionCodecFactory(conf);
            CompressionCodec codec = factory.getCodec(inputPath);
            if (codec == null) {
                System.err.println("No codec found for " + uri);
                System.exit(1);
            }
            String outputUri =
            CompressionCodecFactory.removeSuffix(uri, codec.getDefaultExtension());
            InputStream in = null;
            OutputStream out = null;
            try {
                in = codec.createInputStream(fs.open(inputPath));
                out = fs.create(new Path(outputUri));
                IOUtils.copyBytes(in, out, conf);
            } finally {
                IOUtils.closeStream(in);
                IOUtils.closeStream(out);
            }
        }
    }
    

    Ce code prend le chemin du fichier gz en entrée.
    Vous pouvez exécuter ceci comme:

    FileDecompressor <gzipped file name>
    

    Par exemple quand j'ai exécuté pour mon fichier compressé:

    FileDecompressor /tmp/Links.txt.gz
    

    J'ai obtenu le fichier décompressé à l'emplacement: /tmp/Links.txt

    Il stocke le fichier décompressé dans le même dossier. Vous devez donc modifier ce code pour prendre 2 paramètres d'entrée: <input file path> and <output folder>.

    Une fois que ce programme fonctionne, vous pouvez écrire un script Shell/Perl/Python pour appeler ce programme pour chacune des entrées que vous avez.

  3. en utilisant le script Pig

    Vous pouvez écrire un simple script Pig pour y parvenir.

    J'ai écrit le script suivant, qui fonctionne:

    A = LOAD '/tmp/Links.txt.gz' USING PigStorage();
    Store A into '/tmp/tmp_unzipped/' USING PigStorage();
    mv /tmp/tmp_unzipped/part-m-00000 /tmp/unzipped/Links.txt
    rm /tmp/tmp_unzipped/
    

    Lorsque vous exécutez ce script, le contenu décompressé est stocké dans un dossier temporaire: /tmp/tmp_unzipped. Ce dossier contiendra

    /tmp/tmp_unzipped/_SUCCESS
    /tmp/tmp_unzipped/part-m-00000
    

    Le part-m-00000 contient le fichier décompressé.

    Par conséquent, nous devons le renommer explicitement à l'aide de la commande suivante et enfin supprimer le /tmp/tmp_unzipped dossier:

    mv /tmp/tmp_unzipped/part-m-00000 /tmp/unzipped/Links.txt
    rm /tmp/tmp_unzipped/
    

    Donc, si vous utilisez ce script Pig, il vous suffit de prendre soin de paramétrer le nom du fichier (Links.txt.gz et Links.txt).

    Encore une fois, une fois que ce script fonctionne, vous pouvez écrire un script Shell/Perl/Python pour appeler ce script Pig pour chacune des entrées que vous avez.

30
Manjunath Ballur

Bash solution

Dans mon cas, je ne voulais pas décompresser les fichiers car je n'étais pas sûr de leur contenu. Au lieu de cela, je voulais m'assurer que tous les fichiers dans les fichiers Zip seront placés extraits sur HDFS.

J'ai créé un simple script bash. Les commentaires devraient vous donner une idée de ce qui se passe. Il y a une courte description ci-dessous.

#!/bin/bash

workdir=/tmp/unziphdfs/
cd $workdir

# get all Zip files in a folder
zips=$(hadoop fs -ls /yourpath/*.Zip | awk '{print $8}')
for hdfsfile in $zips
do
    echo $hdfsfile

    # copy to temp folder to unpack
    hdfs dfs -copyToLocal $hdfsfile $workdir

    hdfsdir=$(dirname "$hdfsfile")
    zipname=$(basename "$hdfsfile")

    # unpack locally and remove
    unzip $zipname
    rm -rf $zipname

    # copy files back to hdfs
    files=$(ls $workdir)
    for file in $files; do
       hdfs dfs -copyFromLocal $file $hdfsdir
       rm -rf $file
    done

    # optionally remove the Zip file from hdfs?
    # hadoop fs -rm -skipTrash $hdfsfile
done

La description

  1. Obtenez tous les *.Zip fichiers dans un répertoire hdfs
  2. Un par un: copiez Zip dans un répertoire temporaire (sur le système de fichiers)
  3. Unzip
  4. Copiez tous les fichiers extraits dans le répertoire du fichier Zip
  5. Nettoyer

J'ai réussi à le faire fonctionner avec une structure de sous-répertoires pour de nombreux fichiers Zip dans chacun, en utilisant /mypath/*/*.Zip.

Bonne chance:)

5
Atais

Si vous avez des fichiers texte compressés, hadoop fs -text prend en charge gzip ainsi que d'autres formats de compression courants (snappy, lzo).

hadoop fs -text /tmp/a.gz | hadoop fs -put - /tmp/uncompressed_a
3
tk421

Vous pouvez le faire en utilisant Hive (en supposant qu'il s'agit de données texte).

create external table source (t str) location '<directory_with_gz_files>';
create external table target (t str) location '<target_dir>';
insert into table target select * from source;

Les données seront décompressées dans un nouvel ensemble de fichiers.

si vous ne souhaitez pas modifier les noms et si vous disposez de suffisamment d'espace de stockage sur le nœud sur lequel vous exécutez, vous pouvez le faire.

hadoop fs -get <your_source_directory> <directory_name>
It will create a directory where you run hadoop command. cd to it and gunzip all the files
cd ..
hadoop fs -moveFromLocal <directory_name> <target_hdfs_path>