Spark, suddividendo in modo ottimale un singolo RDD in due


10

Ho un set di dati di grandi dimensioni che devo dividere in gruppi in base a parametri specifici. Voglio che il lavoro venga elaborato nel modo più efficiente possibile. Posso immaginare due modi per farlo

Opzione 1 : creare una mappa dall'RDD originale e filtrare

def customMapper(record):
    if passesSomeTest(record):
        return (1,record)
    else:
        return (0,record)

mappedRdd = rddIn.map(lambda x: customMapper(x))
rdd0 = mappedRdd.filter(lambda x: x[0]==0).cache()
rdd1 = mappedRdd.filter(lambda x: x[1]==1).cache()

Opzione 2 : filtrare direttamente RDD originale

def customFilter(record):
    return passesSomeTest(record)

rdd0 = rddIn.filter(lambda x: customFilter(x)==False).cache()
rdd1 = rddIn.filter(customFilter).cache()

Il metodo del pugno deve iterare su tutti i record del set di dati originale 3 volte, in cui il secondo deve farlo solo due volte, in circostanze normali, tuttavia, spark fa un po 'dietro la costruzione del grafico delle scene, quindi potrei immaginare che siano fatto efficacemente allo stesso modo. Le mie domande sono: a.) Un metodo è più efficiente dell'altro o la creazione del grafico a scintilla li rende equivalenti b.) È possibile eseguire questa divisione in un unico passaggio


Ho anche trovato me stesso con un problema molto simile e non ho davvero trovato una soluzione. Ma ciò che effettivamente accade non è chiaro da questo codice, perché spark ha una "valutazione pigra" ed è presumibilmente in grado di eseguire solo ciò che deve realmente eseguire, e anche di combinare mappe, filtri e tutto ciò che può essere fatto insieme. Quindi forse ciò che descrivi può accadere in un unico passaggio. Tuttavia, non ho abbastanza familiarità con i pigri meccanismi di valutazione. In realtà ho appena notato .cache (). Forse c'è un modo di fare solo un .cache () e ottenere i risultati completi?
user3780968,

Risposte:


9

Prima di tutto, lascia che ti dica che non sono un esperto di Spark; L'ho usato parecchio negli ultimi mesi e credo che ora lo capisca, ma potrei sbagliarmi.

Quindi, rispondendo alle tue domande:

a.) sono equivalenti, ma non nel modo in cui lo vedi; Spark non ottimizzerà il grafico se ti stai chiedendo, ma customMapperverrà comunque eseguito due volte in entrambi i casi; questo è dovuto al fatto che per spark, rdd1e rdd2sono due RDD completamente diversi, e costruirà il grafico di trasformazione dal basso verso l'alto a partire dalle foglie; quindi l'opzione 1 si tradurrà in:

rdd0 = rddIn.map(lambda x: customMapper(x)).filter(lambda x: x[0]==0).cache()
rdd1 = rddIn.map(lambda x: customMapper(x)).filter(lambda x: x[0]==1).cache()

Come hai detto, customMapperviene eseguito due volte (inoltre, rddInverrà letto anche due volte, il che significa che se proviene da un database, potrebbe essere anche più lento).

b.) c'è un modo, devi solo spostarti cache()nel posto giusto:

mappedRdd = rddIn.map(lambda x: customMapper(x)).cache()
rdd0 = mappedRdd.filter(lambda x: x[0]==0)
rdd1 = mappedRdd.filter(lambda x: x[0]==1)

In questo modo, stiamo dicendo a Spark che può memorizzare i risultati parziali di mappedRdd; sarà poi utilizzare questi risultati parziali sia per rdd1e rdd2. Dal punto di vista della scintilla ciò equivale a:

mappedRdd = rddIn.map(lambda x: customMapper(x)).saveAsObjectFile('..')
# forget about everything
rdd0 = sc.objectFile('..').filter(lambda x: x[0]==0)
rdd1 = sc.objectFile('..').filter(lambda x: x[0]==1)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.