解释Apache Beam的Python语法

65
我已阅读Beam文档并查看Python文档,但没有找到大多数Apache Beam示例代码中使用的语法的良好解释。请问有人能够解释下面代码中_|>>的作用吗?此外,引号中的文本 'ReadTrainingData' 有意义吗?还是可以用任何其他标签替换它?换句话说,该标签如何被使用?
(Note: The translated text above is in simplified Chinese.)
train_data = pipeline | 'ReadTrainingData' >> _ReadData(training_data)
evaluate_data = pipeline | 'ReadEvalData' >> _ReadData(eval_data)

input_metadata = dataset_metadata.DatasetMetadata(schema=input_schema)

_ = (input_metadata
| 'WriteInputMetadata' >> tft_beam_io.WriteMetadata(
       os.path.join(output_dir, path_constants.RAW_METADATA_DIR),
       pipeline=pipeline))

preprocessing_fn = reddit.make_preprocessing_fn(frequency_threshold)
(train_dataset, train_metadata), transform_fn = (
  (train_data, input_metadata)
  | 'AnalyzeAndTransform' >> tft.AnalyzeAndTransformDataset(
      preprocessing_fn))

1
这个想法是将 .method() 语法转换为 infix 运算符。例如,将 a.plus(b) 转换为 a + b 的语法。请查看源代码中的 __or____ror____rrshift__ 函数定义 https://github.com/apache/beam/blob/master/sdks/python/apache_beam/transforms/ptransform.py#L448。因此,`MyPTransform | NextPTransform实际上是将这两个 PTransform 对象作为列表_parts传递给新的_ChainedPTransform对象,并且如果您使用__or__` 添加另一个 PTransform,则会展开嵌套列表。 - Davos
1
">>",也就是 "rrshift",实际上是设置 PTransform 的 "label" 属性,但它并不像 Ptransform.label('new name') 或 Ptransform.label = 'new name' 那样简单,对我来说似乎更加复杂。"'ReadEvalData' >> _ReadData(eval_data)" 被解释为返回一个新的 "_NamedPTransform" 对象,其中 "_ReadData(eval_data)" 被初始化为 "self.transform" 属性,字符串 "'ReadEvalData'" 通过使用 "Super" 运行父类 "PTransform" 的 init 方法来初始化标签属性。 - Davos
1
__ror____or__相同,它们最终都变成了管道中缀符号|,但是__ror__允许您定义如何将其他对象传递到PTransform的管道中,其中这些其他对象没有定义管道运算符方法。这种方法使得右侧对象的管道运算符仍然可以从左到右工作。 - Davos
2
非常复杂,创建一个以当前对象为属性的新对象,只是为了实现流畅的函数/Shell风格。虽然从左到右阅读整个处理管道变得更容易,而且看起来类似于函数式编程语法,例如F#或在Rlang中使用MagrittR。它可能比很多嵌套的函数调用要好,例如PTransforrm.apply(NextPTransform.apply(YetAnotherPTransform)),但您始终可以为每个步骤创建新变量。毕竟,它是惰性评估的,并且不会进行数据深层拷贝,因此没有惩罚。 - Davos
2个回答

87
Python中的运算符可以进行重载。在Beam中,|apply的同义词,它将一个PTransform应用于一个PCollection以生成一个新的PCollection>>允许您为在各种UI中更轻松地显示的步骤命名——|>>之间的字符串仅用于这些显示目的和标识特定的应用程序。
请参见https://beam.apache.org/documentation/programming-guide/#transforms

谢谢!这非常有帮助。如果我理解正确,他们是否使用 _ 是因为 writeMetadata 变换没有输出 PCollection? - dobbysock1002
理论上,它应该返回一个 PDone [1],但他们不需要它(所以他们使用了丢弃的 _)。 [1] https://github.com/apache/beam/blob/master/sdks/python/apache_beam/pvalue.py#L163 - rf-
@JoelCroteau:我猜他们认为在这种情况下使用 | 符号是非常聪明的,因为你正在构建一个管道...(例如,在 shell 中经常使用管道符号)。 - Gerard
此外,由于这里没有明确说明,下划线 _ 是 Python 中表示将被丢弃的变量的“典型”语法。例如,在 _ = (input_metadata... 这里,它表示操作的结果将返回给 _,而代码作者明确表示她不会再次使用这个变量。在这种情况下,你可以看到这是一个写操作,作者并不关心该操作返回的内容。 - undefined

2
没有人提到_,所以为了完整起见:
  • 关于_,它没有任何官方特殊之处,但是将一个返回但你不关心的变量赋值给_被视为良好的实践。这样,你的代码读者就明白你打算丢弃它。
    • 这还可以减少内存使用,因为当你重新赋值(覆盖)_时,你会丢弃其他赋值给_的实例。
  • _还有一个非官方的作用:因为它是“丢弃”变量,大多数代码检查工具和其他代码清晰度辅助工具会对其进行不同的处理。
    • 例如,如果你赋值一个变量use_me但实际上从未使用过,代码检查工具会警告你存在未使用的变量。如果你有严格的代码质量限制,也许你甚至不能将带有未使用变量的代码合并到生产环境。
    • _不会被代码检查工具捕捉到(并且可以合并到严格的代码库中),因为它被理解为丢弃变量,因此你的代码没有错误(至少在这方面没有错误)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接