Scala Spark—当我从映射调用自定义函数时,会得到一个java.lang.UnsupportedOperationException

Scala Spark—当我从映射调用自定义函数时,会得到一个java.lang.UnsupportedOperationException,scala,apache-spark,spark-dataframe,Scala,Apache Spark,Spark Dataframe,我有一个数据帧,其结构类似于: root |-- NPAData: struct (nullable = true) | |-- NPADetails: struct (nullable = true) | | |-- location: string (nullable = true) | | |-- manager: string (nullable = true) | |-- service: array (nullable = true)

我有一个数据帧,其结构类似于:

root
 |-- NPAData: struct (nullable = true)
 |    |-- NPADetails: struct (nullable = true)
 |    |    |-- location: string (nullable = true)
 |    |    |-- manager: string (nullable = true)
 |    |-- service: array (nullable = true)
 |    |    |-- element: struct (containsNull = true)
 |    |    |    |-- serviceName: string (nullable = true)
 |    |    |    |-- serviceCode: string (nullable = true) 
 |-- NPAHeader: struct (nullable = true)
 |    |    |-- npaNumber: string (nullable = true)
 |    |    |-- date: string (nullable = true)
我想做的是:

  • 将具有相同编号的记录分组到列表中
  • 在每个列表中,根据元素的
    日期对元素进行排序
  • 一旦我对元素进行了分组和排序,我需要合并 应用一些逻辑的元素。要执行此列表步骤,我决定 使用地图
以下是我迄今为止所做的尝试:

val toUpdate = sourceDF.withColumn("count", count($"NPAHeader").over(Window.partitionBy("NPAHeader.npaNumber").orderBy($"NPAHeader.date".desc))).filter($"count" > 1)

val groupedNpa = toUpdate.groupBy($"NPAHeader.npaNumber" ).agg(collect_list(struct($"NPAData",$"NPAHeader")).as("npa"))

//This is a simply version of my logic.                                                                                                 
def pickOne(List: Seq[Row]): Row = {
      println("First element: "+List.get(0))
      List.get(0)
}

val mergedNpa = groupedNpa.map(row => (row.getAs[String]("npaNumber"),pickOne(row.getAs[Seq[Row]]("npa")))) 
groupBy后面的行示例如下:

[1234,WrappedArray([npaNew,npaOlder,…npaOlder])]

但是当我试图从映射中调用函数时,我遇到了一个异常

线程“main”java.lang.UnsupportedOperationException中出现异常:否 找到org.apache.spark.sql.Row的编码器 -字段(类:“org.apache.spark.sql.Row”,名称:“_2”) -根类:“scala.Tuple2”

我的理解是,我无法从映射中调用函数
pickOne()
(或者至少不能以我尝试的方式调用)。但我不知道我做错了什么

为什么我会有这样的例外

谢谢你的时间

注意:我知道有更简单的方法可以从列表中选择一个元素,而无需调用自定义函数。但我需要调用yes或yes,因为在下一步中,我需要在那里放置一个更复杂的逻辑来合并行

使用Mahesh Chand Kandpal建议后:

import org.apache.spark.sql.catalyst.encoders.RowEncoder

grouped.map(row => "emdNumber: "+row.getAs[String]("emdNumber"))
val mergedNpa = groupedNpa.map(row => (row.getAs[String]("npaNumber"),pickOne(row.getAs[Seq[Row]]("npa"))(RowEncoder(row.schema)))) 
我得到以下错误:

类型失配;发现: org.apache.spark.sql.catalyst.encoders.ExpressionEncoder[org.apache.spark.sql.Row] 必填项:Int


我应该如何应用编码器呢?

当您将map与数据帧一起使用时,需要指定编码器

在spark 2.x
Dataset[Row]中,映射为((Row)⇒ T) (编码器[T])⇒ 数据集[T]

import org.apache.spark.sql.catalyst.encoders.RowEncoder
implicit val encoder = RowEncoder(schema)

谢谢你的回答,但是出现了一个新的错误,请检查编辑。我认为你应该在地图之外的groupedNpa上提供编码器。implicit val encoder=RowEncoder(模式)给出数据帧的模式。同样的结果,我应该如何传递映射?如果可以显示groupedNpa。我可以试试我的贝壳。这是一个玩具的例子。我拥有的真正的一个要复杂得多。但是,您能否在回答中添加一行代码,说明如何使用编码器调用自定义函数?