【问题标题】:Copy files to local from multiple directories in HDFS for last 24 hours将文件从 HDFS 中的多个目录复制到本地过去 24 小时
【发布时间】:2019-08-21 18:21:41
【问题描述】:

我在将数据从 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'\''"$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) }}'

但这个是复制比我早几天的文件,它只复制一个目录中的文件(在本例中为报告 1)。

有什么方法可以让这更灵活和正确。如果这可以是 bash 的求解器,而不是 Python 的求解器,那就太好了。 欢迎任何建议或链接到具有类似问题的好答案。

此外,不必处于某个循环中。我可以为每个报告使用单独的代码行。

【问题讨论】:

  • 可能是我理解的不对,为什么不直接复制/path/to/folder/*或者/path/to/folder/report*呢?
  • @Tiberiu 因为这些文件夹每天每小时都会收到报告(csv 文件),而且越来越大。我不需要所有这些文件,只需要前 24 小时的每一天。
  • 啊,我明白了。我不确定 bash 命令是什么,但如果是我,我会有另一个文件夹结构,未复制的文件都将驻留在其中,所以你可以在那里获取所有内容。复制后,它们可以移动到一般的report 文件夹。将大大简化您的命令,并在出现问题时留下痕迹,但我是出于编程心态。
  • @Tiberiu 问题是我不是创建文件夹结构的人。如果没问题,我只适用于一个文件夹(报告),我可以使用该 bash 脚本,对任何其他文件夹稍作更改。
  • 您是否尝试安装您的 HDFS(使用 hadoop-fuse-dfs 或类似名称)?

标签: bash hadoop hdfs


【解决方案1】:

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

通常我会说 Never parse the output of ls,但对于 Hadoop,您在这里别无选择,因为没有与 find 等效的选项。 (从2.7.0开始就有了,不过根据documentation是非常有限的)

第一步:递归ls

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

第 2 步: 使用 仅选择文件和仅选择 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

【讨论】:

  • 谢谢!我会尽快对此进行测试,并让您知道它是否有效。看起来很有希望。 :) 再次感谢。
  • 直到今天我才有机会对此进行测试,但我接受,否则赏金将到期。问题是下一个:awk: cmd.行:1:13:42 awk:cmd。 line:1: ^ 语法错误你知道吗?
  • 第 4 步。两个例子。
  • 非常感谢@kvantour 的回答。您是否建议任何现在开始学习的人的链接awk
  • @NikSp 从 awk one-liners explained 开始,然后继续阅读 posix 标准以了解其想法,然后开始在 gnu awk 手册中查找内容
【解决方案2】:

你可以把“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 上的任务。

【讨论】:

  • hadoop fs -find 是在 Apache Hadoop 2.7.0 中引入的。
  • 可以查看命令参考here
  • 这意味着您可以调整这些简单的命令以使用 hadoop。
  • 是的,但hadoop find 不知道-mtime
猜你喜欢
  • 2014-10-11
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-04
相关资源
最近更新 更多