我正在使用 apache Beam 2.10 并试图了解将{p3}返回给调用者时flatmap到底在做什么。
在阅读在线文档的说明后,我认为 flatMap 就像在this示例中那样,将PCollection元素的集合简单地拆分为单个pcollection。
可调用对象必须为输入的每个元素返回一个可迭代对象 PCollection。这些可迭代的元素将被压平为 输出PCollection。
但是在以下代码的情况下, flatMap 会拼合“ Hello World”的每个单个字符,而不是整体返回“ Hello World”。
def simple(x):
logging.info("Inside simple type: {0}, val: {1}".format(type(x), x))
# Just return
return x
def run():
with beam.Pipeline(runner='DirectRunner') as p:
elems = p | 'map:init' >> beam.Create(["Hello World"])
#
# Sample with FlatMap
#
( elems | 'flatmap:exec' >> beam.FlatMap(simple) # 1 to 1 relation with flatmap
| 'flatmap:out' >> beam.io.textio.WriteToText(file_path_prefix='flatmap')
)
def main():
run()
if __name__ == "__main__":
main()
H
e
l
l
o
W
o
r
l
d
但是当我返回一个 generator 时,就像在这个code中那样,迭代的结果似乎变成了pcollection。
def simple(x):
logging.info("Inside simple type: {0}, val: {1}".format(type(x), x))
# Just return
yield x
def run():
with beam.Pipeline(runner='DirectRunner') as p:
elems = p | 'map:init' >> beam.Create(["Hello World"])
#
# Sample with FlatMap
#
( elems | 'flatmap:exec' >> beam.FlatMap(simple) # 1 to 1 relation with flatmap
| 'flatmap:out' >> beam.io.textio.WriteToText(file_path_prefix='flatmap')
)
def main():
run()
if __name__ == "__main__":
main()
Hello World
如果我从字面上返回一个 iterator ,则将迭代一个字符串,并将每个字符展平为PCollections。
def simple(x):
logging.info("Inside simple type: {0}, val: {1}".format(type(x), x))
# Just return
return iter(x)
def run():
with beam.Pipeline(runner='DirectRunner') as p:
elems = p | 'map:init' >> beam.Create(["Hello World"])
#
# Sample with Map
#
( elems | 'flatmap:exec' >> beam.FlatMap(simple) # 1 to 1 relation with flatmap
| 'flatmap:out' >> beam.io.textio.WriteToText(file_path_prefix='flatmap')
)
def main():
run()
if __name__ == "__main__":
main()
H
e
l
l
o
W
o
r
l
d
那么,在将PCollection返回给调用者函数时,flatMap到底能做什么?
答案 0 :(得分:1)
FlatMap
假定给定函数的返回类型为iterable
。在第一个示例中,simple
返回"Hello World"
。与iterable
一样,"Hello World"
可以视为['H','e','l','l','o',' ','W','o','r','l','d']
。因此,您的第一个示例的工作方式如下:
[] -> create -> ["Hello World"]
["Hello World"] -> map -> [['H','e','l','l','o',' ','W','o','r','l','d']]
[['H','e','l','l','o',' ','W','o','r','l','d']] -> flatten -> ['H','e','l','l','o',' ','W','o','r','l','d']
最终PCollection:['H','e','l','l','o',' ','W','o','r','l','d']
但是,在第二个示例中,simple
产生x
。您可以认为simple
返回iterator
,其中包含单个元素x
。所以您的第二个示例是这样的:
[] -> create -> ["Hello World"]
["Hello World"] -> map -> [["Hello World"]]
[["Hello World"]] -> flatten -> ["Hello World"]
最终PCollection:["Hello World"]
要回答您的最后一个问题:
yield x
和return iter(x)
在语义上是不同的。以下示例可以帮助您理解上下文。
>>> list(iter("abc"))
['a', 'b', 'c']
>>> def x(): yield "abc"
>>> list(x())
['abc']