当前位置: 首页 > 知识库问答 >
问题:

使用火花 udf 在斯卡拉的范围内进行模式匹配

芮承运
2023-03-14

我有一个包含字符串的Spark数据帧,我使用Likert量表将这些字符串与数字分数进行匹配。不同的问题id对应不同的分数。我尝试在Apache Spark udf中的Scala范围内进行模式匹配,使用这个问题作为指导:

如何在Scala的一个范围内进行模式匹配?

但是当我使用范围而不是简单的OR语句时,我遇到了编译错误,即

<code>31|32| 33|;34

31 到 35 无法编译。任何想法,我在语法上出错了吗?

此外,在最后一种情况下,我希望映射到字符串而不是Int,case_=

想必这是Spark的一个共性问题,因为在原生Scala中完全有可能返回< code>Any

这是我的代码:

def calculateScore = udf((questionId: Int, answerText: String) => (questionId, answerText) match {

      case ((31 | 32 | 33 | 34 | 35), "Rarely /<br>Never") => 4 //this is fine
      case ((31 | 32 | 33 | 34 | 35), "Occasionally") => 3
      case ((31 | 32 | 33 | 34 | 35), "Often") => 2
      case ((31 | 32 | 33 | 34 | 35), "Almost always /<br>Always") => 1
      case ((x if 41 until 55 contains x), "None of the time") => 1 //this line won't compile
      case _ => 0 //would like to map to "None"
    })

然后,udf用于Spark数据帧,如下所示:

val df3 = df.withColumn("NumericScore", calculateScore(df("QuestionId"), df("AnswerText")))

共有2个答案

高晋
2023-03-14

如果您想将最后一个case,即case_映射为“无”String,那么所有的case都应该返回String以及

遵循udf函数应该适合您

def calculateScore  = udf((questionId: Int, answerText: String) => (questionId, answerText) match {
  case ((31 | 32 | 33 | 34 | 35), "Rarely /<br>Never") => "4" //this is fine
  case ((31 | 32 | 33 | 34 | 35), "Occasionally") => "3"
  case ((31 | 32 | 33 | 34 | 35), "Often") => "2"
  case ((31 | 32 | 33 | 34 | 35), "Almost always /<br>Always") => "1"
  case (x, "None of the time") if (x >= 41 && x < 55) => "1" //this line won't compile
  case _ => "None"
})

如果要将最后一个事例(即 case _ 映射到 None),则需要将其他返回类型更改为 Option 的子,因为 None 是 Option 的子

以下代码也应该适合您

def calculateScore  = udf((questionId: Int, answerText: String) => (questionId, answerText) match {
  case ((31 | 32 | 33 | 34 | 35), "Rarely /<br>Never") => Some(4) //this is fine
  case ((31 | 32 | 33 | 34 | 35), "Occasionally") => Some(3)
  case ((31 | 32 | 33 | 34 | 35), "Often") => Some(2)
  case ((31 | 32 | 33 | 34 | 35), "Almost always /<br>Always") => Some(1)
  case (x, "None of the time") if (x >= 41 && x < 55) => Some(1) //this line won't compile
  case _ => None
})

最后一点是,您有 java.lang.不受支持的错误消息操作异常:不支持类型 Any 的架构明确指出不支持返回类型为 Anyudf 函数不受支持。匹配案例中的所有返回类型都应保持一致。

姚星宇
2023-03-14

保护表达式应放在模式之后:

def calculateScore = udf((questionId: Int, answerText: String) => (questionId, answerText) match {
  case ((31 | 32 | 33 | 34 | 35), "Rarely /<br>Never") => 4 
  case ((31 | 32 | 33 | 34 | 35), "Occasionally") => 3
  case ((31 | 32 | 33 | 34 | 35), "Often") => 2
  case ((31 | 32 | 33 | 34 | 35), "Almost always /<br>Always") => 1
  case (x, "None of the time") if 41 until 55 contains x => 1
  case _ => 0 //would like to map to "None"
})
 类似资料:
  • 我尝试使用I forest https://github.com/titicaca/spark-iforest,的scala实现,但是当我构建时(就像README中报告的< code>mvn clean package),它给我这些错误: 有人知道为什么吗?谢谢 scala版本2.11.12 火花版本2.4.0 maven版本3.5.2 我修改了pom.xml,调整了scala、spark和mav

  • 如何将多个列对分解为多行? 我有一个包含以下内容的数据帧 我想要一个最终的数据帧,如下所示 我试着使用下面的代码,但是它返回了4条记录,而不是我想要的两条记录

  • 我有一个用斯卡拉写的UDF,我希望能够通过Pyspark会话调用它。UDF 采用两个参数:字符串列值和第二个字符串参数。我已经能够成功地调用UDF,如果它只需要一个参数(列值)。如果需要多个参数,我很难调用UDF。以下是到目前为止我在斯卡拉和Pyspark中能够做的事情: Scala UDF: 在Scala中使用它时,我已经能够注册和使用这个UDF: Scala主类: 以上工作成功。下面是Pysp

  • 将现有应用程序从Spark 1.6移动到Spark 2.2*(最终)会导致错误“org.apache.spark.SparkExctive:任务不可序列化”。我过于简化了我的代码,以演示同样的错误。代码查询拼花文件以返回以下数据类型:“org.apache.spark.sql.数据集[org.apache.spark.sql.行]”我应用一个函数来提取字符串和整数,返回字符串。一个固有的问题与Sp

  • 我有一个要求,火花UDF必须超载,我知道UDF超载是不支持火花。因此,为了克服spark的这一限制,我尝试创建一个接受任何类型的UDF,它在UDF中找到实际的数据类型,并调用相应的方法进行计算并相应地返回值。这样做时,我得到一个错误 以下是示例代码: 有可能使上述要求成为可能吗?如果没有,请建议我一个更好的方法。 注:Spark版本-2.4.0

  • 我在火花数据帧中有一个“结构类型”列,它有一个数组和一个字符串作为子字段。我想修改数组并返回相同类型的新列。我可以用UDF处理它吗?或者有什么替代方案? 似乎我需要行类型的UDF,类似 这是有意义的,因为Spark不知道返回类型的模式。不幸的是,udf.register也失败了: