Alexandre Krabbe
Alexandre Krabbe

Reputation: 771

How to get a SQL like GROUP BY using Apache Pig?

I have the following input called movieUserTagFltr:

(260,{(260,starwars),(260,George Lucas),(260,sci-fi),(260,cult classic),(260,Science Fiction),(260,classic),(260,supernatural powers),(260,nerdy),(260,Science Fiction),(260,critically acclaimed),(260,Science Fiction),(260,action),(260,script),(260,"imaginary world),(260,space),(260,Science Fiction),(260,"space epic),(260,Syfy),(260,series),(260,classic sci-fi),(260,space adventure),(260,jedi),(260,awesome soundtrack),(260,awesome),(260,coming of age)})
(858,{(858,Katso Sanna!)})
(924,{(924,slow),(924,boring)})
(1256,{(1256,Marx Brothers)})

it follows the schema: (movieId:int, tags:bag{(movieId:int, tag:cararray),...})

Basically the first number represents a movie id, and the subsequent bag holds all the keywords associated with that movie. I would like to group those key words in such way that I would have an output something like this:

(260,{(1,starwars),(1,George Lucas),(1,sci-fi),(1,cult classic),(4,Science Fiction),(1,classic),(1,supernatural powers),(1,nerdy),(1,critically acclaimed),(1,action),(1,script),(1,"imaginary world),(1,space),(1,"space epic),(1,Syfy),(1,series),(1,classic sci-fi),(1,space adventure),(1,jedi),(1,awesome soundtrack),(1,awesome),(1,coming of age)})
(858,{(1,Katso Sanna!)})
(924,{(1,slow),(1,boring)})
(1256,{(1,Marx Brothers)})

Note that the tag Science Fiction has appeared 4 times for the movie with id 260. Using the GROUP BY and COUNT I manged to count the distinct keywords for each movie using the following script:

sum = FOREACH group_data { 
    unique_tags = DISTINCT movieUserTagFltr.tags::tag;
    GENERATE group, COUNT(unique_tags) as tag;
};

But that only returns a global count, I want a local count. So the logic of what I was thinking was:

result = iterate over each tuple of group_data {
    generate a tuple with $0, and a bag with {
        foreach distinct tag that group_data has on it's $1 variable do {
            generate a tuple like: (tag_name, count of how many times that tag appeared on $1)
        }
    }
}

Upvotes: 0

Views: 48

Answers (1)

savagedata
savagedata

Reputation: 722

You can flatten out your original input so that each movieID and tag are their own record. Then group by movieID and tag to get a count for each combination. Finally, group by movieID so that you end up with a bag of tags and counts for each movie.

Let's say you start with movieUserTagFltr with the schema you described:

A = FOREACH movieUserTagFltr GENERATE FLATTEN(tags) AS (movieID, tag);
B = GROUP A BY (movieID, tag);
C = FOREACH B GENERATE
    FLATTEN(group) AS (movieID, tag),
    COUNT(A) AS movie_tag_count;
D = GROUP C BY movieID;

Your final schema is:

D: {group: int,C: {(movieID: int,tag: chararray,movie_tag_count: long)}}

Upvotes: 2

Related Questions