一次触发触发的Spark Streaming追加输出模式

时间:2018-07-10 14:40:02

标签: apache-spark apache-kafka spark-streaming spark-structured-streaming

我尝试在Kafka输入和此类配置中使用Spark流(2.2.0):

  • 加水印和聚合
  • 开窗
  • 输出模式:OutputMode.Append()
  • 触发模式:Trigger.Once()

但是我没有输出(在kafka和控制台中都没有)。 多次启动该应用程序也不起作用。

当我使用OutputMode.Complete()或Trigger.ProcessingTime(0L)时,它可以工作。不幸的是,这不是我的需要。

触发器一次是否支持追加模式?

这是一个重现此问题的最小应用程序。 Gist

case class Model(valueForGroupBy: Int, time: Timestamp)

object Application {

  val appName = "sample"

//  val outputMode: OutputMode = OutputMode.Complete() // OK
  val outputMode: OutputMode = OutputMode.Append() // KO with trigger once

  val triggerMode: Trigger = Trigger.Once()

  val delayThreshold: FiniteDuration = 1.minute // watermarking wait for late

  val duration : FiniteDuration = 1.minute // window duration and slide

  val topic = "SAMPLE_TOPIC"
  val bootstrapServers = "127.0.0.1:9092"


  type KafkaKV = (String, String)

  def main(args: Array[String]): Unit = {

    val spark: SparkSession = SparkSession
      .builder
      .appName(appName)
      .getOrCreate()

    import org.apache.spark.sql._
    import org.apache.spark.sql.functions._
    import spark.implicits._

    val streamReader: DataStreamReader = spark.readStream
      .format("kafka")
      .option("kafka.bootstrap.servers", bootstrapServers)
      .option("subscribe", topic)
      .option("startingOffsets", "earliest")
      .option("failOnDataLoss", "false")

    val df: DataFrame = streamReader.load()

    val ds: Dataset[Model] = df.selectExpr("CAST(key AS STRING)", "CAST(value AS STRING)").as[KafkaKV]
      .select(from_json($"value", Encoders.product[Model].schema).as("json"))
      .select($"json.*")
      .as[Model]

    val groupByColumns = Seq(
      window(new Column("time"), windowDuration = duration.toString, slideDuration = duration.toString),
      new Column("valueForGroupBy")
    )

    val agg = ds
      .withWatermark("time", delayThreshold.toString)
      .groupBy(groupByColumns: _*)
      .count()

    val streamWriter = agg
      .selectExpr(s"CAST(valueForGroupBy AS STRING) AS key", "to_json(struct(*)) AS value")
      .writeStream
      .trigger(triggerMode)
      .outputMode(outputMode)
      .format("console")
      .option("truncate", value = false)

    val streamingQuery = streamWriter.start()

    streamingQuery.awaitTermination()

  }
}

2 个答案:

答案 0 :(得分:0)

不支持带有“触发一次”的附加模式。

这是一个Spark已知的错误:https://issues.apache.org/jira/browse/SPARK-24699

答案 1 :(得分:0)

这是Spark的已知错误。

在实际实现中,水印将在下一批中保留。由于触发器中一次没有后续批处理,因此watermak永远不会持久。

Spark bugtracker中存在一个票证:https://issues.apache.org/jira/browse/SPARK-24699