【问题标题】:Pig Latin: Load multiple files from a date range (part of the directory structure)Pig Latin:从日期范围加载多个文件(目录结构的一部分)
【发布时间】:2011-03-31 17:42:41
【问题描述】:

我有以下场景-

使用的猪版本 0.70

示例 HDFS 目录结构:

/user/training/test/20100810/<data files>
/user/training/test/20100811/<data files>
/user/training/test/20100812/<data files>
/user/training/test/20100813/<data files>
/user/training/test/20100814/<data files>

正如您在上面列出的路径中看到的,其中一个目录名称是日期戳。

问题:我想从 20100810 到 20100813 的日期范围内加载文件。

我可以将日期范围的 'from' 和 'to' 作为参数传递给 Pig 脚本,但是如何在 LOAD 语句中使用这些参数。我能够做到以下几点

temp = LOAD '/user/training/test/{20100810,20100811,20100812}' USING SomeLoader() AS (...);

以下适用于 hadoop:

hadoop fs -ls /user/training/test/{20100810..20100813}

但是当我在 pig 脚本中尝试使用 LOAD 时它失败了。如何使用传递给 Pig 脚本的参数从日期范围加载数据?

错误日志如下:

Backend error message during job submission
-------------------------------------------
org.apache.pig.backend.executionengine.ExecException: ERROR 2118: Unable to create input splits for: hdfs://<ServerName>.com/user/training/test/{20100810..20100813}
        at org.apache.pig.backend.hadoop.executionengine.mapReduceLayer.PigInputFormat.getSplits(PigInputFormat.java:269)
        at org.apache.hadoop.mapred.JobClient.writeNewSplits(JobClient.java:858)
        at org.apache.hadoop.mapred.JobClient.writeSplits(JobClient.java:875)
        at org.apache.hadoop.mapred.JobClient.access$500(JobClient.java:170)
        at org.apache.hadoop.mapred.JobClient$2.run(JobClient.java:793)
        at org.apache.hadoop.mapred.JobClient$2.run(JobClient.java:752)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:396)
        at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1062)
        at org.apache.hadoop.mapred.JobClient.submitJobInternal(JobClient.java:752)
        at org.apache.hadoop.mapred.JobClient.submitJob(JobClient.java:726)
        at org.apache.hadoop.mapred.jobcontrol.Job.submit(Job.java:378)
        at org.apache.hadoop.mapred.jobcontrol.JobControl.startReadyJobs(JobControl.java:247)
        at org.apache.hadoop.mapred.jobcontrol.JobControl.run(JobControl.java:279)
        at java.lang.Thread.run(Thread.java:619)
Caused by: org.apache.hadoop.mapreduce.lib.input.InvalidInputException: Input Pattern hdfs://<ServerName>.com/user/training/test/{20100810..20100813} matches 0 files
        at org.apache.hadoop.mapreduce.lib.input.FileInputFormat.listStatus(FileInputFormat.java:231)
        at org.apache.pig.backend.hadoop.executionengine.mapReduceLayer.PigTextInputFormat.listStatus(PigTextInputFormat.java:36)
        at org.apache.hadoop.mapreduce.lib.input.FileInputFormat.getSplits(FileInputFormat.java:248)
        at org.apache.pig.backend.hadoop.executionengine.mapReduceLayer.PigInputFormat.getSplits(PigInputFormat.java:258)
        ... 14 more



Pig Stack Trace
---------------
ERROR 2997: Unable to recreate exception from backend error: org.apache.pig.backend.executionengine.ExecException: ERROR 2118: Unable to create input splits for: hdfs://<ServerName>.com/user/training/test/{20100810..20100813}

org.apache.pig.impl.logicalLayer.FrontendException: ERROR 1066: Unable to open iterator for alias test
        at org.apache.pig.PigServer.openIterator(PigServer.java:521)
        at org.apache.pig.tools.grunt.GruntParser.processDump(GruntParser.java:544)
        at org.apache.pig.tools.pigscript.parser.PigScriptParser.parse(PigScriptParser.java:241)
        at org.apache.pig.tools.grunt.GruntParser.parseStopOnError(GruntParser.java:162)
        at org.apache.pig.tools.grunt.GruntParser.parseStopOnError(GruntParser.java:138)
        at org.apache.pig.tools.grunt.Grunt.run(Grunt.java:75)
        at org.apache.pig.Main.main(Main.java:357)
