我对Pig / Python很新,需要帮助。试图编写一个协调财务数据的Pig脚本。使用的参数遵循类似(grand_tot,x1,x2,... xn)的语法,这意味着第一个值应该等于剩余值的总和。
我不知道如何单独使用Pig来实现这一目标,所以我一直在尝试编写Python UDF。猪将元组传递给Python;如果x1:xn的总和等于grand_tot,那么Python应该返回一个" 1" to Pig表示数字匹配,否则返回" 0"。
这是我到目前为止所做的:
register 'myudf.py' using jython as myfuncs;
A = LOAD '$file_nm' USING PigStorage(',') AS (grand_tot,west_region,east_region,prod_line_a,prod_line_b, prod_line_c, prod_line_d);
A1 = GROUP A ALL;
B = FOREACH A1 GENERATE TOTUPLE($recon1) as flds;
C = FOREACH B GENERATE myfuncs.isReconciled(flds) AS res;
DUMP C;
$ recon1 作为参数传递,定义为:
grand_tot, west_region, east_region
我稍后会将 $ recon2 传递给:
grand_tot, prod_line_a, prod_line_b, prod_line_c, prod_line_d
示例数据行(在 $ file_nm 中)如下所示:
grand_tot,west_region,east_region,prod_line_a,prod_line_b, prod_line_c, prod_line_d
10000,4500,5500,900,2200,450,3700,2750
12500,7500,5000,3180,2770,300,3950,2300
9900,7425,2475,1320,460,3070,4630,1740
最后......这是我尝试使用Python UDF代码的原因:
@outputSchema("result")
def isReconciled(arrTuple):
arrTemp = []
arrNew = []
string1 = ""
result = 0
## the first element of the Tuple should be the sum of remaining values
varGrandTot = arrTuple[0]
## create a new array with the remaining Tuple values
arrTemp = arrTuple[1:]
for item in arrTuple:
arrNew.append(item)
## sum the second to the nth values
varSum = sum(arrNew)
## if the first value in the tuple equals the sum of all remaining values
if varGrandTot = varSum then:
#reconciled to the penny
result = 1
else:
result = 0
return result
我收到的错误消息是: 不支持的操作数类型+:' int'和' array.array'
我尝试过很多尝试将数组值转换为数字并转换为float的东西,以便我可以求和,但没有成功。
任何想法???谢谢你的期待!
答案 0 :(得分:1)
你可以在PIG中做到这一点。
首先,在架构中指定数据类型。 PigStorage将使用bytearray作为默认数据类型。因此你的python脚本会抛出错误。看起来像你的示例数据有int但在你的问题中你提到了float。
其次,从第二个字段或您选择的字段开始添加字段。
第三,使用bincond运算符检查第一个字段值和。
A = LOAD '$file_nm' USING PigStorage(',') AS (grand_tot:float,west_region:float,east_region:float,prod_line_a:float,prod_line_b:float, prod_line_c:float, prod_line_d:float);
A1 = FOREACH A GENERATE grand_tot,SUM(TOBAG(prod_line_a,prod_line_b,prod_line_c,prod_line_d)) as SUM_ALL;
B = FOREACH A1 GENERATE (grand_tot == SUM_ALL ? 1 : 0);
DUMP B;
答案 1 :(得分:0)
您arrTuple
很可能不是数字数组,但有些项目是数组。
要检查它,请通过添加一些检查来修改您的代码:
@outputSchema("result")
def isReconciled(arrTuple):
# some checks
tmpl = "Item # {i} shall be a number (has value {itm} of type {tp})"
for i, num in enumerate(arrTuple):
msg = templ.format(i=i, itm=itm, tp=type(itm))
assert isinstance(arrTuple[0], (int, long, float)), msg
# end of checks
arrTemp = []
arrNew = []
string1 = ""
result = 0
## the first element of the Tuple should be the sum of remaining values
varGrandTot = arrTuple[0]
## create a new array with the remaining Tuple values
arrTemp = arrTuple[1:]
for item in arrTuple:
arrNew.append(item)
## sum the second to the nth values
varSum = sum(arrNew)
## if the first value in the tuple equals the sum of all remaining values
if varGrandTot = varSum then:
#reconciled to the penny
result = 1
else:
result = 0
return result
很可能会在其中一个项目上抛出AssertionFailed
个异常。阅读
断言要学习,哪个项目正在制造麻烦。
无论如何,如果要在第一个数字等于数组其余部分的总和时返回0或1,请执行以下操作 也会工作:
@outputSchema("result")
def isReconciled(arrTuple):
if arrTuple[0] == sum(arrTuple[1:]):
return 1
else:
return 0
如果您获得True
代替1和False
而不是0,您会感到满意:
@outputSchema("result")
def isReconciled(arrTuple):
return arrTuple[0] == sum(arrTuple[1:])