最近 24 小时从 HDFS 中的多个目录复制文件到本地
Copy files to local from multiple directories in HDFS for last 24 hours
我在从 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" 开头),然后是从之前 24 小时复制到本地的 CSV 文件应该在每天早上 4 点完成(我可以用 crontab 安排)。
问题是我不知道如何遍历文件并将时间戳作为参数传递。
我试过这样的东西(在 Stack Overflow 上找到)
/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'\''"" ""'\'' +%s"; cmd | getline WHEN; DIFF=NOW-WHEN; if(NOW > DIFF){ print "Migrating: "; system("datalake/hadoop/bin/hadoop fs -copyToLocal /path/to/local_dir/") }}'
但是这个正在复制比我早几天的文件,并且它只从一个目录(在本例中为 report1)复制文件。
有什么办法可以使这个更加灵活和正确吗?如果这可以用 bash 而不是 Python 来求解,那就太好了。
欢迎任何建议或 link 对类似问题的良好回答。
此外,没有必要在某个循环中。我可以为每个报告使用单独的代码行。
您可以将 "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 上的任务。
注意:我无法对此进行测试,但您可以通过查看输出来逐步测试:
通常我会说Never parse the output of ls
, but with Hadoop, you don't have a choice here as there is no equivalent to find
. (Since 2.7.0 there is a find, but it is very limited according to the documentation)
步骤 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$/'
确保你不会在这里得到有趣的空行或只是目录名...
第三步:继续使用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$/ && ((" ") > cutoff)'
第四步: 一个一个复制文件:
首先,检查您要执行的命令:
$ hadoop fs -ls -R /path/to/folder/ \
| awk -v cutoff="$(date -d '-24 hours' '+%F %H:%M')" \
'(!/^d/) && /\.csv$/ && ((" ") > 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$/ && ((" ") > cutoff) {
print $NF
}' | xargs -I{} echo hadoop fs -get '{}' /path/to/local/
(要执行的去掉echo
)
我在从 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" 开头),然后是从之前 24 小时复制到本地的 CSV 文件应该在每天早上 4 点完成(我可以用 crontab 安排)。 问题是我不知道如何遍历文件并将时间戳作为参数传递。
我试过这样的东西(在 Stack Overflow 上找到)
/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'\''"" ""'\'' +%s"; cmd | getline WHEN; DIFF=NOW-WHEN; if(NOW > DIFF){ print "Migrating: "; system("datalake/hadoop/bin/hadoop fs -copyToLocal /path/to/local_dir/") }}'
但是这个正在复制比我早几天的文件,并且它只从一个目录(在本例中为 report1)复制文件。
有什么办法可以使这个更加灵活和正确吗?如果这可以用 bash 而不是 Python 来求解,那就太好了。 欢迎任何建议或 link 对类似问题的良好回答。
此外,没有必要在某个循环中。我可以为每个报告使用单独的代码行。
您可以将 "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 上的任务。
注意:我无法对此进行测试,但您可以通过查看输出来逐步测试:
通常我会说Never parse the output of ls
, but with Hadoop, you don't have a choice here as there is no equivalent to find
. (Since 2.7.0 there is a find, but it is very limited according to the documentation)
步骤 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$/'
确保你不会在这里得到有趣的空行或只是目录名...
第三步:继续使用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$/ && ((" ") > cutoff)'
第四步: 一个一个复制文件:
首先,检查您要执行的命令:
$ hadoop fs -ls -R /path/to/folder/ \
| awk -v cutoff="$(date -d '-24 hours' '+%F %H:%M')" \
'(!/^d/) && /\.csv$/ && ((" ") > 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$/ && ((" ") > cutoff) {
print $NF
}' | xargs -I{} echo hadoop fs -get '{}' /path/to/local/
(要执行的去掉echo
)