Caused by: org.apache.pig.backend.executionengine.ExecException: ERROR 2997: Unable to recreate exception from backend error: org.apache.pig.backend.executionengine.ExecException: ERROR 2118: Unable to create input splits for: hdfs://<ServerName>.com/user/training/test/{20100810..20100813}
        at org.apache.pig.backend.hadoop.executionengine.mapReduceLayer.Launcher.getStats(Launcher.java:169)

我是否需要使用 Python 等高级语言来捕获范围内的所有日期戳并将它们作为逗号分隔列表传递给 LOAD?

干杯

【问题讨论】:

标签: hadoop apache-pig


【解决方案1】:

正如zjffdu所说,路径扩展是由shell完成的。解决问题的一种常见方法是简单地使用 Pig 参数(无论如何,这是使脚本更可重复使用的好方法):

外壳:

pig -f script.pig -param input=/user/training/test/{20100810..20100812}

脚本.猪:

temp = LOAD '$input' USING SomeLoader() AS (...);

【讨论】:

  • 这根本不起作用,但它似乎可以起作用,因为 pig 具有令人震惊的命令行处理。您正在使用 bash 生成将调用 pig 的命令行。但它会扩展为pig -f script.pig -param input=/user/training/test/20100810 input=/user/training/test/20100811 input=/user/training/test/20100812(如果您想查看,请将pig 更改为echo)。只有第一个input= 前面是-param;其余的根本不是猪参数绑定。但是 pig 只是在第一个无法识别的input=... 处停止处理命令行参数,并且只运行第一个日期!
  • 你可以证明pig忽略了第二个input=...之后的所有内容,方法是使用带有第二个参数的pig脚本(比如output),并将-param output=...放在输入绑定之后。您收到关于 Undefined parameter : output 的错误消息。
【解决方案2】:

Pig 正在使用 hadoop 文件 glob 实用程序处理您的文件名模式,而不是 shell 的 glob 实用程序。 Hadoop 已记录在 here。如您所见,hadoop 不支持范围的 '..' 运算符。在我看来,您有两个选择 - 要么手动写出 {date1,date2,date2,...,dateN} 列表,如果这是一个罕见的用例,可能是要走的路,或者编写一个为您生成该列表的包装脚本。从日期范围构建这样的列表对于您选择的脚本语言来说应该是一项微不足道的任务。对于我的应用程序,我使用了生成的列表路由,它工作正常(CHD3 分发)。

【解决方案3】:

当我尝试在脚本中创建文件 glob 并将其作为参数传递给猪脚本时遇到问题。

目前的答案都不适用于我的情况,但我确实找到了一个可能在这里有用的一般答案。

在我的例子中,shell 扩展正在发生,然后将其传递到脚本中 - 导致 pig 解析器出现完全问题,这是可以理解的。

因此,只需将 glob 用双引号括起来,就可以保护它不被 shell 扩展,并将其按原样传递到命令中。

不会工作:

$ pig -f my-pig-file.pig -p INPUTFILEMASK='/logs/file{01,02,06}.log' -p OTHERPARAM=6

会工作

$ pig -f my-pig-file.pig -p INPUTFILEMASK="/logs/file{01,02,06}.log" -p OTHERPARAM=6

我希望这可以减轻一些痛苦和痛苦。

