如何在Pig中转换参数?

时间:2014-09-10 15:08:30

标签: hadoop apache-pig oozie oozie-coordinator

我需要处理Pig中的数据集,该数据集每天午夜一次。因此,我有一个Oozie协调员负责日程安排,每天00:00生成一个工作流程。 文件名遵循URI方案

hdfs://${dataRoot}/input/raw${YEAR}${MONTH}${DAY}${HOUR}.avro

其中$ {HOUR}始终为'00'。

数据集中的每个条目都包含一个UNIX时间戳,我想过滤掉那些在晚上11:45(23:45)之前有时间戳的条目。由于我需要运行过去的数据集,因此需要根据当前处理的日期动态设置定义阈值的时间戳的值。例如,从2013年12月12日开始处理数据集需要阈值1418337900.因此,设置阈值必须由协调员完成。

据我所知,不可能将格式化日期转换为EL中的UNIX时间戳。我提出了一个相当hacky的解决方案: 协调器将阈值的日期和时间传递给相应的工作流,该工作流启动Pig脚本的参数化实例。

coordinator.xml的摘录:

<property>
    <name>threshold</name>
    <value>${coord:formatTime(coord:dateOffset(coord:nominalTime(), -15, 'MINUTE'), 'yyyyMMddHHmm')}</value>
</property>

workflow.xml的摘录:

<action name="foo">
    <pig>
        <job-tracker>${jobTracker}</job-tracker>
        <name-node>${nameNode}</name-node>
        <script>${applicationPath}/flights.pig</script>
        <param>jobInput=${jobInput}</param>
        <param>jobOutput=${jobOutput}</param>
        <param>threshold=${threshold}</param>
    </pig>
    <ok to="end"/>
    <error to="error"/>
</action>

Pig脚本需要将此格式化日期时间转换为UNIX时间戳。因此,我写了一个UDF:

public class UnixTime extends EvalFunc<Long> {

    private long myTimestamp = 0L;

    private static long convertDateTime(String dt, String format)
            throws IOException {
        DateFormat formatter;
        Date date = null;
        formatter = new SimpleDateFormat(format);
        try {
            date = formatter.parse(dt);
        } catch (ParseException ex) {
            throw new IOException("Illegal Date: " + dt + " format: " + format);
        }
        return date.getTime() / 1000L;
    }

    public UnixTime(String dt, String format) throws IOException {
        myTimestamp = convertDateTime(dt, format);
    }

    @Override
    public Long exec(Tuple input) throws IOException {
        return myTimestamp;
    }

}

在Pig脚本中,创建一个宏,使用协调器/工作流的输入初始化UDF。然后,您可以过滤时间戳。

DEFINE THRESH mystuff.pig.UnixTime('$threshold', 'yyyyMMddHHmm');
d = LOAD '$jobInput' USING PigStorage(',') AS (time: long, value: chararray);
f = FILTER d BY d <= THRESH();
...

如果可以在Pig中转换输入参数并将其再次用作某种常量,那么我遇到的问题就引出了更普遍的问题。 有没有更好的方法来解决这个问题,还是我的方法不必要地复杂化了?

编辑:TL; DR

经过多次搜索,我发现有人遇到同样的问题: http://grokbase.com/t/pig/user/125gszzxnx/survey-where-are-all-the-udfs-and-macros

感谢Gaurav在皮卡中推荐UDF。 如果没有使用 declare 和shell脚本,似乎没有高性能的解决方案。

1 个答案:

答案 0 :(得分:0)

您可以将Pig脚本放入Python脚本并传递值。

#!/usr/bin/python
import sys
import time

from org.apache.pig.scripting import Pig



P = Pig.compile("""d = LOAD '$jobInput' USING PigStorage(',') AS (time: long, value: chararray);
f = FILTER d BY d <= '$thresh';
""")

jobinput = {whatever you defined}
thresh = {whatever you defined in the UDF}
Q = P.bind({'thresh':thresh,'jobinput':jobinput})
results = Q.runSingle()
if results.isSuccessful() == "FAILED":
         raise "Pig job failed"