Скопируйте файлы в локальные из нескольких каталогов в HDFS за последние 24 часа - PullRequest
8 голосов
/ 26 марта 2019

У меня проблема с передачей данных из HDFS на локальный компьютер. У меня например:

/path/to/folder/report1/report1_2019_03_24-03_10*.csv
/path/to/folder/report1/report1_2019_03_24-04_12*.csv
...
/path/to/folder/report1/report1_2019_03_25-05_12*.csv
/path/to/folder/report1/report1_2019_03_25-06_12*.csv
/path/to/folder/report1/report1_2019_03_25-07_11*.csv
/path/to/folder/report1/report1_2019_03_25-08_13*.csv
/path/to/folder/report2/report2_out_2019_03_25-05_12*.csv
/path/to/folder/report2/report2_out_2019_03_25-06_11*.csv
/path/to/folder/report3/report3_TH_2019_03_25-05_12*.csv

Так что мне нужно ввести в каждую из этих папок (report1, report2, report3 ... Но не все из них начинаются с «report»), а затем CSV-файлы, которые были скопированы с предыдущих 24-часовых копий в локальную и которые должны быть выполнены каждая утро в 4 часа утра (я могу запланировать это с помощью crontab). Проблема в том, что я не знаю, как перебирать файл и передавать метку времени в качестве аргумента.

Я пробовал что-то вроде этого (найдено в Переполнение стека)

/datalake/hadoop/bin/hadoop fs -ls /path/to/folder/report1/report1/*    |   tr -s " "    |    cut -d' ' -f6-8    |     grep "^[0-9]"    |    awk 'BEGIN{ MIN=1440; LAST=60*MIN; "date +%s" | getline NOW } { cmd="date -d'\''"$1" "$2"'\'' +%s"; cmd | getline WHEN; DIFF=NOW-WHEN; if(NOW > DIFF){ print "Migrating: "$3; system("datalake/hadoop/bin/hadoop fs -copyToLocal /path/to/local_dir/"$3) }}'

Но этот файл копирует файлы старше меня на несколько дней и копирует только файлы из одного каталога (в данном случае report1).

Есть ли способ сделать это более гибким и правильным. Было бы здорово, если бы это можно было решить с помощью bash, а не с Python. Любое предложение приветствуется или ссылка на хороший ответ с аналогичной проблемой.

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

Ответы [ 2 ]

4 голосов
/ 29 марта 2019

примечание: Я не смог проверить это, но вы можете проверить это шаг за шагом, посмотрев на вывод:

Обычно я бы сказал Никогда не анализируйте вывод ls, но с hadoop у вас на самом деле нет выбора, поскольку нет эквивалента find. (Начиная с версии 2.7.0 есть находка, но она очень ограничена в соответствии с документацией )

Шаг 1: рекурсив ls

$ hadoop fs -ls -R /path/to/folder/

Шаг 2: используйте awk для выбора только файлов и csv только для файлов
каталоги распознаются по их разрешениям, которые начинаются с d, поэтому мы должны исключить их. И файлы csv распознаются по последнему полю, оканчивающемуся на csv:

$ hadoop fs -ls -R /path/to/folder/ | awk '!/^d/ && /\.csv$/'

убедитесь, что у вас нет пустых строк или просто имя каталога ...

Шаг 3: продолжайте использовать awk для обработки времени. Я предполагаю, что у вас есть какой-либо стандартный awk, поэтому я не буду использовать расширения GNU. Hadoop выведет формат времени как yyyy-MM-dd HH:mm. Это сортируемый формат, который находится в полях 6 и 7:

$ hadoop fs -ls -R /path/to/folder/  \
   | awk -v cutoff="$(date -d '-24 hours' '+%F %H:%M')" \
         '(!/^d/) && /\.csv$/ && (($6" "$7) > cutoff)'

Шаг 4: Копирование файлов по одному:

Сначала проверьте команду, которую вы собираетесь выполнить:

$ hadoop fs -ls -R /path/to/folder/  \
   | awk -v cutoff="$(date -d '-24 hours' '+%F %H:%M')" \
         '(!/^d/) && /\.csv$/ && (($6" "$7) > cutoff) {
            print "migrating", $NF
            cmd="hadoop fs -get "$NF" /path/to/local/"
            print cmd
            # system(cmd)
         }'

(удалите #, если хотите выполнить)

или

$ hadoop fs -ls -R /path/to/folder/  \
   | awk -v cutoff="$(date -d '-24 hours' '+%F %H:%M')" \
         '(!/^d/) && /\.csv$/ && (($6" "$7) > cutoff) {
            print $NF
         }' | xargs -I{} echo hadoop fs -get '{}' /path/to/local/

(удалите эхо, если хотите выполнить)

1 голос
/ 29 марта 2019

Вы можете сделать это проще, используя «find» в сочетании с «cp», например:

find /path/to/directory/ -type f -name "*.csv" | xargs cp -t /path/to/copy

Если вы хотите очистить каталог от файлов старше 24 часов, вы можете использовать:

find /path/to/files/ -type f -name "*.csv" -mtime +1 | xargs rm -f

Может быть, вы можете реализовать их как скрипт, а затем установить это как задачу в Cron.

...