Apache Beam似乎拒绝承认Kotlin的Iterable
。这是示例代码:
@ProcessElement
fun processElement(
@Element input: KV<String, Iterable<String>>, receiver: OutputReceiver<String>
) {
val output = input.key + "|" + input.value.toString()
println("output: $output")
receiver.output(output)
}
我收到以下奇怪的错误:
java.lang.IllegalArgumentException:
...PrintString, @ProcessElement processElement(KV, OutputReceiver), @ProcessElement processElement(KV, OutputReceiver):
@Element argument must have type org.apache.beam.sdk.values.KV<java.lang.String, java.lang.Iterable<? extends java.lang.String>>
当然,如果我将Iterable
替换为java.lang.Iterable
,则相同的代码也可以正常工作。我在做什么错了?
行为版本:
1.3.21
2.11.0
这是具有完整代码和堆栈跟踪的要点:
更新:
经过反复试验,我发现虽然List<String>
引发了类似的异常,但是MutableList<String>
确实有效:
class PrintString: DoFn<KV<String, MutableList<String>>, String>() {
@ProcessElement
fun processElement(
@Element input: KV<String, MutableList<String>>, receiver: OutputReceiver<String>
) {
val output = input.key + "|" + input.value.toString()
println("output: $output")
receiver.output(output)
}
}
因此,这使我想起Kotlin的Immutable集合实际上只是接口,而底层集合仍然是可变的。但是,尝试将Iterable
替换为MutableIterable
会继续导致错误。
答案 0 :(得分:4)
在ParDo
之后使用GroupByKey
时,我也遇到了这个问题。事实证明,在编写接受@JvmWildcard
结果的转换时,Iterable
通用类型中需要GroupByKey
注释。
请参阅下面的人为设计示例,该示例读取文件并按每行的第一个字符进行分组。
class BeamPipe {
class ConcatLines : DoFn<KV<String, Iterable<@JvmWildcard String>>, KV<String, String>>() {
@ProcessElement
fun processElement(@Element input: KV<String, Iterable<@JvmWildcard String>>, receiver: OutputReceiver<KV<String, String>>) {
receiver.output(KV.of(input.key, input.value.joinToString("\n")))
}
}
fun pipe(options: PipelineOptions) {
val file =
"testFile.txt"
val p = Pipeline.create(options)
p.apply(TextIO.read().from(file))
.apply("Key lines by first character",
WithKeys.of { line: String -> line[0].toString() }
.withKeyType(TypeDescriptors.strings()))
.apply("Group lines by first character", GroupByKey.create<String, String>())
.apply("Concatenate lines", ParDo.of(ConcatLines()))
.apply("Write to files", FileIO.writeDynamic<String, KV<String, String>>()
.by { it.key }
.withDestinationCoder(StringUtf8Coder.of())
.via(Contextful.fn(ProcessFunction { it.value }), TextIO.sink())
.to("whatever")
.withNaming { key -> FileIO.Write.defaultNaming(key, ".txt") }
)
p.run()
}
}
答案 1 :(得分:1)
我对kotlin不太熟悉,但是似乎您需要导入import java.lang.Iterable
才能在代码中使用它。
答案 2 :(得分:1)
这似乎是Beam Kotlin SDK中的错误。您的@ProcessElement
方法的反射分析无法正常工作。您可能可以通过使用ProcessContext ctx
而不是使用@Element
参数来解决此问题。
答案 3 :(得分:0)
当我们从groupbykey.create()获得可迭代对象时,我可以知道如何解决该问题。我无法像您做javalang可迭代的
那样groupbykey答案 4 :(得分:0)
对于那些正在经历此问题并在这里找到解决方法的人,我目前继续在kotlin中编写管道的解决方法是创建一个Java静态类,该类具有可创建,包含和处理您的Iterable的函数。然后将结果(不可重复的格式)传递回kotlin。