如何动态获取Pig中组内的前N%记录

时间:2013-10-03 21:21:47

标签: dynamic hadoop apache-pig sampling

我有一个问题,我不确定如何解决猪。我有一个关于Hadoop的数据集(大约400万条记录),其中包含按产品类别划分的产品标题。每个标题都有。它出现在网页上的次数,没有。有点被点击进入产品详细信息页面。没有。产品类别中的标题可能有所不同。

示例数据 -

视频游戏|光环4 | 5400 | 25
视频游戏| Forza Motorsport 4 Limited珍藏版| 6000 | 10
电子游戏| Marvel Ultimate Alliance | 2000 | 55
相机&照片|适用于GoPro HD的Steadicam | 12000 | 250
相机&照片| Hero GoPro Motorsports 1080P宽高清5MP头盔相机| 10000 | 125

我希望根据第3列(网页上的外观)获得每个产品类别中的前N%记录。但是,N%必须根据类别的重量/重要性而变化。例如。对于视频游戏,我希望获得前15%的记录;适用于相机和相机照片,我想获得前5%,等等。有没有办法在Pig中嵌套的FOREACH代码块中的LIMIT子句中动态设置%或Integer值?

PRODUCT_DATA = LOAD '<PRODUCT FILE PATH>' USING PigStorage('|') AS (categ_name:chararray, product_titl:chararray, impression_cnt:long, click_through_cnt:long);

GRP_PROD_DATA = GROUP PRODUCT_DATA BY categ_name;

TOP_PROD_LIST = FOREACH GRP_PROD_DATA {

                  SORTED_TOP_PROD = ORDER PRODUCT_DATA BY impression_cnt DESC;
                  SAMPLED_DATA = LIMIT SORTED_TOP_PROD <CATEGORY % OR INTEGER VALUE>;
                  GENERATE flatten(SAMPLED_DATA);
                }

STORE TOP_PROD_TITLE_LIST INTO '<SOME PATH>' USING PigStorage('|');

如何动态(按类别)设置给定组的%或整数值?我想过使用MACRO但是不能从NESTED FOREACH块中调用MACROS。我可以编写一个UDF,它将类别名称作为参数,并输出%OR INTEGER值,并从LIMIT操作调用此UDF吗?

SAMPLED_DATA = LIMIT SORTED_TOP_PROD categLimitVal(categ_name);

有什么建议吗?我使用的是版本0.10的Pig。

2 个答案:

答案 0 :(得分:0)

这样的事可能有用。但是,我从来没有需要在Pig地图中查找变量键,并且this other SO question没有答案,所以你需要做一些试验和错误才能使它工作:

--Load your dynamic percentages as a map
A = LOAD 'percentages' AS (categ_name:chararray, perc:float);
PERCENTAGES = FOREACH A GENERATE TOMAP(categ_name, perc);

PRODUCT_DATA = LOAD ...;
GRP_PROD_DATA = GROUP PRODUCT_DATA BY categ_name;

--Count the elements per group; needed to calculate pecentages
C = FOREACH GRP_PROD_DATA generate FLATTEN(group) AS categ_name, COUNT(*) as count;
c_MAP = FOREACH C GENERATE TOMAP(categ_name, count);

TOP_PROD_LIST = FOREACH GRP_PROD_DATA {
    SORTED_TOP_PROD = ORDER PRODUCT_DATA BY impression_cnt DESC;
    SAMPLED_DATA = LIMIT SORTED_TOP_PROD (C_MAP#group * PERCENTAGES#group);
    GENERATE flatten(SAMPLED_DATA);
}

您也可以尝试使用Pig's TOP功能代替ORDER + LIMIT

答案 1 :(得分:0)

我想我用一种稍微不同的方法来解决它。我不确定它是如何优化的,也许有更好的方法来组织/优化脚本。基本上,如果我按照ASC展示次数的顺序对每个类别中的产品标题进行排名,并在该类别的RANK&lt; = SAMPLE LIMIT时进行过滤,那么我可以模拟动态抽样。 SAMPLE LIMIT只是每个类别COUNT每个类别定义的PERCENT WEIGHT * RANK。对于ENUMERATE元组,我正在利用LinkedIn提供REGISTER '/tmp/udf/datafu-1.0.0.jar'; define Enumerate datafu.pig.bags.Enumerate('1'); set default_parallel 10; LKP_DATA = LOAD '/tmp/lkp.dat' USING PigStorage('|') AS (categ_name:chararray, perc:float); PRODUCT_DATA = LOAD '/tmp/meta.dat' USING PigStorage('|') AS (categ_name:chararray, product_titl:chararray, impression_cnt:long, click_through_cnt:long); GRP_PROD_DATA = GROUP PRODUCT_DATA BY categ_name; CATEG_COUNT = FOREACH GRP_PROD_DATA generate FLATTEN(group) AS categ_name, COUNT(PRODUCT_DATA) as cnt; CATEG_JOINED = JOIN CATEG_COUNT BY categ_name, LKP_DATA BY categ_name USING 'replicated'; CATEG_PERCENT = FOREACH CATEG_JOINED GENERATE CATEG_COUNT::categ_name AS categ_name, CATEG_COUNT::cnt AS record_cnt, LKP_DATA::perc AS percentage; PRCNT_PROD_DATA = JOIN PRODUCT_DATA BY categ_name, CATEG_PERCENT BY categ_name; PRCNT_PROD_DATA = FOREACH PRCNT_PROD_DATA GENERATE PRODUCT_DATA::categ_name AS categ_name, PRODUCT_DATA::product_titl AS product_titl, PRODUCT_DATA::impression_cnt AS impression_cnt, PRODUCT_DATA::click_through_cnt AS click_through_cnt, CATEG_PERCENT::record_cnt*CATEG_PERCENT::percentage AS sample_size; GRP_PRCNT_PROD_DATA = GROUP PRCNT_PROD_DATA BY categ_name; ORDRD_PROD_LIST = FOREACH GRP_PRCNT_PROD_DATA { SORTED_TOP_PROD = ORDER PRCNT_PROD_DATA BY impression_cnt DESC; GENERATE flatten(SORTED_TOP_PROD); } GRP_PROD_LIST = GROUP ORDRD_PROD_LIST BY categ_name; GRP_PRCNT_PROD_DATA = FOREACH GRP_PROD_LIST GENERATE flatten(Enumerate(ORDRD_PROD_LIST)) AS (categ_name, product_titl, impression_cnt, click_through_cnt, sample_size, rnk); SAMPLED_DATA = FILTER GRP_PRCNT_PROD_DATA BY rnk <= sample_size; SAMPLED_DATA = FOREACH SAMPLED_DATA GENERATE categ_name, product_titl, impression_cnt, click_through_cnt, rnk; DUMP SAMPLED_DATA; UDF的DataFu开源jar。

同样,如果有人提出改进/更好地组织代码的建议,我很满意:)感谢您输入Cabad,它真的有帮助!

脚本:

{{1}}