0

我在根据参数输入加载日志文件时遇到问题,想知道是否有人能够提供一些指导。有问题的日志是 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 集群上的自动化作业复杂化。

除了使用 glob 之外,还可能有一种对 Pig 友好的方式来限制 LOAD。也就是说,我仍然必须使用我的 UDF,这似乎是问题的根源。

这真的归结为我想在我的 LOAD 语句中包含一个内置在 Pig 中的动态路径 glob。猪似乎没有那么容易。

我需要将我的 UDF 转换为静态 Java 方法吗?或者我会遇到同样的问题吗?(如果它会起作用,我会犹豫不决。它是一个 8 行 Python 函数,与等效的 Java 代码相比,它易于部署并且更容易被其他人维护。)

自定义 LoadFunc 是答案吗?有了这个,我大概必须指定 /year= /month= /day=* 并强制 Pig 测试每个文件名的日期戳,它位于两个日期之间。这似乎是一个巨大的黑客攻击和资源浪费。

有任何想法吗?

4

1 回答 1

2

将此问题发布到 Pig 用户列表。我的理解是,在构建 DAG 之前,Pig 将首先预处理其脚本以替换参数、导入和宏。这使得基于现有变量构建新变量有点不可能,并解释了我未能构建 UDF 来构建路径 glob。

如果您是 Pig 开发人员,需要基于现有参数构建新变量,您可以使用另一个脚本来构建这些变量并将它们作为参数传递给您的 Pig 脚本,或者您可以探索需要在哪里使用这些新变量并根据您的需要将它们构建在单独的构造中。

就我而言,我不情愿地选择创建Cheolsoo Park 所描述的自定义LoadFunc。这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=&gt;year&lt;/month=&gt;month&lt;/day=&gt;day&lt;/*</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 脚本。

于 2013-02-22T17:02:38.840 回答