我有一些代码将两个流DataFrames
连接起来并输出到控制台。
val dataFrame1 =
df1Input.withWatermark("timestamp", "40 seconds").as("A")
val dataFrame2 =
df2Input.withWatermark("timestamp", "40 seconds").as("B")
val finalDF: DataFrame = dataFrame1.join(dataFrame2,
expr(
"A.id = B.id" +
" AND " +
"B.timestamp >= A.timestamp " +
" AND " +
"B.timestamp <= A.timestamp + interval 1 hour")
, joinType = "leftOuter")
finalDF.writeStream.format("console").start().awaitTermination()
我现在想要的是重构此部分以使用Datasets
,因此我可以进行一些compile-time
检查。
所以我尝试的很简单:
val finalDS: Dataset[(A,B)] = dataFrame1.as[A].joinWith(dataFrame2.as[B],
expr(
"A.id = B.id" +
" AND " +
"B.timestamp >= A.timestamp " +
" AND " +
"B.timestamp <= A.timestamp + interval 1 hour")
, joinType = "leftOuter")
finalDS.writeStream.format("console").start().awaitTermination()
但是,这会出现以下错误:
org.apache.spark.sql.AnalysisException:不支持两个流式数据帧/数据集之间的流-流外部联接,而联接键中没有水印,或者在可为空的一侧没有水印,没有适当的范围条件;; < / p>
如您所见,join
代码未更改,因此两侧都有水印,并且有范围条件。唯一的变化是使用Dataset
API而不是DataFrame
。
此外,当我使用内部join
时也可以:
val finalDS: Dataset[(A,B)] = dataFrame1.as[A].joinWith(dataFrame2.as[B],
expr(
"A.id = B.id" +
" AND " +
"B.timestamp >= A.timestamp " +
" AND " +
"B.timestamp <= A.timestamp + interval 1 hour")
)
finalDS.writeStream.format("console").start().awaitTermination()
有人知道怎么回事吗?
答案 0 :(得分:1)
好吧,当您使用joinWith
方法而不是join
时,您依赖于不同的实现,并且该实现似乎不支持 leftOuter join 用于流式传输数据集。
您可以查看官方文档的outer joins with watermarking部分。方法join
未使用joinWith
。请注意,结果类型将为DataFrame
。这意味着您很可能将不得不手动映射字段
val finalDS = dataFrame1.as[A].join(dataFrame2.as[B],
expr(
"A.key = B.key" +
" AND " +
"B.timestamp >= A.timestamp " +
" AND " +
"B.timestamp <= A.timestamp + interval 1 hour"),
joinType = "leftOuter").select(/* useful fields */).as[C]