我有一个代码可以在Google云端存储中提取.ZIP文件的内容。它工作正常,但我需要使用此代码与将在运行时提供的文件路径(“gs://some_bucket/filename.zip”)。当我使用运行时值尝试它时,我得到一个错误:
import numpy as np
import tensorflow as tf
series = tf.placeholder(tf.float32, shape=[None, 5])
series_length = tf.placeholder(tf.int64)
def magic_slice_function(input_x, input_y):
array = []
for i in range(len(input_x)):
temp = [input_x[i][j] for j in range(input_y[i])]
array.extend(temp)
return [array]
with tf.Session() as sess:
input_x = np.array([[1, 2, 3, 0, 0],
[2, 3, 0, 0, 0],
[1, 0, 0, 0, 0]])
input_y = np.array([3, 2, 1], dtype=np.int64)
merged_series = tf.py_func(magic_slice_function, [series, series_length], tf.float32, name='slice_func')
out = tf.split(merged_series, input_y)
print(sess.run(out, feed_dict={series: input_x, series_length: input_y}))
我正在使用的代码是:
[array([ 1., 2., 3.], dtype=float32), array([ 2., 3.], dtype=float32), array([ 1.], dtype=float32)]
UnzipFN类:
Exception in thread "main" java.lang.IllegalArgumentException: unable to serialize org.apache.beam.sdk.io.gcp.bigquery.BigQueryQuerySource@187bc24
at org.apache.beam.sdk.util.SerializableUtils.serializeToByteArray(SerializableUtils.java:53)
at org.apache.beam.sdk.util.SerializableUtils.ensureSerializable(SerializableUtils.java:83)
at org.apache.beam.sdk.io.Read$Bounded.<init>(Read.java:94)
at org.apache.beam.sdk.io.Read$Bounded.<init>(Read.java:89)
at org.apache.beam.sdk.io.Read.from(Read.java:48)
at org.apache.beam.sdk.io.gcp.bigquery.BigQueryIO$Read.expand(BigQueryIO.java:535)
at org.apache.beam.sdk.io.gcp.bigquery.BigQueryIO$Read.expand(BigQueryIO.java:292)
at org.apache.beam.sdk.Pipeline.applyInternal(Pipeline.java:482)
at org.apache.beam.sdk.Pipeline.applyTransform(Pipeline.java:422)
at org.apache.beam.sdk.values.PBegin.apply(PBegin.java:44)
at org.apache.beam.sdk.Pipeline.apply(Pipeline.java:164)
at BeamTest2.StarterPipeline.main(StarterPipeline.java:180)
Caused by: java.io.NotSerializableException: org.apache.beam.sdk.Pipeline
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at org.apache.beam.sdk.util.SerializableUtils.serializeToByteArray(SerializableUtils.java:49)
... 11 more
如何处理这种情况?
P.S。 - .zip提取代码与BigQueryIO.read()无关。我只是将它用作hack才能读取运行时值。如果您有任何其他建议请告诉我。
感谢。
答案 0 :(得分:1)
如果我理解正确,您的ValueProvider<String>
包含一个文件模式,并且您正在使用GcsUtil.expand()
扩展文件模式,并且您希望将函数(UnzipFn
)应用于每个文件模式生成的文件名。
目前的代码不会有多种原因:
BigQueryIO.read().fromQuery()
,其中fromQuery()
的参数是ValueProvider
,它总是返回空字符串(您的NestedValueProvider
,在做了一堆之后,始终返回空字符串""
)。这将在运行时失败,因为查询不能为空。使用BigQueryIO
作为黑客来尝试访问ValueProvider
并不是一个好主意 - 请参阅下文。ValueProvider
中提取值。在管道运行时,从工作程序调用该函数,以获取提供程序的运行时值。在管道运行时,无法从其工作人员向管道添加步骤。Pipeline
对象捕获到SerializableFunction
闭包中,并且无法序列化,因为Pipeline
不是Serializable
- 因为没有合法的用例用于序列化Pipeline
Java对象:它永远不需要运送给工作者或运行者,它只是主程序中使用的临时构建器对象,用于构造稍后可以调用.run()
的东西。另一方面,SerializableFunction
将发送给工作人员,以便他们可以评估ValueProvider
的当前值。将ValueProvider
视为占位符,仅在管道运行时具有值,而不是在构造时具有值 - 例如您可以在provider.get()
内拨打DoFn
。 NestedValueProvider
根本不会改变这一点 - 它只是通过一些简单的转换逻辑包装另一个ValueProvider
,并且当你有一个ValueProvider<Something>
但需要它作为{{ {1}}。
问题的关键在于您尝试仅在运行时使用值(ValueProvider<SomethingSlightlyDifferent>
options.getInputFile()
)来构建构建时间 - 创建管道步骤{{1} }。从逻辑上讲,在构造时避免ValueProvider
不可用是不可能的:Create.of(paths)
专门用于表示在施工时尚未提供的值,因此它们是在管道描述中保留为占位符,并仅在管道运行时作为参数提供。您需要提出一个管道结构,其中输入文件是占位符,管道以您想要的方式处理它。
你可以这样做:
ValueProvider
其中ValueProvider
为p.apply(Create.ofProvider(options.getInputFile(), StringUtf8Coder.of()))
.apply(ParDo.of(new ExpandFn()))
.apply(...fusion break...)
.apply(ParDo.of(new UnzipFn()))
,其为ExpandFn
并且为您的DoFn
内容,并且对于融合中断,请参阅例如实施String
。
在Beam 2.2中(你现在可以在HEAD上使用它)你不需要GcsUtil.expand()
- 已经存在一个可以扩展filepatterns的转换等等(例如它可以逐步扩展文件模式并继续观察对于匹配它的新文件,在流式传输管道中)。所以你可以更简洁地写出来:
JdbcIO.java