Hadoop: сжать файл в HDFS?
Недавно я установил компрессию LZO в Hadoop. Какой самый простой способ сжать файл в HDFS? Я хочу сжать файл, а затем удалить оригинал. Должен ли я создать работу MR с IdentityMapper и IdentityReducer, который использует сжатие LZO?
7 ответов
Я предлагаю вам написать задание MapReduce, которое, как вы говорите, просто использует Identity Mapper. Пока вы занимаетесь этим, вам следует рассмотреть возможность записи данных в файлы последовательности для повышения производительности загрузки. Вы также можете хранить файлы последовательности в сжатии на уровне блоков и на уровне записей. Вы должны увидеть, что лучше для вас, так как оба оптимизированы для разных типов записей.
Для меня это меньше затрат на написание задания потоковой передачи Hadoop для сжатия файлов.
Это команда, которую я запускаю:
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
Потоковая команда от Джеффа Ву вместе с объединением сжатых файлов даст один сжатый файл. Когда в потоковое задание передается не 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
Вот что я использовал:
/*
* 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, так что это может быть немного медленнее.
@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 файла по 10 МБ (это обычный текст в формате JSON)
Только карта дает мне 4 файла по 650 КБ. Если я отображаю и уменьшаю, у меня есть 1 файл по 1,05 МБ.
Я знаю, что это старая ветка, но если кто-то следит за этой веткой (например, я), было бы полезно знать, что любой из следующих 2 методов дает вам 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 добавляет x'09'в конце каждой строки, я нашел исправление, и нам нужно установить следующие 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
Что ж, если вы сжимаете один файл, вы можете сэкономить некоторое пространство, но вы не можете реально использовать возможности Hadoop для обработки этого файла, поскольку распаковка должна выполняться одной задачей Map последовательно. Если у вас много файлов, есть Hadoop Archive, но я не уверен, что он включает какие-либо виды сжатия. Основным вариантом использования сжатия, о котором я могу думать, является сжатие выходных данных Карт для отправки в Reduces (за исключением сетевого ввода-вывода).
Да, чтобы ответить на ваш вопрос более полно, вам, вероятно, потребуется реализовать свой собственный RecordReader и / или InputFormat, чтобы убедиться, что весь файл прочитан одной задачей Map, а также использовать правильный фильтр распаковки.