在SparkContext.scala
中,有两个为基本类型定义的到其可写对应项的隐式转换,例如Int,Long,String
。
以String为例,有两种定义,定义如下:
implicit def stringWritableConverter(): WritableConverter[String] =
simpleWritableConverter[String, Text](_.toString)
字符串
和
implicit val stringWritableConverterFn: () => WritableConverter[String] =
() => simpleWritableConverter[String, Text](_.toString)
型
我想问一下这些方法和变量是如何使用的。它们用于隐式类型转换,但没有输入参数(stringWritableConverter
不带参数,stringWritableConverterFn
也不带参数)。
这些隐式转换是如何被转换为WritableConverter
的
它们没有参数,我只是不知道如何/何时使用这些转换
谢谢.
更新
为了更好地用代码来说明问题,我编写了以下简单的代码来减少Spark
import scala.reflect.{ClassTag, classTag}
trait Writable
class IntWritable(value: Int) extends Writable
class Text(value: String) extends Writable
class WritableConverter[T](
val writableClass: ClassTag[T] => Class[_ <: Writable],
val convert: Writable => T)
object implicit_test {
private def simpleWritableConverter[T, W <: Writable : ClassTag](convert: W => T)
: WritableConverter[T] = {
println("Hello, simpleWritableConverter")
val wClass = classTag[W].runtimeClass.asInstanceOf[Class[W]]
new WritableConverter[T](_ => wClass, x => convert(x.asInstanceOf[W]))
}
implicit val stringWritableConverterFn: () => WritableConverter[String] = {
println("Hello stringWritableConverterFn")
() => simpleWritableConverter[String, Text](_.toString)
}
implicit def stringWritableConverter(): WritableConverter[String] = {
println("Hello stringWritableConverter")
simpleWritableConverter[String, Text](_.toString)
}
def do_convert(a: String) = println(s"a is $a")
def main(args: Array[String]): Unit = {
//Compile Error: Required String, Found Text
do_convert(new Text("abc"))
}
}
型
当我调用do_convert(new Text("abc"))
时,编译器会抱怨Required String, Found Text
,这意味着隐式转换没有生效。
1条答案
按热度按时间fcwjkofz1#
我并不是100%理解这个故事,但我觉得我可能会给你带来一些有用的见解。我将使用Spark版本3.4.1源代码(以及相应的Hadoop版本3.3.4)进行解释。
整个故事看起来有点像这样:
字符串
这些可复制对象是什么?
我在这里引用this great answer的一部分:
我们已经知道,在分布式计算环境中,数据需要在不同节点之间传输。这需要数据的序列化和重复化,以将结构化格式的数据转换为字节流,反之亦然。因此,Hadoop使用简单高效的序列化协议在map和reduce阶段之间序列化数据,这些称为可重复性(s)前面已经提到的一些可写的例子是不可写的,可写的,布尔可写的和浮点可写的。
因此,我们知道在使用Hadoop时,我们将跳转到一堆这样的
Writable
对象上。为了使用原语类型进行可靠的计算,我们需要有一种方法从Writable
转到我们的原语。为什么我们看起来有两个
stringWritableConverter
?如果你仔细看我贴在这里的代码注解,你会发现
stringWritableConverter
和stringWritableConverterFn
做的事情完全一样。所以我们可以简化我们的问题:这里只有
stringWritableConverterFn
重要。这个
stringWritableConverterFn
会发生什么?在Scala中,implant是在编译时解析的。所以在编译时,下面的代码将被调用:
型
请密切注意这里的类型
[String, Text]
。String
是原始类型,Text
是Writable
类org.apache.hadoop.io.Text
。让我们单独看看
simpleWritableConverter
函数:型
因此,创建了一个新的
WritableConverter
对象,它存储了两件事:convert
函数,其签名为W => T
。这是Hadoop中Text
的toString
方法。总结
在Hadoop中,可转换类被广泛使用。如果我们希望能够检索它们所表示的原语类型,我们需要能够将这些类转换为它们的原语类型。这就是这些
WritableConverter
对象的用途。最后,我们创建了这个
WritableConverter[String]
类,它包含了一种通过toString
方法将Text
可转换为String
原语的方法!回复您的更新
如果你想看看这个转换器的实际效果,你可以看一个测试示例:
型
在这里,您可以看到我们创建了这个
converter
对象,它可以使用其convert
方法(来自本文开头的WritableConverter[T]
类)为您进行转换。这个例子的不同之处在于,你没有调用
WritableConverter
的convert
方法。所以Scala找不到任何将Text
转换为String
的函数。