PySpark结构化流将udf应用于窗口

时间:2019-10-22 16:05:16

标签: apache-spark pyspark databricks spark-structured-streaming azure-databricks

我正在尝试将Puds udf应用于pyspark结构化流的窗口。问题在于,流一旦赶上当前状态,所有新窗口就会以某种方式仅包含一个值。

py

正如您在屏幕快照中看到的那样,2019-10-22T15:34:08.730 + 0000之后的所有窗口都只包含一个值。用于生成此代码的代码是这样的:

@pandas_udf("Count long, Resampled long, Start timestamp, End timestamp", PandasUDFType.GROUPED_MAP)
def myudf(df):
  df = df.dropna()
  df = df.set_index("Timestamp")
  df.sort_index(inplace=True)

  # resample the dataframe
  resampled = pd.DataFrame()
  oidx = df.index
  nidx = pd.date_range(oidx.min(), oidx.max(), freq="30S")
  resampled["Value"] = df.Value.reindex(oidx.union(nidx)).interpolate('index').reindex(nidx)
  return pd.DataFrame([[len(df.index), len(resampled.index), df.index.min(), df.index.max()]], columns=["Count", "Resampled", "Start", "End"])

predictionStream = sensorStream.withWatermark("Timestamp", "90 minutes").groupBy(col("Name"), window(col("Timestamp"), "70 minutes", "5 minutes"))

predictionStream.apply(myudf).writeStream \
    .queryName("aggregates") \
    .format("memory") \
    .start()

流确实每5分钟获取新值。只是该窗口以某种方式仅从最后一批中获取值,即使水印不应该过期也是如此。

我在做错什么吗?我已经尝试过玩水印了。对结果没有影响。我需要udf内部窗口的所有值。

我在设置为5.5 LTS ML(包括Apache Spark 2.4.3,Scala 2.11)的群集上的数据砖中运行此程序

2 个答案:

答案 0 :(得分:0)

您似乎可以为writeStream指定所需的输出模式

See documentation at Output Modes

默认情况下,它使用附加模式:

  

这是默认模式,在该模式下,仅将自上次触发以来添加到结果表中的新行输出到接收器。

尝试使用:

predictionStream.apply(myudf).writeStream \
.queryName("aggregates") \
.format("memory") \
.outputMode(OutputMode.Complete) \
.start()

答案 1 :(得分:0)

我发现了一个关于此问题的 Spark JIRA issue,但它没有解决就关闭了。该错误似乎是,我在 Spark 3.1.1 版上独立确认了这一点,即 Pandas UDF 在每个触发器上仅使用自上次触发器以来的数据执行。因此,您可能只处理要在每个触发器中考虑的数据子集。 Grouped Map Pandas UDF 似乎不适用于具有增量表源的结构化流。如果您之前找到了解决方案,请继续跟进,否则我会把这个留在这里给也找到这个线程的人。

编辑:Databricks 论坛中有一些讨论,关于首先进行流式聚合,然后使用 Pandas UDF(可能需要一个包含数组的列的单个记录),如下所示。我尝试过这个。有用。但是,我的批处理持续时间很长,我不确定这些额外的工作对它的贡献有多大。

agg_exprs = [f.collect_list('col_of_interest_1'),
             f.collect_list('col_of_interest_2'),
             f.collect_list('col_of_interest_3')]
intermediate_sdf = source_sdf.groupBy('time_window', ...).agg(agg_exprs)

final_sdf = intermediate_sdf.groupBy('time_window', ...).applyInPandas(func, schema)