1

我有一个猪脚本,其代码如下:

scores = LOAD 'file' as (id:chararray, scoreid:chararray, score:int);
scoresGrouped = GROUP scores by id;
top10s = foreach scoresGrouped{
    sorted = order scores by score DESC;
    sorted10 = LIMIT sorted 10;
    GENERATE group as id, sorted10.scoreid as top10candidates;
};

它给了我一个像

 id1, {(scoreidA),(scoreidB),(scoreIdC)..(scoreIdFoo)}

但是,我也希望包含项目的索引,所以我会得到类似的结果

 id1, {(scoreidA,1),(scoreidB,2),(scoreIdC,3)..(scoreIdFoo,10)}

是否可以在嵌套的 foreach 中以某种方式包含索引,或者我必须编写自己的 UDF 以在之后添加它?

4

2 回答 2

2

您将需要一个 UDF,其唯一参数是您要为其添加排名的排序包。我以前也有同样的需求。这是为您节省一点时间的 exec 函数:

public DataBag exec(Tuple b) throws IOException {
    try {
        DataBag bag = (DataBag) b.get(0);
        Iterator<Tuple> it = bag.iterator();
        while (it.hasNext()) {
            Tuple t = (Tuple)it.next();
            if (t != null && t.size() > 0 && t.get(0) != null) {
                t.append(n++);
            }
            newBag.add(t);
        }
    } catch (ExecException ee) {
        throw ee;
    } catch (Exception e) {
        int errCode = 2106;
        String msg = "Error while computing item number in " + this.getClass().getSimpleName();
        throw new ExecException(msg, errCode, PigException.BUG, e);           
    }

    return newBag;
}

(计数器n被初始化为exec函数外部的类变量。)

您还可以实现Accumulator 接口,即使您的整个包不适合内存,您也可以这样做。( COUNT 内置函数就是这样做的。)只要确保n = 1L;cleanup()方法和return newBag;in 中设置getValue(),其他一切都是一样的。

于 2012-12-21T14:14:19.120 回答
2

对于包中的索引元素,您可以使用来自 LinkedIn 的DataFu项目的Enumerate UDF:

register '/path_to_jar/datafu-0.0.4.jar';
define Enumerate datafu.pig.bags.Enumerate('1');
scores = ...
...
result = foreach top10s generate id, Enumerate(top10candidates);
于 2012-12-22T14:26:51.517 回答