Pig - 如何迭代一袋地图
Posted
技术标签:
【中文标题】Pig - 如何迭代一袋地图【英文标题】:Pig - how to iterate on a bag of maps 【发布时间】:2013-08-12 06:38:39 【问题描述】:让我解释一下这个问题。我有这行代码:
u = FOREACH persons GENERATE FLATTEN($0#'experiences') as j;
dump u;
产生这个输出:
([id#1,date_begin#12 2012,description#blabla,date_end#04 2013],[id#2,date_begin#02 2011,description#blabla2,date_end#04 2013])
([id#1,date_begin#12 2011,description#blabla3,date_end#04 2012],[id#2,date_begin#02 2010,description#blabla4,date_end#04 2011])
然后,当我这样做时:
p = foreach u generate j#'id', j#'description';
dump p;
我有这个输出:
(1,blabla)
(1,blabla3)
但这不是我想要的。我想要这样的输出:
(1,blabla)
(2,blabla2)
(1,blabla3)
(2,blabla4)
我怎么会有这个?
非常感谢。
【问题讨论】:
在第一个区块中你做dump j;
,你的意思是dump u;
?另外,你能提供DESCRIBE u;
的输出吗?
是的,谢谢。 DESCRIBE u 产生这个输出: u: j: bytearray
【参考方案1】:
我假设你在FLATTEN
ing 在u
中的$0 是一个元组。
总体问题是j
仅引用元组中的第一个映射。为了得到你想要的输出,你必须把每个元组转换成一个包,然后FLATTEN
它。
如果您知道每个元组最多有两个映射,您可以这样做:
-- My B is your u
B = FOREACH A GENERATE (tuple(map[],map[]))$0#'experiences' AS T ;
B2 = FOREACH B GENERATE FLATTEN(TOBAG(T.$0, T.$1)) AS j ;
C = foreach B2 generate j#'id', j#'description' ;
如果您不知道元组中有多少字段,那么这将非常困难。
注意:这适用于猪 0.10。
对于映射数量未定义的元组,我能想到的最佳答案是使用 UDF 来解析字节数组:
myudf.py
@outputSchema('vals: (val:map[])')
def foo(the_input):
# This converts the indeterminate number of maps into a bag.
foo = [chr(i) for i in the_input]
foo = ''.join(foo).strip('()')
out = []
for f in foo.split('],['):
f = f.strip('[]')
out.append(dict((k, v) for k, v in [ i.split('#') for i in f.split(',')]))
return out
myscript.pig
register 'myudf.py' using jython as myudf ;
B = FOREACH A GENERATE FLATTEN($0#'experiences') ;
T1 = FOREACH B GENERATE FLATTEN(myudf.foo($0)) AS M ;
T2 = FOREACH T1 GENERATE M#'id', M#'description' ;
但是,这取决于 #
、,
或 ],[
不会出现在映射中的任何键或值中。
注意:这适用于猪 0.11。
因此,在这种情况下,pig 处理 python UDF 输入的方式似乎发生了变化。不是将字节数组作为foo
的输入,而是自动将字节数组转换为适当的类型。在这种情况下,它会让一切变得更容易:
myudf.py
@outputSchema('vals: (val:map[])')
def foo(the_input):
# This converts the indeterminate number of maps into a bag.
out = []
for map in the_input:
out.append(map)
return out
myscript.pig
register 'myudf.py' using jython as myudf ;
# This time you should pass in the entire tuple.
B = FOREACH A GENERATE $0#'experiences' ;
T1 = FOREACH B GENERATE FLATTEN(myudf.foo($0)) AS M ;
T2 = FOREACH T1 GENERATE M#'id', M#'description' ;
【讨论】:
不幸的是,我不知道元组上有多少字段:( @shanks_roux 我已经更新了我的答案以包含一种未知数量字段的方法。我对此不满意,但它会起作用。 感谢您的帮助!但是为什么您对自己的解决方案不满意? 我不满意,因为我找不到纯猪的方式。在纯猪中应该有某种方法可以做到这一点,而且速度会更快,并且不会有关于什么不能出现在地图中的任意规则。 是的,你是对的。我没有准确地说我使用 MongoLoader 加载数据(数据在 mongoDB 数据库中),我认为解决方案可能是 mongoloader 的不同用途。但是您的解决方案似乎不错,对此我表示感谢。以上是关于Pig - 如何迭代一袋地图的主要内容,如果未能解决你的问题,请参考以下文章