在Spark Streaming中使用UDF将collect_list列转换为其他数据类型列

时间:2018-07-04 09:24:33

标签: scala apache-spark spark-streaming

请求是合并来自2个流传输源的数据,然后减少相同的键,然后对这些值应用函数以将其转换为另一个UDO(用户定义的对象类型)。我不知道该怎么做。所以在这里我只是创建了一个类似的问题,如下所示:

2个输入流具有3列,即id,value和posttime。我们首先对其进行合并,然后根据id进行归约,然后生成带有值(id,用户定义的函数(值,发布时间))的最终结果。如何实现呢?

如果我按以下方式实现它:

val dff = df.union(df2)
  .withWatermark("posttime", "15 minutes")
  .groupBy(window($"posttime", "10 minutes", "5 minutes"),$"id")
  .agg(collect_list(struct("value", "posttime")).as("data"))
  .withColumn("data", user-defined-function("data"))

我应该如何定义用户定义的函数来输入列并输出具有不同数据类型的列?

// How to tranform the Column (Type: A) to output Column (Type: B)
def user-defined-function(columnName: String): Column = {
  val x = Column(columnName).cast(List<struct>)
  val ptime = if(x.posttime < y.posttime) x.posttime else y.posttime
  val value = (x.value.toInt + y.value.toInt).toString
  return new Column(struct(value, ptime))
}

2 个答案:

答案 0 :(得分:0)

通常,您将这样定义一个UDF:

import org.apache.spark.sql.functions.udf
import org.apache.spark.sql.Row

// assumption: value is of type double, posttime is timestamp
val myUDF = udf((data:Seq[Row]) => {
  val x: Seq[(Double, Timestamp)] = data.map{case Row(x:Double,y:java.sql.Timestamp) => (x,y)}

  // do something with x 

})

UDF的返回类型由最后一个表达式的类型给出。您无需在UDF中创建Column,只需使用普通的Scala类型

答案 1 :(得分:0)

我已经看过您的UDF和您要做什么。我已经以优化方式修改了您的登录信息。只需检查一下,您是否会获得预期的结果。

val dff = df.union(df2)
  .withWatermark("posttime", "15 minutes")
  .groupBy(window($"posttime", "10 minutes", "5 minutes"),$"id")
  .agg(struct(sum($"value").as("value"), min($"posttime").as("posttime")).as("data"))

val dff = df.union(df2)
  .withWatermark("posttime", "15 minutes")
  .groupBy(window($"posttime", "10 minutes", "5 minutes"),$"id")
  .agg(sum($"value").as("value"), min($"posttime").as("posttime"))