我在根据参数输入加载日志文件时遇到问题,并且想知道某人是否能够提供一些指导。有问题的日志是Omniture日志,基于年,月和日存储在子目录中(例如/ year = 2013 / month = 02 / day = 14),文件名中包含日期戳。对于任何一天,可能存在多个日志,每个数百MB。
我有一个Pig脚本,它目前处理整个月的日志,月份和年份指定为脚本参数(例如/ year = $ year / month = $ month / day = *)。它工作正常,我们对它很满意。也就是说,我们希望切换到每周处理日志,这意味着之前的LOAD路径glob将无法工作(周数可以包括几个月和几年)。为了解决这个问题,我有一个Python UDF,它需要一个开始日期并为一周的日志吐出必要的glob,例如:
>>> log_path_regex(2013, 1, 28)
'{year=2013/month=01/day=28,year=2013/month=01/day=29,year=2013/month=01/day=30,year=2013/month=01/day=31,year=2013/month=02/day=01,year=2013/month=02/day=02,year=2013/month=02/day=03}'
然后将这个glob插入适当的路径:
> %declare omniture_log_path 's3://foo/bar/$week_path/*.tsv.gz';
> data = LOAD '$omniture_log_path' USING OmnitureTextLoader(); // See http://github.com/msukmanowsky/OmnitureTextLoader
不幸的是,我不能为我的生活找出如何根据$ year,$ month和$ day脚本参数填充$ week_path。我尝试使用%declare但grunt抱怨,说它的日志,但从来没有:
> %declare week_path util.log_path_regex(year, month, day);
2013-02-14 16:54:02,648 [main] INFO org.apache.pig.Main - Apache Pig version 0.10.1 (r1426677) compiled Dec 28 2012, 16:46:13
2013-02-1416:54:02,648 [main] INFO org.apache.pig.Main - Logging error messages to: /tmp/pig_1360878842643.log % ls /tmp/pig_1360878842643.log
ls: cannot access /tmp/pig_1360878842643.log: No such file or directory
如果我在参数前加上美元符号或用带引号括起前缀参数,则会产生相同的错误。
如果我尝试使用define(我相信它只适用于静态Java函数),我会得到以下结果:
> define week_path util.log_path_regex(year, month, day);
2013-02-14 17:00:42,392 [main] ERROR org.apache.pig.tools.grunt.Grunt - ERROR 1200: <file script.pig, line 11, column 37> mismatched input 'year' expecting RIGHT_PAREN
与%declare一样,如果我在参数前加上美元符号或用带引号括起前缀参数,我会得到同样的错误。
我已经四处寻找并没有提出解决方案。我可能正在寻找错误的东西。调用shell命令可能会起作用,但是会很困难,因为它会使我们的脚本部署变得复杂,并且可能不可行,因为我们从S3而不是挂载的目录中检索日志。同样,将生成的glob作为单个参数传递可能会使实例化的MapReduce集群上的自动作业复杂化。
除了使用globs之外,还有一种很好的Pig友好方式来限制LOAD。也就是说,我仍然必须使用我的UDF,这似乎是问题的根源。
这真的归结为我希望在我的LOAD语句中包含一个在Pig内部构建的动态路径glob。猪似乎没那么容易。
我是否需要将UDF转换为静态Java方法?或者我会遇到同样的问题吗? (我不愿意这样做是偶然的。它是一个8行的Python函数,易于部署,并且比其他Java代码更易于维护。)
自定义LoadFunc是答案吗?有了这个,我可能必须指定/ year = / month = / day = *并强制Pig测试每个文件名以查找两个日期之间的日期戳。这似乎是一个巨大的黑客和浪费资源。
有什么想法吗?
答案 0 :(得分:2)
我posted this question to the Pig user list。我的理解是,在构建DAG之前,Pig将首先预处理其脚本以替换参数,导入和宏。这使得基于现有变量构建新变量有点不可能,并解释了我无法构建UDF来构造路径glob。
如果您是Pig开发人员,需要根据现有参数构建新变量,您可以使用另一个脚本构建这些变量并将它们作为参数传递给Pig脚本,或者您可以探索需要使用它们的位置新变量并根据您的需要在单独的构造中构建它们。
就我而言,我不情愿地选择创建a custom LoadFunc
as described by Cheolsoo Park。此LoadFunc
接受其构造函数中报表的句点开头的日,月和年,并构建pathGlob
属性以匹配该期间的路径。然后将pathGlob
插入setLocation()
中的某个位置。例如
/**
* Limit data to a week starting at given day. If day is 0, month is assumed.
*/
public WeeklyOrMonthlyTextLoader(String year, String month, String day) {
super();
pathGlob = getPathGlob(
Integer.parseInt(year),
Integer.parseInt(month),
Integer.parseInt(day)
);
}
/**
* Replace DATE_PATH in location with glob required for reading in this
* month or week of data. This assumes the following directory structure:
*
* <code>/year=>year</month=>month</day=>day</*</code>
*/
@Override
public void setLocation(String location, Job job) throws IOException {
location = location.replace(GLOB_PLACEHOLDER, pathGlob);
super.setLocation(location, job);
}
然后从Pig脚本中调用它,如下所示:
DEFINE TextLoader com.foo.WeeklyOrMonthlyTextLoader('$year', '$month', '$day');
请注意,构造函数接受String
,而不是int
。这是因为Pig中的参数是字符串,无法在Pig脚本中转换或转换为其他类型(在MR任务中使用时除外)。
虽然与包装脚本相比,创建自定义LoadFunc
可能看起来有些过分,但我希望解决方案是纯Pig,以避免在使用脚本之前强制分析师执行设置任务。在为预定作业创建Amazon MapReduce群集时,我还想在不同时期使用库存Pig脚本。