2015-09-04 9 views
6

Utilizzando Scala e Spark, ho il seguente costruzione:Come fa il compilatore Scala a gestire i valori delle variabili inutilizzate?

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 } 

ai fini della mappatura rdd1 in un PairRDD è il join con rdd2 nel passaggio successivo. Tuttavia, in realtà mi interessano solo i valori di rdd2, quindi il passo di mappatura nell'ultima riga che omette le chiavi. In realtà, si tratta di un'intersezione tra rdd2 e rdd1 eseguita con Spark join() per motivi di efficienza.

La mia domanda si riferisce ai tasti di rdd1pairs: vengono creati solo per motivi sintattici (per consentire l'unione) nella prima fase della mappa e vengono successivamente eliminati senza alcun utilizzo. Come fa il compilatore a gestirlo? Ha importanza in termini di consumo di memoria se utilizzo la stringa s (come mostrato nell'esempio)? Devo sostituirlo con null o 0 per risparmiare un po 'di memoria? Il compilatore effettivamente crea e memorizza questi oggetti (riferimenti) o si accorge che non vengono mai utilizzati?

risposta

3

In questo caso, penso che ciò che farà il driver Spark influenzi l'esito piuttosto che il compilatore. Spark può o meno ottimizzare la propria pipeline di esecuzione per evitare di creare la duplicazione ridondante di s. Non sono sicuro, ma penso che Spark creerà il rdd1pairs, in memoria.

Invece di mappatura per (String, String) si potrebbe usare (String, Unit):

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

Quello che stai facendo è fondamentalmente un filtro di rdd2 sulla base di rdd1. Se rdd1 è significativamente più piccolo di rdd2, un altro metodo sarebbe quello di rappresentare i dati di rdd1 come variabile di trasmissione piuttosto che un RDD e semplicemente di filtrare rdd2. Ciò evita qualsiasi shuffling o riduzione della fase, quindi potrebbe essere più veloce, ma funzionerà solo se i dati di rdd1 sono sufficientemente piccoli da adattarsi a ciascun nodo.

EDIT:

Considerando quanto utilizzando unità anziché String risparmiare spazio, considerare i seguenti esempi:

object size extends App { 

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

e

object size extends App { 

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

Utilizzo del comando jstat come descritto in questa domanda How to check heap usage of a running JVM from the command line? la prima versione utilizza molto meno heap rispetto alla seconda.

Edit 2:

Unit è effettivamente un oggetto Singleton senza contenuti, così logicamente, non dovrebbe richiedere alcuna serializzazione. Il fatto che la definizione del tipo contenga Unit ti dice tutto ciò che ti serve per poter deserializzare una struttura che ha un campo di tipo Unità.

Spark utilizza la serializzazione Java per impostazione predefinita.Si consideri il seguente:

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 
} 

I due file sono di dimensioni identiche:

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

e

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

sembra ragionevole, grazie. Tuttavia, non sono ancora sicuro di come memorizzare i riferimenti all'unità consente di risparmiare una quantità significativa di memoria rispetto alla variante di stringa originale. Lo fa? – Carsten

+0

Ho esteso la mia risposta per coprire quell'argomento – mattinbits

+1

Ma nella domanda originale non vengono create nuove stringhe. Un riferimento a una stringa ha le stesse dimensioni di un riferimento a '()'. –

Problemi correlati