【问题标题】:Spark sequences [int] comparison with [String] sequence ouputSpark 序列 [int] 与 [String] 序列输出的比较
【发布时间】:2017-05-09 04:57:12
【问题描述】:

我试图比较两个不同列中的整数包装数组并将评级作为字符串:

import org.apache.spark.sql.Row
import org.apache.spark.sql.functions._
import scala.collection.mutable.WrappedArray

DataFrame 数据的 A 列和 B 列带有我想比较的包装数组:

val data = Seq(
    (Seq(1,2,3),Seq(4,5,6),Seq(7,8,9)),
    (Seq(1,1,3),Seq(6,5,7),Seq(11,9,8))
    ).toDF("A","B","C")

下面是它的样子:

data: org.apache.spark.sql.DataFrame = [A: array<int>, B: array<int> ... 1 more field]
+---------+---------+----------+
|        A|        B|         C|
+---------+---------+----------+
|[1, 2, 3]|[4, 5, 6]| [7, 8, 9]|
|[1, 1, 3]|[6, 5, 7]|[11, 9, 8]|
+---------+---------+----------+

然后这里是用户定义函数,我想比较每行 A 列和 B 列中配对数组中的每个元素,并用简单的逻辑给出评级。例如,如果 A(1) > B(1),则 D(1) 为“顶部”。所以作为D列的第一行,我希望有[“Top”,“Top”,“Top”]

def myToChar(num1: Seq[Int], num2: Seq[Int]): Seq[String] = {
        val twozipped = num1.zip(num2)
        for ((x,y) <- num1.zip(num2)) {
          if (x > y)  "Top"
          if (x < y)  "Well"
          if (x == y)  "Good"
    }}


val udfToChar = udf(myToChar(_: Seq[Int], _: Seq[Int]))

val ouput = data.withColumn("D",udfToChar($"A",$"B"))

但是,我不断收到&lt;console&gt;:45: error: type mismatch; 错误信息。不确定我的 udf() 类型定义是否错误,感谢任何指导以纠正我的错误。

【问题讨论】:

    标签: arrays scala apache-spark udf


    【解决方案1】:

    您的myToChar 定义被声明为返回Seq[String] - 但它的实现没有 - 它返回Unit,因为for 表达式(没有yield 子句)具有Unit 类型。

    您可以通过修复函数的实现来解决此问题:

    • for 替换为map 操作
    • 将最后一个if 替换为else,否则映射函数还会为不符合任何if 条件的输入返回Unit(与模式匹配不同,编译器无法断定您的if 条件是详尽无遗的 - 它必须假设也有可能它们都不成立)

    所以 - 一个正确的实现应该是:

    def myToChar(num1: Seq[Int], num2: Seq[Int]): Seq[String] = {
      num1.zip(num2).map { case (x, y) =>
        if (x > y) "Top"
        if (x < y) "Well"
        else "Good"
      }
    } 
    

    或者使用带有守卫的模式匹配:

    def myToChar(num1: Seq[Int], num2: Seq[Int]): Seq[String] = {
      num1.zip(num2).map {
        case (x, y) if x > y => "Top"
        case (x, y) if x < y => "Well"
        case _ => "Good"
      }
    }
    

    【讨论】:

    • 确实感谢您的回答。我可以向您了解num1.zip(num2).foreach()num1.zip(num2).map() 之间的区别吗?我的愚蠢想法是foreach() 将遍历每个元素...
    • map 需要一个函数将每个元素转换为一个新元素(可能是不同的类型),因此返回一个包含转换后元素的新序列; foreach 需要一个对每个元素操作且不返回值的函数(从技术上讲,返回Unit),因此foreach 表达式本身返回一个值(再次 - Unit)。因此,foreach 在您想引起一些“副作用”(例如写入日志、持久化到磁盘、通过网络发送等)时很有用,而map 在您想返回值时很有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-17
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    相关资源
    最近更新 更多