在Hadoop集群上使用Pig,我有一个巨大的bag
巨大的tuples
我经常添加字段,因为我继续在这个项目上工作,以及几个使用它的各种字段的UDF 。我希望能够在每个tuple
的几个字段上调用UDF,并且将结果重新连接到该特定元组。使用唯一ID进行连接以重新连接记录将永远占用数十亿条记录。
我认为在GENERATE
语句中应该有一种方法可以做到这一点,但我找不到合适的语法。
以下是使用Python UDF获取想法的玩具代码。
Register 'jumper.py' using jython as myfuncs;
jumps = LOAD 'jumps.csv' USING PigStorage(',')
AS (jumper:int, attempt:int, distance:double, location:chararray);
byJumper = GROUP jumps by jumper;
sigmas = FOREACH byJumper GENERATE
jumps.jumper, jumps.attempt, jumps.distance, jumps.location,
myfuncs.conv2sigma(jumps.distance);
rmf sigmas
STORE sigmas INTO 'sigmas' USING PigStorage(',');
这是在每个元组中生成包含单个字段的元组,而不是我期望的形式的元组。
输入数据
对于每次跳跃,我们想要生成跳线与其平均值有多少标准差(sigma),然后我们将按位置关联sigma以查看跳线在哪里做得最好。我们需要计算每个人的平均值和标准差,然后计算每次跳转的“sigma”,并将数据与附加的新sigma字段一起存储。
问题是:
我们如何将其更改为输出
(jumper:int, attempt:int, distance:double, location:chararray, sigma:double)
等元组?
我已经以各种方式尝试过FLATTEN
,它只会给我带来巨大的交叉产品。我可以更改我的UDF以接受跳线并尝试输出三元组然后执行JOIN
,但在现实世界中,由于数据集的大小,此解决方案非常不切实际。
如果您想在家中试用,这是支持代码和数据:
jumper.py :(一个快速,不深思熟虑的实现 - 这里唯一重要的是它需要一个包输入并产生一个包输出,其中一个输出元组对应于每个输入元组)
#!/usr/local/bin/python
# we're forced to use python 2.5.2 :-(
from math import sqrt
@outputSchema("y:bag{t:tuple(sigma:double)}")
def conv2sigma(bag):
s = 0.0
n = 0
dd = []
print('conv2sigma input bag:')
print(bag)
for word in bag:
d = float(word[0])
dd.append(d)
n += 1
s += d
a = s / n
ss = 0
for d in dd:
ss += (d-a)**2
sd = sqrt(ss)
outputBag = []
for d in dd:
outputBag.append( ( (d-a)/sd, ) )
print('conv2sigma output bag:')
print(outputBag)
return outputBag
输入文件jumps.csv
:
0,0,5,a
0,1,6,b
0,2,7,c
0,3,5,a
0,4,8,c
0,5,7,b
0,6,6,b
0,7,7,c
0,8,5,a
1,0,6,a
1,1,5,a
1,2,7,b
1,3,4,a
1,4,5,a
1,5,7,b
1,6,8,c
1,7,9,c
1,8,5,a
1,9,4,a
1,10,5,a
1,11,6,b
1,12,8,c
1,13,8,b
2,0,7,b
2,1,5,a
2,2,6,b
2,3,5,a
2,4,7,c
2,5,5,a
2,6,6,c
2,7,5,a
2,8,7,b
2,9,5,a
2,10,6,b
现在生成的输出:
{(0),(0),(0),(0),(0),(0),(0),(0),(0)},{(1),(2),(3),(4),(5),(6),(7),(8),(0)},{(6.0),(7.0),(5.0),(8.0),(7.0),(6.0),(7.0),(5.0),(5.0)},{(b),(c),(a),(c),(b),(b),(c),(a),(a)},{(-0.07188851546895898),(0.25160980414135625),(-0.39538683507927425),(0.5751081237516715),(0.25160980414135625),(-0.07188851546895898),(0.25160980414135625),(-0.39538683507927425),(-0.39538683507927425)}
{(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)},{(8),(0),(1),(2),(3),(4),(5),(6),(7),(9),(10),(11),(12),(13)},{(5.0),(6.0),(5.0),(7.0),(4.0),(5.0),(7.0),(8.0),(9.0),(4.0),(5.0),(6.0),(8.0),(8.0)},{(a),(a),(a),(b),(a),(a),(b),(c),(c),(a),(a),(b),(c),(b)},{(-0.20716308289978433),(-0.03655819109996196),(-0.20716308289978433),(0.1340467006998604),(-0.3777679746996067),(-0.20716308289978433),(0.1340467006998604),(0.30465159249968277),(0.4752564842995052),(-0.3777679746996067),(-0.20716308289978433),(-0.03655819109996196),(0.30465159249968277),(0.30465159249968277)}
{(2),(2),(2),(2),(2),(2),(2),(2),(2),(2),(2)},{(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)},{(7.0),(5.0),(6.0),(5.0),(7.0),(5.0),(6.0),(5.0),(7.0),(5.0),(6.0)},{(b),(a),(b),(a),(c),(a),(c),(a),(b),(a),(b)},{(0.4276686017238498),(-0.2960782627318961),(0.06579516949597684),(-0.2960782627318961),(0.4276686017238498),(-0.2960782627318961),(0.06579516949597684),(-0.2960782627318961),(0.4276686017238498),(-0.2960782627318961),(0.06579516949597684)}
每个输出元组都是一个行李集合,每个行李都包含来自一个字段的单个条目的元组,这不是我们想要的。
答案 0 :(得分:1)
您需要分两步完成此操作。每个跳转都有自己的sigma值,因此为了将每个sigma与正确的跳转正确关联,您需要将ID传递给sigma计算UDF,然后将结果重新加入(坏主意),或者计算首先汇总统计数据(均值和标准差),然后从中推导出sigma。方法如下:
jumps = LOAD 'jumps.csv' USING PigStorage(',')
AS (jumper:int, attempt:int, distance:double, location:chararray);
byJumper = GROUP jumps by jumper;
jumperSummaries =
FOREACH byJumper
GENERATE
group AS jumper,
FLATTEN(jumps.(attempt, distance, location)),
myfuncs.mean(jumps.distance) AS mean,
myfunds.stddev(jumps.distance) AS stddev;
sigmas =
FOREACH jumperSummaries
GENERATE
jumper,
attempt,
distance,
location,
myfuncs.sigma(distance, mean, stddev) AS sigma;
FLATTEN
取消所有跳转的组合并返回原始输入,但现在每个记录都复制了该跳线的均值和标准差,然后您可以使用它来计算每个跳跃行的sigma逐行。
请注意,虽然这在概念上是两个步骤,但它仍然只需要一个map-reduce作业。
答案 1 :(得分:0)
与WinnieNicklaus'进行比较回答,并提出意见,这是我提出的解决方案:
Register 'jumper.py' using jython as myfuncs;
jumps = LOAD 'jumps.csv' USING PigStorage(',')
AS (jumper:int, attempt:int, distance:double, location:chararray);
byJumper = GROUP jumps by jumper;
sigmas0 = FOREACH byJumper
GENERATE
FLATTEN(jumps),
FLATTEN(myfuncs.conv2sigma(jumps.(jumper,attempt,distance)));
sigmas1 = FILTER sigmas0 BY jumper == s_id AND attempt == s_att;
sigmas = FOREACH sigmas1
GENERATE jumper, attempt, distance, location, sigma;
rmf sigmas
STORE sigmas INTO 'sigmas' USING PigStorage(',');
第一个FOREACH
会创建一个(可能很大的)产品sigma0
,过滤掉"错误的"产品的元素并生成所需的字段。 JOIN
通常以学术方式描述。
这似乎可能很慢。
但它仍会导致单个Map-Reduce作业,并且似乎在实践中快速。
对我来说,一个巨大的胜利是它允许我的UDF做任意复杂的事情,并返回任意多个重新加入输入数据的元组。