代码之家  ›  专栏  ›  技术社区  ›  Arnkrishn

pig拉丁语:从一个日期范围(目录结构的一部分)加载多个文件

  •  29
  • Arnkrishn  · 技术社区  · 14 年前

    我有以下场景-

    清管器版本使用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。

    我可以将日期范围的“从”和“到”作为参数传递给pig脚本,但如何在LOAD语句中使用这些参数。我能做到以下几点

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

    以下内容适用于Hadoop:

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

    但当我在pig脚本中尝试加载时,它失败了。如何利用传递给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)来捕获范围内的所有日期戳,并将它们作为逗号分隔的列表传递给加载?

    干杯

    10 回复  |  直到 7 年前
        1
  •  21
  •   TehShrike    11 年前

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

        2
  •  31
  •   Romain    14 年前

    正如ZJFFDU所说,路径扩展是由shell完成的。解决问题的一种常见方法是简单地使用pig参数(这是使脚本更具可恢复性的一种好方法):

    壳牌:

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

    猪:

    temp = LOAD '$input' USING SomeLoader() AS (...);
    
        3
  •  10
  •   Jay D    13 年前

    当我在脚本中创建文件glob时遇到了这个问题,然后将它作为参数传递到pig脚本中。

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

    在我的例子中,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
  •  6
  •   om-nom-nom Dennis Williamson    11 年前

    因此,既然这样做有效:

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

    但这不起作用:

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

    但是,如果您想要一个跨越300天的日期范围,并且通过一个完整的列表来加载,那么至少说是不优雅的。我想出了这个办法,它奏效了。

    假设您要将数据从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')
    
        5
  •  4
  •   balduran    13 年前
    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
  •  4
  •   Jay D    13 年前

    我发现这个问题是由Linuxshell引起的。Linux shell将帮助您扩展

     {20100810..20100812} 
    

      20100810 20100811 20100812, 
    

    然后你实际运行命令

    bin/hadoop fs -ls 20100810 20100811 20100812
    

    但在 hdfs api ,它不会帮助您扩展表达式。

        7
  •  4
  •   OneCricketeer Gabriele Mariotti    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
  •  1
  •   wlk    14 年前

    我是否需要使用更高级的语言(如python)来捕获范围内的所有日期戳,并将它们作为逗号分隔的列表传递给加载?

    可能您没有-这可以使用自定义加载UDF来完成,或者尝试重新考虑目录结构(如果您的范围主要是静态的,这将很好地工作)。

    另外:pig接受参数,也许这对您有帮助(也许您可以做一个函数,将数据从一天内加载并合并到结果集,但我不知道是否可能)

    编辑:也许编写生成日期列表(文件夹)的简单python或bash脚本是最简单的解决方案,您不必将其传递给pig,这应该可以很好地工作。

        9
  •  1
  •   Datalicious    9 年前

    对于Romain的答案,如果您只想参数化日期,shell的运行方式如下:

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

    猪:

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

    请注意报价。

        10
  •  0
  •   Jay D    13 年前

    Pig 支持全球状态 hdfs ,

    所以我想 pig 可以处理模式 /user/training/test/{20100810,20100811,20100812} ,

    你能粘贴错误日志吗?