我有一个如下所示的数据集:
foo,R foo,Y bar,C foo,R baz,Y foo,R baz,Y baz,R ...
我想生成一个报告,总结第一列中每个唯一值的“R”,“Y”和“C”记录的数量。对于此数据集,它看起来像:
foo,3,1,0 bar,0,0,1 baz,1,2,0
第二列是'R'记录的数量,第三列是'Y'记录的数量,最后一列是'C'记录的数量。
我知道我可以先按记录类型,组和聚合进行过滤,但这会导致三个子报告的昂贵连接。我宁愿组一次并生成我组中的每个{R,Y,C}列。
如何将我的数据集中第二列与“R”,“Y”或“C”进行比较的布尔结果转换为我可以聚合的数值?理想情况下,我希望1匹配,0匹配三列中的每一列不匹配。
答案 0 :(得分: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之后,每个值都有一个包含R,Y,C类所有行的BAG。在FOREACH中使用FILTER我们创建3个单独的BAG(每个R,Y,C一个),GENERATE中的SIZE(bag)计算每个包中的行数。
您可能遇到的唯一问题是当val列中存在太多具有相同值的行时,因为嵌套的FOREACH依赖于内存操作,并且产生的中间BAG可能会变得非常大。如果您开始获得与内存相关的异常,那么您可以从How to handle spill memory in pig启发。我们的想法是使用2个GROUP BY操作,第一个用于获取每个(val,cat)的计数,第二个用于绕R转动R,Y,C,从而避免了昂贵的JOIN操作(参见Pivoting in Pig)。 p>
关于BOOLEAN的问题:我使用了bincond运算符。 如果你不需要计数,你可以使用IsEmpty(bag)而不是SIZE(bag),它会稍微快一点,以获得你的0和1转换。