Pig Latin:从日期范围加载多个文件(目录结构的一部分)

时间:2010-08-18 18:39:39

标签: hadoop apache-pig

我有以下情况 -

猪版本使用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}

但是当我在猪脚本中尝试使用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?

欢呼声

11 个答案:

答案 0 :(得分:31)

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

壳:

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

script.pig:

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

答案 1 :(得分:21)

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

答案 2 :(得分:10)

当我在尝试在脚本中创建文件glob然后将其作为参数传递到pig脚本时,我遇到了这个答案。

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

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

因此,简单地用双引号括起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

我希望这可以为某些人带来痛苦和痛苦。

答案 3 :(得分:6)

因此,这有效:

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')

答案 4 :(得分:4)

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

 {20100810..20100812} 

  20100810 20100811 20100812, 

然后你实际上运行命令

bin/hadoop fs -ls 20100810 20100811 20100812

但是在hdfs api中,它无法帮助您扩展表达式。

答案 5 :(得分:4)

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)

感谢戴维坎贝尔。 由于他们获得了一些选票,因此其中一些答案是错误的。

以下是我的测试结果:

  • 作品

    • 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

答案 7 :(得分:1)

  

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

可能你没有 - 这可以使用自定义Load UDF来完成,或者尝试重新思考你的目录结构(如果你的范围大多是静态的,这将很好用。)

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

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

答案 8 :(得分:1)

对于Romain的回答,如果你只想参数化日期,那么shell会像这样运行:

clc
applicationCompiler -package yourProject.prj
cmdWinDoc = com.mathworks.mde.cmdwin.CmdWinDocument.getInstance;
% loop until condition found
while true
  pause ( 2 )
  myTxt = cmdWinDoc.getText(cmdWinDoc.getStartPosition.getOffset,cmdWinDoc.getLength);
  %
  if ~isempty ( strfind ( myTxt, 'Package finished' ) )
    fprintf ( 'Woo hoo - it worked!!! :)\n' );
    break
  end
  if ~isempty ( strfind ( myTxt, 'Package failed' ) )
    fprintf ( 'Uh oh - it failed!!! :)\n' );
    break
  end
end

猪:

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

请注意引号。

答案 9 :(得分:0)

Pig支持hdfs的全球状态,

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

可以粘贴错误日志吗?

答案 10 :(得分:0)

这是我用来生成日期列表的脚本,然后将该列表放入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