将文件从 HDFS 中的多个目录复制到本地 24 小时



我在将数据从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

所以我需要输入这些文件夹中的每一个(报告1,报告2,报告3...但并非所有文件都以"报告"开头,然后是 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 求解,那就太好了。 欢迎任何建议或链接到具有类似问题的良好答案。

此外,没有必要处于某种循环中。我可以为每个报表使用单独的代码行。

注意:我无法对此进行测试,但您可以通过查看输出逐步测试:

通常我会说永远不要解析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/

(如果要执行,请删除echo)

您可以通过将"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上的任务。

最新更新