Scala:未指定的值参数证据$ 3

时间:2016-01-12 09:59:29

标签: scala apache-spark

我环顾四周,发现了其他几个例子,但我并不真正了解这些答案究竟发生了什么。

我想了解为什么以下代码无法编译:

val df = readFiles(sqlContext).
    withColumn("timestamp", udf(UDFs.parseDate _)($"timestamp"))

给出错误:

Error:(29, 58) not enough arguments for method udf: (implicit evidence$2: reflect.runtime.universe.TypeTag[java.sql.Date], implicit evidence$3: reflect.runtime.universe.TypeTag[String])org.apache.spark.sql.UserDefinedFunction.
Unspecified value parameter evidence$3.
            withColumn("timestamp", udf(UDFs.parseDate _)($"timestamp")).
                                                         ^

此代码 编译:

val parseDate = udf(UDFs.parseDate _)
val df = readFiles(sqlContext).
    withColumn("timestamp", parseDate($"timestamp"))

显然我找到了“解决方法”,但我真的很想理解:

  1. 这个错误究竟意味着什么。我在TypeTagClassTag找到的信息真的很难理解。我不是来自Java背景,这可能没有帮助,但我想我应该能够掌握它......
  2. 如果没有单独的功能定义,我可以实现我想要的目标

1 个答案:

答案 0 :(得分:6)

错误消息确实有点误导;原因是函数udf采用隐式参数列表,但您传递的是实际参数。由于我不太了解spark,因为udf签名有点复杂,我会尝试用简化的例子来解释发生了什么。

实际上udf是一个给出一些显式参数的函数,一个隐式参数列表为你提供了另一个函数;让我们定义以下函数,给定pivot类型为T的{​​{1}},我们有一个隐式Ordering将作为一个函数,允许我们将一个序列拆分为两个,一个包含小于pivot的元素,另一个包含更大的元素:

def buildFn[T](pivot: T)(implicit ev: Ordering[T]): Seq[T] => (Seq[T], Seq[T]) = ???

让我们忽略实施,因为它并不重要。现在,如果我执行以下操作:

val elements: Seq[Int] = ???
val (small, big) = buildFn(10)(elements)

我会在你的代码中犯同样的错误,即编译器会认为我明确地将elements作为隐式参数列表传递,这不会编译。我的示例的错误消息将与您拥有的错误消息有所不同,因为在我的情况下,我错误地为隐式参数列表传递的参数数量与预期参数列表匹配,然后错误将是关于不排队的类型。

相反,如果我把它写成:

val elements: Seq[Int] = ???
val fn = buildFn(10)
val (small, big) = fn(elements)

在这种情况下,编译器将正确地将隐式参数传递给函数。我不知道有什么办法可以绕过这个问题,除非你想明确地传递实际的隐含参数,但我觉得它很丑陋而且并不总是实用的;作为参考,这就是我的意思:

val elements: Seq[Int] = ???
val (small, big) = buildFn(10)(implicitly[Ordering[Int]])(elements)