Pig 10.0 - group the tuples and merge bags in a foreach

apache-pig, hadoop

Solution

I finally managed to achieve the wanted behavior. A self contained example of my solution follows:

Data file:

a       b       1
a       b       2
a       b       3
a       b       4
a       d       1
a       b       3
a       b       6
a       e       7
z       b       1
z       b       2
z       b       3

Code:

-- Prepare data
in = LOAD 'data' USING PigStorage() 
        AS (One:chararray, Two:chararray, Id:long);

grp = GROUP in by (One, Two);
cnt = FOREACH grp {
        ids = DISTINCT in.Id;
        GENERATE
                ids        as Ids,
                group.One  as One,
                group.Two  as Two,
                COUNT(ids) as Count;
}       

-- Interesting code follows
grp2 = GROUP cnt by One;
cnt2 = FOREACH grp2 {
        ids = FOREACH cnt.Ids generate FLATTEN($0);
        GENERATE
                ids  as Ids,
                group      as One,
                COUNT(ids) as Count;
}               

describe cnt2;
dump grp2;
dump cnt2;

Describe:

Cnt: {Ids: {(Id: long)},One: chararray,Two: chararray,Count: long}

grp2:

(a,{({(1),(2),(3),(4),(6)},a,b,5),({(1)},a,d,1),({(7)},a,e,1)})
(z,{({(1),(2),(3)},z,b,3)})

cnt2:

({(1),(2),(3),(4),(6),(1),(7)},a,7)
({(1),(2),(3)},z,3)

Since the code uses a FOREACH nested in a FOREACH it requires Pig > 10.0.

I will let the question as unresolved for a few days since a cleaner solution probably exists.

Problem

I'm using `Pig 10.0`. I want to Merge bags in a foreach. Let's say I have the following `visitors` alias: ``` (a, b, {1, 2, 3, 4}), (a, d, {1, 3, 6}), (a, e, {7}), (z, b, {1, 2, 3}) ``` I want to group the tuples on the first field and merge the bags with a set semantic to get the following following tuples: ``` ({1, 2, 3, 4, 6, 7}, a, 6) ({1, 2, 3}, z, 3) ``` The first field is the union of the bags with a set semantic. The second field of the tuple is the group field. The third field is the number items in the bag. I tried several variations around the following code (replaced SetUnion by Group/Distinct etc.) but always failed to achieve the wanted behavior: ``` DEFINE SetUnion datafu.pig.bags.sets.SetUnion(); grouped = GROUP visitors by (FirstField); merged = FOREACH grouped { VU = SetUnion(visitors.ThirdField); GENERATE VU as Vu, group as FirstField, COUNT(VU) as Cnt; } dump merged; ``` Can you explain where I'm wrong and how to implement the desired behavior?

Original source