我使用Flink 1.2.0 Table API处理一些流数据。以下是我的代码:
val dataTable = myDataStream
// table A
val tableA = dataTable
.window(Tumble over 5.minutes on 'rowtime as 'w)
.groupBy("w, group1, group2")
.select("w.start as time, group1, group2, data1.sum as data1, data2.sum as data2")
tableEnv.registerTable("tableA", tableA)
// table A sink
tableA.writeToSink(sinkTableA)
//...
// I shoul get some other outputs from TableA output
//...
val dataTable = tableEnv.ingest("tableA")
// table result1
val result1 = dataTable
.window(Tumble over 5.minutes on 'rowtime as 'w)
.groupBy("w, group1")
.select("w.start as time, group1, data1.sum as data1")
// result1 sink
result2.writeToSink(sinkResult1)
// table result2
val result2 = dataTable
.window(Tumble over 5.minutes on 'rowtime as 'w)
.groupBy("w, group2")
.select("w.start as time, group2, data2.sum as data1")
// result2 sink
result2.writeToSink(sinkResult2)
我等待在flink执行计划中获取此树。 与我在其他Flink工作中的Flink Streaming相同。
DataStream_Operators -> TableA_Operators -> TableA_Sink
|-> Result1_Operators -> Result1_Sink
|-> Result2_Operators -> Result2_Sink
但是,对于TableA,我得到3个相同的opertoprs副本!
DataStream_Operators -> TableA_Operators -> TableA_Sink
|-> Copy_of_TableA_Operators -> Result1_Operators -> Result1_Sink
|-> Copy_of_TableA_Operators -> Result2_Operators -> Result2_Sink
我的结果是这项工作的输入数据很糟糕。
我如何解决这个问题并获得最佳执行计划?
我没说,Flink Table API和SQL是实验性功能和 也许它将在下一版本中修复。
答案 0 :(得分:0)
在当前状态下,每当您将Table
转换为DataSet
或DataStream
或将其写入TableSink
时,Table API都会转换整个查询。在您的程序中,您调用三次writeToSink
,这意味着每次翻译完整的查询。
但完整的查询是什么?已经在Table
上应用了所有Table API运算符。当您在Table
中注册TableEnvironment
时,它基本上被注册为视图,即仅注册其定义(定义表的所有运算符)。因此,当您第二次和第三次调用writeToSink
时,会再次翻译这些运算符。
如果您将tableA
翻译成DataStream
并在DataStream
注册TableEnvironment
而不是将其注册为Table
,则可以解决此问题。这看起来如下:
val tableA = ...
val streamA = tableA.toDataStream[X] // X should be a case class for rows of tableA
val tableEnv.registerDataStream("tableA", streamA)
tableEnv.ingest("tableA").writeToSink(sinkTableA) // emit tableA by ingesting the registered DataStream
我知道,这不是很方便,但目前是避免重复翻译表的唯一方法。