2

我有一个如下所示的数据集:

富,R
富,Y
酒吧,C
富,R
巴兹,Y
富,R
巴兹,Y
巴兹,R
...

我想生成一个报告,总结第一列中每个唯一值的“R”、“Y”和“C”记录的数量。对于这个数据集,它看起来像:

富,3,1,0
酒吧,0,0,1
baz,1,2,0

其中第二列是“R”记录的数量,第三列是“Y”记录的数量,最后是“C”记录的数量。

我知道我可以先按记录类型、组和聚合进行过滤,但这会导致三个子报告的连接成本很高。我宁愿分组一次并生成我组中的每个 {R, Y, C} 列。

如何将比较数据集中第二列与“R”、“Y”或“C”的布尔结果转换为我可以聚合的数值?理想情况下,我希望 1 表示匹配,0 表示三列中的每一列不匹配。

4

1 回答 1

2

Apache PIG 非常适合此类问题。可以用一个 GROUP BY 和一个嵌套 FOREACH 解决

inpt = load '~/pig/data/group_pivot.csv' using PigStorage(',') as (val : chararray, cat : chararray);
grp = group inpt by (val);
final = foreach grp {
    rBag = filter inpt by cat == 'R';
    yBag = filter inpt by cat == 'Y';
    cBag = filter inpt by cat == 'C';
    generate flatten(group) as val, SIZE(rBag) as R, SIZE(yBag) as Y, SIZE(cBag) as C;
};

dump final;
--(bar,0,0,1)
--(baz,1,2,0)
--(foo,3,1,0)

bool = foreach final generate val, (R == 0 ? 0 : 1) as R, (Y == 0 ? 0 : 1) as Y, (C == 0 ? 0 : 1) as C;

dump bool;
--(bar,0,0,1)
--(baz,1,1,0)
--(foo,1,1,0)

我已经在您的示例中进行了尝试,并得到了预期的结果。这个想法是,在 GROUP BY 之后,每个值都有一个 BAG,其中包含所有具有 R、Y、C 类别的行。使用 FOREACH 中的 FILTER,我们创建了 3 个单独的 BAG(每个 R、Y、C 一个),并且 GENERATE 中的 SIZE(bag) 计算每个包中的行数。

您可能遇到的唯一问题是当 val 列中具有相同值的行太多时,因为嵌套的 FOREACH 依赖于内存操作,并且生成的中间 BAG 可能会变得非常大。如果您开始获得与内存相关的异常,那么您可以从How to handle splash memory in pig 中获得启发。想法是使用 2 个 GROUP BY 操作,第一个获取每个 (val, cat) 的计数,第二个以 val 为中心旋转 R、Y、C,从而避免昂贵的 JOIN 操作(请参阅Pivoting in Pig)。

关于 BOOLEAN 的问题:我使用了 bincond 运算符。如果您不需要计数,您可以使用 IsEmpty(bag) 而不是 SIZE(bag),它会稍微快一些并且 bincond 来获得您的 0 和 1 转换。

于 2012-08-21T08:40:05.870 回答