我对于Object Orientend和功能性编程都很新,所以如果我在这里问一个愚蠢的问题,请原谅我。我已经彻底搜查并试图找到自己几个小时的答案,但无济于事。
我在scala上使用Spark2时遇到以下问题。
我有两个Dataframe,我想传递给UDF,它应该输出一个结果Dataframe。为了简单起见,我创造了两个" test"数据框作为输入。
val seqs = List(("1234","abaab"), ("1235","aaab")).toDF
val actions = List(1,2).toDF
动作列表数据框将转换为字符串数组,例如:
val actionsARR = actions.rdd.map(x=>(x.getInt(0)+96).toChar.toString).collect()
然后我们有一个UDF来计算seqs中动作的出现次数:
def countActions(sequence:String, actions:Array[String]):Array[Int] = {
return actions.map(x => x.r.findAllIn(sequence).size)
}
放在一起:
val results = seqs.map(x=>(x.getString(0), countActions(x.getString(1),actionsARR))).toDF("sequence_u_key","action_counter")
这在另一个运行一个命令的spark shell中工作正常,我现在尝试将代码嵌入到另一个接受Dataframes作为输入的UDF中:
def testFun(seqsin:DataFrame, actionsin:DataFrame ): DataFrame ={
seqsin.map(x=>(x.getString(0), countActions(x.getString(1),actionsARR))).toDF("sequence_u_key","action_counter")
}
用以下方式调用:
testFun(seqs,actions).show
有效,但它目前还没有使用Dataframe actionsin,但已经从中创建了名为actionsARR的数组。
当然我希望它在Dataframe中执行操作并将其转换为UDF中的Array,所以我尝试了:
def testFun(seqsin:DataFrame, actionsin:DataFrame ): DataFrame ={
val acts = actionsin.rdd.map(y=>(y.getInt(0)+96).toChar.toString).collect()
seqsin.map(x=>(x.getString(0), countActions(x.getString(1),acts))).toDF("sequence_u_key","action_counter")
}
但是当我用我的数据帧作为输入调用该函数时,我得到:
testFun(seqs,actions).show 17/07/19 07:31:32 ERROR Executor:Exception 在阶段38.0中的任务0.0(TID 64)java.lang.ClassCastException 17/07/19 07:31:32 WARN TaskSetManager:阶段38.0中丢失了任务0.0 (TID 64,localhost,executor driver):java.lang.ClassCastException
17/07/19 07:31:32 ERROR TaskSetManager:阶段38.0中的任务0失败1 倍;中止工作17/07/19 07:31:32 WARN TaskSetManager:丢失任务 阶段38.0中的1.0(TID 65,localhost,执行程序驱动程序):TaskKilled(故意杀死)org.apache.spark.SparkException:作业已中止 由于阶段失败:阶段38.0中的任务0失败1次,最近一次 失败:阶段38.0中丢失的任务0.0(TID 64,localhost,执行者 driver):java.lang.ClassCastException
驱动程序堆栈跟踪:at org.apache.spark.scheduler.DAGScheduler.org $阿帕奇$火花$ $调度$$ DAGScheduler failJobAndIndependentStages(DAGScheduler.scala:1435) 在 org.apache.spark.scheduler.DAGScheduler $$ anonfun $ abortStage $ 1.适用(DAGScheduler.scala:1423) 在 org.apache.spark.scheduler.DAGScheduler $$ anonfun $ abortStage $ 1.适用(DAGScheduler.scala:1422) 在 scala.collection.mutable.ResizableArray $ class.foreach(ResizableArray.scala:59) 在scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48) 在 org.apache.spark.scheduler.DAGScheduler.abortStage(DAGScheduler.scala:1422) 在 org.apache.spark.scheduler.DAGScheduler $$ anonfun $ handleTaskSetFailed $ 1.适用(DAGScheduler.scala:802) 在 org.apache.spark.scheduler.DAGScheduler $$ anonfun $ handleTaskSetFailed $ 1.适用(DAGScheduler.scala:802) 在scala.Option.foreach(Option.scala:257)at org.apache.spark.scheduler.DAGScheduler.handleTaskSetFailed(DAGScheduler.scala:802) 在 org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.doOnReceive(DAGScheduler.scala:1650) 在 org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.onReceive(DAGScheduler.scala:1605) 在 org.apache.spark.scheduler.DAGSchedulerEventProcessLoop.onReceive(DAGScheduler.scala:1594) 在org.apache.spark.util.EventLoop $$ anon $ 1.run(EventLoop.scala:48)
在 org.apache.spark.scheduler.DAGScheduler.runJob(DAGScheduler.scala:628) 在org.apache.spark.SparkContext.runJob(SparkContext.scala:1918)at org.apache.spark.SparkContext.runJob(SparkContext.scala:1931)at at org.apache.spark.SparkContext.runJob(SparkContext.scala:1944)at at org.apache.spark.SparkContext.runJob(SparkContext.scala:1958)at at org.apache.spark.rdd.RDD $$ anonfun $ collect $ 1.apply(RDD.scala:935)at at org.apache.spark.rdd.RDDOperationScope $ .withScope(RDDOperationScope.scala:151) 在 org.apache.spark.rdd.RDDOperationScope $ .withScope(RDDOperationScope.scala:112) 在org.apache.spark.rdd.RDD.withScope(RDD.scala:362)at org.apache.spark.rdd.RDD.collect(RDD.scala:934)at testFun(:44)... 52 elided由以下原因引起: java.lang.ClassCastException
也许我尝试将两个Dataframe传递给一个函数,将一个Dataversion转换为一个数组,然后在函数中使用它们,从根本上做了一些错误的事情?或许我错过了一些简单的东西?
哦,我可以成功创建一个函数,它接受一个Dataframe并转换并将其作为数组返回。
任何帮助将不胜感激
最好的问候
詹姆斯