2015-09-04 54 views
6

使用Scala和火花,我有以下结构:Scala编译器如何处理未使用的变量值?

val rdd1: RDD[String] = ... 
val rdd2: RDD[(String, Any)] = ... 

val rdd1pairs = rdd1.map(s => (s, s)) 
val result = rdd2.join(rdd1pairs) 
       .map { case (_: String, (e: Any, _)) => e } 

映射rdd1的目的成PairRDD是在随后的步骤与rdd2加入。但是,我实际上只对rdd2的值感兴趣,因此最后一行中的映射步骤省略了密钥。实际上,出于效率原因,这是用Spark的join()执行的rdd2rdd1之间的交点。

我的问题涉及到rdd1pairs的键:它们仅在第一个映射步骤中为语法原因(允许连接)创建,后来被丢弃而没有任何用法。编译器如何处理这个问题?无论我使用字符串s(如示例中所示),是否在内存消耗方面都很重要?我应该用null还是0替换它以节省一点存储空间?编译器是否实际创建和存储这些对象(引用),还是会注意到它们从未被使用过?

回答

3

在这种情况下,我认为Spark驱动程序会做的事情会影响结果,而不是编译器。 Spark是否可以优化执行流水线以避免产生冗余重复s。我不确定,但我认为Spark会在内存中创建rdd1pairs

而是映射(String, String)的,你可以使用(String, Unit)

rdd1.map(s => (s,())) 

你在做什么基本上是基于rdd1rdd2过滤器。如果rdd1明显小于rdd2,另一种方法是将rdd1的数据表示为广播变量而不是RDD,并且只需过滤rdd2即可。这样可以避免任何混洗或缩短阶段,因此可能会更快,但只有在rdd1的数据足够小才能适合每个节点时才能工作。

编辑:

考虑如何使用单位,而不是字符串节省空间,可以考虑下面的例子:

object size extends App { 

    (1 to 1000000).map(i => ("foo"+i,())) 
    val input = readLine("prompt> ") 
} 

object size extends App { 

    (1 to 1000000).map(i => ("foo"+i, "foo"+i)) 
    val input = readLine("prompt> ") 
} 

在这个问题How to check heap usage of a running JVM from the command line?描述使用jstat命令第一个版本比后者使用的堆少得多。

编辑2:

Unit实际上是没有内容的单独的对象,所以从逻辑上讲,它不应该要求任何序列化。类型定义包含Unit的事实告诉你所有你需要能够反序列化一个具有Unit类型字段的结构。

Spark默认使用Java序列化。考虑以下几点:

object Main extends App { 

    import java.io.{ObjectOutputStream, FileOutputStream} 

    case class Foo (a: String, b:String) 
    case class Bar (a: String, b:String, c: Unit) 

    val str = "abcdef" 
    val foo = Foo("abcdef", "xyz") 
    val bar = Bar("abcdef", "xyz",()) 

    val fos = new FileOutputStream("foo.obj") 
    val fo = new ObjectOutputStream(fos) 
    val bos = new FileOutputStream("bar.obj") 
    val bo = new ObjectOutputStream(bos) 
    fo writeObject foo 
    bo writeObject bar 
} 

这两个文件是相同的大小:

�� sr Main$Foo3�,�z \ L at Ljava/lang/String;L bq ~ xpt abcdeft xyz 

�� sr Main$Bar+a!N��b L at Ljava/lang/String;L bq ~ xpt abcdeft xyz 
+0

听起来有道理,谢谢。但是,我仍然不确定与原始字符串变体相比,如何存储对Unit的引用可以节省大量的内存。可以? – Carsten

+0

扩展了我的答案以覆盖该主题 – mattinbits

+1

但在原始问题中没有创建新的字符串。对String的引用与对'()'的引用的大小相同。 –

相关问题