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

Dynamic 如何在Pig中动态获取组内前N%记录,dynamic,hadoop,apache-pig,sampling,Dynamic,Hadoop,Apache Pig,Sampling,我有一个问题,我不知道如何解决在猪。我有一个关于Hadoop的数据集(大约400万条记录),其中包含按产品类别划分的产品标题。每个标题都有它在网页上显示的次数,以及点击它进入产品详细信息页面的次数。产品类别中的标题数量可能会有所不同 样本数据- 电子游戏|光环4 | 5400 | 25 电子游戏| Forza Motorsport 4限量珍藏版| 6000 | 10 电子游戏|惊奇漫画终极联盟| 2000 | 55 照相机和照片|适用于GoPro HD的Pro Steadicam | 12000

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

样本数据-

电子游戏|光环4 | 5400 | 25
电子游戏| Forza Motorsport 4限量珍藏版| 6000 | 10
电子游戏|惊奇漫画终极联盟| 2000 | 55
照相机和照片|适用于GoPro HD的Pro Steadicam | 12000 | 250
照相机和照片| Hero GoPro Motorsports 1080P宽高清5MP头盔照相机| 10000 | 125

我想根据第3列(在网页上的出现情况)获得每个产品类别中前N%的记录。但是,N%必须根据类别的权重/重要性而变化。对于视频游戏,我想获得前15%的记录;对于Camera&Photo,我想得到前5%的值,等等。有没有办法在Pig中的嵌套FOREACH代码块中动态设置LIMIT子句中的%或整数值

PRODUCT_DATA=LOAD'',使用PigStorage(“|”)作为(类别名称:chararray,产品标题:chararray,impression_cnt:long,单击链接至长链接)

GRP\u PROD\u DATA=按类别名称分组产品数据

TOP\u PROD\u LIST=FOREACH GRP\u PROD\u 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);
                }
SORTED_TOP_PROD=按印象描述订购产品数据;
采样数据=已排序的上限产品;
生成展平(采样的_数据);
}
使用PigStorage(“|”)将顶部产品标题列表存储到“”

如何动态(按类别)设置给定组的%或整数值?我曾想过使用宏,但不能从嵌套的FOREACH块中调用宏。我是否可以编写一个以类别名称为参数的UDF,并输出%或整数值,然后通过限制操作调用此UDF

SAMPLED_DATA=LIMIT SORTED_TOP_PROD categLimitVal(类别名称)


有什么建议吗?我正在使用Pig的0.10版。

类似的东西可能会起作用。但是,我从来没有必要在Pig映射中查找变量键,也没有答案,因此您需要进行一些尝试和错误操作才能使其正常工作:

--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);
}

您也可以尝试使用函数而不是
顺序
+
限制

我想我用了一种稍微不同的方法解决了这个问题。我不确定它有多优化,也许有更好的方法来组织/优化脚本。基本上,如果我在
ASC
印象计数和过滤的顺序中对每个类别中的产品标题进行排序,当
rank
时,您可以使用Hadoop streaming并将
LIMIT
行替换为通过“awk…”排序的
STREAM\u TOP\u PROD。然而,我建议您重新考虑您的用例,因为为了能够获得前%的记录,您需要首先对它们进行计数(或者将它们全部保存在awk脚本的内存中),然后根据类别到百分比的映射来获取前%的记录。这是一种反MapReduce。Top X值处理速度快;顶部Y%不是。谢谢你回答我的问题。不幸的是,我尝试了上述方法,但没有成功。LIMIT只允许整数或标量表达式。它不允许引用关系中的另一列。在这种情况下,限制和顶部都不起作用。不知道我还能尝试什么。猪允许,所以这样做可以解决你的问题。或者,我在对您的问题的评论中建议的
awk
解决方案肯定会起作用。快速评论:如果切换到Pig 0.11,您可以使用
RANK
运算符,而不是Enumerate UDF。
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;