この場合、コンパイラではなく、結果に影響を与えるのはSparkドライバです。 s
の重複した複製を作成しないように、Sparkが実行パイプラインを最適化できるかどうか。私は確信していませんが、私はスパークがメモリにrdd1pairs
を作成すると思います。 (String, String)
へ
代わりのマッピングあなたは(String, Unit)
使用できます。何をやっている
rdd1.map(s => (s,()))
を基本的にrdd1
に基づいてrdd2
のフィルタです。 rdd1がrdd2よりもかなり小さい場合、別の方法は、rdd1
のデータをRDDではなくブロードキャスト変数として表現し、単純にrdd2
をフィルタリングすることです。これにより、シャッフルまたはフェーズの削減が回避されるため、より速くなる可能性がありますが、rdd1
のデータが各ノードに収まるのに十分小さい場合にのみ機能します。
EDIT:この質問で説明したようにjstat
コマンドを使用して
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?:
がユニットを使用してどのように考えるのではなく文字列は、スペースを節約し、次の例を考えます最初のバージョンは後者よりもヒープの使用量が大幅に少なくなります。
編集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
}
2つのファイルは同じサイズのものである:
�� 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
は合理的ですね、ありがとう。しかし、私は、Unitへの参照をどのようにして元の文字列バリアントと比較してかなりの量のメモリを保存するのかまだまだわかりません。それは? – Carsten
そのトピックをカバーするために私の答えを拡張しました – mattinbits
しかし、元の質問では新しい文字列は作成されません。文字列への参照は、 '()'への参照と同じサイズです。 –