为什么foreachPartition错误输出流数据集?

时间:2017-07-06 00:55:54

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

我正在从Spark Streaming迁移到Structured Streaming,我遇到以下代码的问题:

def processDataSet(inputDataset: Dataset[MyMessage], foobar: FooBar) = {
    inputDataset.foreachPartition { partitionIterator =>
      val filteredIterator = partitionIterator.filter(foobar.filter)
      ...
      ...
    }
}       
val streamingQuery = inputDataset
  .writeStream
  .trigger(ProcessingTime("5 seconds"))
  .outputMode("append")
  .format("console")
  .start

使用以下AnalysisException错误输出:

  

引起:org.apache.spark.sql.AnalysisException:必须使用writeStream.start();;

执行带有流源的查询

流式查询是否不支持foreachPartitionwriteStream.foreach是在这种情况下实施foreachPartition的唯一方法吗?

我希望避免发送每个事件,而是累积所有行,形成一个巨大的POST请求主体并将其发送到HTTP端点。因此,如果批处理中的1000个事件和5个分区,则在每个请求正文中并行生成5个请求和200个事件。

1 个答案:

答案 0 :(得分:2)

TL; DR 是的。不支持foreachPartition操作,您应该使用ForeachWriter

引用foreachPartition的scaladoc:

  

foreachPartition(f:(Iterator [T])⇒Unit):Unit 将函数f应用于此数据集的每个分区。

正如您现在可能已经发现的那样,foreach是一个操作,因此会触发Spark执行。

由于您使用流数据集,因此不允许使用foreach等“传统”方法触发执行。

引用结构化流媒体Unsupported Operations

  

此外,有些数据集方法不适用于流式数据集。它们是立即运行查询并返回结果的操作,这对流式数据集没有意义。相反,这些功能可以通过显式启动流式查询来完成(请参阅下一节)。

流媒体替代方案中有foreach运算符(也称为接收器)。这就是结构化流媒体中的foreachPartition

引用Using Foreach

  

foreach操作允许对输出数据计算任意操作。

     

要使用它,您必须实现接口ForeachWriter,该接口具有在触发器后生成一系列行作为输出时被调用的方法。

  

我希望避免发送每个事件,而是累积所有行,形成一个巨大的POST请求主体并将其发送到HTTP端点。因此,如果批处理中的1000个事件和5个分区,则在每个请求正文中并行生成5个请求和200个事件。

在将数据集写入接收器之前,这似乎是一个聚合,不是吗?使用groupBy运算符和collect_list函数对行进行分组,这样当您writeStream时,您将拥有任意数量的组。

除非没有别的办法,否则我宁愿避免使用称为分区的RDD这种低级功能作为优化写入的方法。