【讨论】:

    【解决方案4】:

    既然这样有效:

    temp = LOAD '/user/training/test/{20100810,20100811,20100812}' USING SomeLoader()
    

    但这不起作用:

    temp = LOAD '/user/training/test/{20100810..20100812}' USING SomeLoader()
    

    但是,如果您想要一个跨越 300 天的日期范围,并且将完整列表传递给 LOAD 至少可以说并不优雅。我想出了这个并且它有效。

    假设你要加载2012-10-08到今天2013-02-14的数据,你可以做的是

    temp = LOAD '/user/training/test/{201210*,201211*,201212,2013*}' USING SomeLoader()
    

    然后做一个过滤器

    filtered = FILTER temp BY (the_date>='2012-10-08')
    

    【讨论】:

    • 大括号语法中的通配符,例如“/test/{201210*, 201211*}”非常高效且易于实现
    【解决方案5】:
    temp = LOAD '/user/training/test/2010081*/*' USING SomeLoader() AS (...);
    load 20100810~20100819 data
    temp = LOAD '/user/training/test/2010081{0,1,2}/*' USING SomeLoader() AS (...);
    load 20100810~2010812 data
    

    如果变量位于文件路径的中间,则连接子文件夹名称或对所有文件使用“*”。

    【讨论】:

      【解决方案6】:

      我发现这个问题是由 linux shell 引起的。 Linux shell 助你扩展

       {20100810..20100812} 
      

        20100810 20100811 20100812, 
      

      然后你实际运行命令

      bin/hadoop fs -ls 20100810 20100811 20100812
      

      但在hdfs api中,它对你扩展表达式没有帮助。

      【讨论】:

        【解决方案7】:

        感谢戴夫·坎贝尔。 超出的一些答案是错误的,因为他们得到了一些选票。

        以下是我的测试结果:

        • 作品

          • pig -f test.pig -param input="/test_{20120713,20120714}.txt"
            • 表达式中的“,”前后不能有空格
          • pig -f test.pig -param input="/test_201207*.txt"
          • pig -f test.pig -param input="/test_2012071?.txt"
          • pig -f test.pig -param input="/test_20120713.txt,/test_20120714.txt"
          • pig -f test.pig -param input=/test_20120713.txt,/test_20120714.txt
            • 表达式中的“,”前后不能有空格
        • 没用

          • pig -f test.pig -param input="/test_{20120713..20120714}.txt"
          • pig -f test.pig -param input=/test_{20120713,20120714}.txt
          • pig -f test.pig -param input=/test_{20120713..20120714}.txt

        【讨论】:

          【解决方案8】:

          我是否需要使用 Python 等高级语言来捕获范围内的所有日期戳并将它们作为逗号分隔列表传递给 LOAD?

          您可能不知道 - 这可以使用自定义加载 UDF 来完成,或者尝试重新考虑您的目录结构(如果您的范围大部分是静态的,这将很有效)。

          另外:Pig 接受参数,也许这会对你有所帮助(也许你可以做一个函数来加载一天的数据并将其合并到结果集,但我不知道是否可能)

          编辑:可能编写简单的 python 或 bash 脚本来生成日期(文件夹)列表是最简单的解决方案,您只需将其传递给 Pig,这应该可以正常工作

          【讨论】:

          • 感谢 Wojtek。好吧,网格已经到位,更改目录结构是不可行的。我看到了, temp = LOAD '/user/training/test/{20100810,20100811,20100812}' USING SomeLoader() AS (...);并且 hadoop fs -ls /user/training/test/{20100810,20100811,20100812} 工作正常。 hadoop fs -ls /user/training/test/{20100810..20100812} 也可以,但是 temp = LOAD '/user/training/test/{20100810..20100812}' USING SomeLoader() AS (...);在转储温度或存储温度下失败。
          【解决方案9】:

          对于 Romain 的回答,如果您只想参数化日期,shell 将像这样运行:

          pig -param input="$(echo {20100810..20100812} | tr ' ' ,)" -f script.pig
          

          猪:

          temp = LOAD '/user/training/test/{$input}' USING SomeLoader() AS (...);
          

          请注意引号。

          【讨论】:

            【解决方案10】:

            Pig支持hdfs的地球状态,

            所以我认为pig 可以处理这种模式 /user/training/test/{20100810,20100811,20100812},

            你能粘贴错误日志吗?

            【讨论】:

            • 您好 zjffdu,我已将错误日志复制到问题中。谢谢
            【解决方案11】:

            这是我用来生成日期列表的脚本,然后将此列表放入 pig 脚本参数。非常棘手,但对我有用。

            例如:

            DT=20180101
            DT_LIST=''
            for ((i=0; i<=$DAYS; i++))
            do
                d=$(date +%Y%m%d -d "${DT} +$i days");
                DT_LIST=${DT_LIST}$d','
            done
            
            size=${#DT_LIST}
            DT_LIST=${DT_LIST:0:size-1}
            
            
            pig -p input_data=xxx/yyy/'${DT_LIST}' script.pig
            
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-12-08
              • 1970-01-01
              • 2023-04-06
              • 1970-01-01
              • 1970-01-01
              • 2020-02-28
              • 2013-11-09
              相关资源
              最近更新 更多