об'єднати вихідні файли після фази зменшення


75

У mapreduce кожне завдання зменшення запишіть його вихідні дані у файл з іменем part-r-nnnnn, де nnnnn - це ідентифікатор розділу, пов'язаний із завданням зменшення. Чи співпадає / зменшує об’єднання цих файлів? Якщо так, то як?

Відповіді:


121

Замість того, щоб виконувати злиття файлів самостійно, ви можете делегувати все злиття вихідних файлів зменшення, викликавши:

hadoop fs -getmerge /output/dir/on/hdfs/ /desired/local/output/file.txt

Примітка. Це поєднує файли HDFS локально. Перед запуском переконайтеся, що у вас достатньо місця на диску


16
чи є спосіб зробити це, але на dfs? Я маю на увазі, що я хочу об’єднати їх в один файл на dfs?
humanzz

10
Здається, це не працює з dfs, об’єднаний файл записується в локальну файлову систему. Звичайно, ви могли б просто написати це назад, але здається марнотратством.
Маріус Сутьє

4
Примітка: це не безпечно для нетекстових файлів. getMergeробить просту конкатенацію файлів, яка з чимось на зразок SequenceFile не дасть розумного виводу.
growse

2
Це не працює з HDFS як пунктом призначення, який саме призначений.
Gaurav Kumar

getmerge переносить дані з hdfs до локальних.
armourbear

28

Ні, Hadoop не об’єднує ці файли. Кількість отриманих файлів однакова з кількістю завдань скорочення.

Якщо вам це потрібно як вхід для наступного завдання, тоді не турбуйтеся про наявність окремих файлів. Просто вкажіть весь каталог як вхідні дані для наступного завдання.

Якщо вам потрібні дані за межами кластера, я зазвичай зливаю їх у приймальному кінці, витягуючи дані з кластера.

Тобто приблизно так:

hadoop fs -cat /some/where/on/hdfs/job-output/part-r-* > TheCombinedResultOfTheJob.txt

Дякую за вашу відповідь buf у конфігураційному файлі map / reduce ( mapred-default.xml ) є атрибут з назвою io.sort.factor , для чого він використовується ???
Шахряр

2
Код io.sort.factor пов’язаний з обробкою МЕЖ картою та кроком зменшення. Не результат зменшення.
Niels Basjes,

звідки ви знаєте правильний порядок, у якому буде об’єднано файл part-r- *?
Razvan

3
@Razvan: Порядок не повинен мати значення. Якщо це має значення, тоді у вас є алгоритм, який не масштабується, і ви, мабуть, маєте припущення щодо того, який Редуктор зробив яку частину роботи. Тож якщо це трапиться, у вас проблема іншого типу.
Niels Basjes

@NielsBasjes: Краще використовувати "hadoop fs -getmerge" замість "hadoop fs -cat"
Нага

8

Це функція, яку ви можете використовувати для об’єднання файлів у HDFS

public boolean getMergeInHdfs(String src, String dest) throws IllegalArgumentException, IOException {
    FileSystem fs = FileSystem.get(config);
    Path srcPath = new Path(src);
    Path dstPath = new Path(dest);

    // Check if the path already exists
    if (!(fs.exists(srcPath))) {
        logger.info("Path " + src + " does not exists!");
        return false;
    }

    if (!(fs.exists(dstPath))) {
        logger.info("Path " + dest + " does not exists!");
        return false;
    }
    return FileUtil.copyMerge(fs, srcPath, fs, dstPath, false, config, null);
}

8

Лише для текстових файлів та HDFS як джерела та місця призначення використовуйте наведену нижче команду:

hadoop fs -cat /input_hdfs_dir/* | hadoop fs -put - /output_hdfs_file

Це об'єднає всі файли в input_hdfs_dirі запише вихідні дані назад у HDFS за адресою output_hdfs_file. Майте на увазі, що всі дані будуть повернуті до локальної системи, а потім знову завантажені в hdfs, хоча тимчасові файли не створюються, і це відбувається на льоту за допомогою UNIX pe.

Крім того, це не буде працювати з нетекстовими файлами, такими як Avro, ORC тощо.

Для двійкових файлів ви можете зробити щось подібне (якщо у вас таблиці Hive зіставлені в каталогах):

insert overwrite table tbl select * from tbl

Залежно від вашої конфігурації, це також може створити більше, ніж файли. Щоб створити один файл, або встановіть явно кількість редукторів до 1, використовуючи, mapreduce.job.reduces=1або встановіть властивість вулика як hive.merge.mapredfiles=true.


За допомогою цього рішення також пам’ятайте про можливе надходження в кінцевий пункт призначення від stdin. А саме, я зіткнувся з ситуацією, коли в кластері, що підтримує HA, з’являється попереджувальне повідомлення, коли один із вузлів перебуває в режимі очікування. У такій ситуації мій вихід містив ці невинні інакше попереджувальні повідомлення. посилання
kasur

4

Файли part-r-nnnnn генеруються після фази зменшення, позначеної між ними r. Тепер факт: якщо у вас запущений один редуктор, ви отримаєте вихідний файл, такий як part-r-00000. Якщо кількість редукторів дорівнює 2, тоді у вас буде частина-r-00000 та частина-r-00001 тощо. Подивіться, якщо вихідний файл занадто великий, щоб поміститися в пам'ять машини, оскільки фреймворк hadoop розроблений для роботи на товарних машинах , тоді файл розколюється. Відповідно до MRv1, у вас є обмеження на 20 редукторів, які працюють за вашою логікою. Можливо, у вас є більше, але те саме потрібно налаштувати у файлах конфігурації mapred-site.xml . Розмова про ваше запитання; Ви можете скористатися getmerge або встановити кількість редукторів до 1, вбудувавши наступний вираз у код драйвера

job.setNumReduceTasks(1);

Сподіваюся, це відповідає на ваше запитання.


3

Ви можете запустити додаткове завдання зіставлення / зменшення, де відображення та зменшення не змінюють дані, а розділювач призначає всі дані одному редуктору.


1
Не якщо вам потрібно об’єднати більше даних, ніж може обробити локальна машина
Хавнар,

1

Окрім моєї попередньої відповіді, у мене є ще одна відповідь для вас, яку я намагався кілька хвилин тому. Ви можете використовувати CustomOutputFormat, який виглядає як код, наведений нижче

public class VictorOutputFormat extends FileOutputFormat<StudentKey,PassValue> {

    @Override
    public RecordWriter<StudentKey,PassValue> getRecordWriter(
            TaskAttemptContext tac) throws IOException, InterruptedException {
        //step 1: GET THE CURRENT PATH
        Path currPath=FileOutputFormat.getOutputPath(tac);

        //Create the full path
        Path fullPath=new Path(currPath,"Aniruddha.txt");

        //create the file in the file system
        FileSystem fs=currPath.getFileSystem(tac.getConfiguration());
        FSDataOutputStream fileOut=fs.create(fullPath,tac);
        return new VictorRecordWriter(fileOut);
    }

}

Просто погляньте на четвертий рядок з останнього. Я використав своє власне ім'я як ім'я вихідного файлу і протестував програму з 15 редукторами. Файл все ще залишається незмінним. Отже, отримання одного файлу замість двох або більше можливо, але ще бути дуже чітким. Розмір вихідного файлу не повинен перевищувати розмір первинної пам'яті, тобто вихідний файл повинен поміщатися в пам'ять товарної машини, інакше там може бути проблема з розділенням вихідного файлу. Дякую!!


getmerge може вирішити вашу мету, але це альтернатива. але це корисно
Aniruddha Sinha

0

Чому б не використовувати свинячий сценарій, як цей, для об’єднання файлів розділів:

stuff = load "/path/to/dir/*"

store stuff into "/path/to/mergedir"

0

Якщо файли мають заголовок, ви можете позбутися його, виконавши наступне:

hadoop fs -cat /path/to/hdfs/job-output/part-* | grep -v "header" > output.csv

потім додайте заголовок вручну для output.csv


0

. Чи співпадає / зменшує об’єднання цих файлів?

Ні. Це не зливається.

Ви можете використовувати IdentityReducer для досягнення своєї мети.

Не виконує зменшення, записуючи всі вхідні значення безпосередньо на вихід.

public void reduce(K key,
                   Iterator<V> values,
                   OutputCollector<K,V> output,
                   Reporter reporter)
            throws IOException

Записує всі ключі та значення безпосередньо на вихід.

Погляньте на відповідні публікації SE:

hadoop: різниця між редуктором 0 та редуктором ідентичності?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.