2017-07-31 3 views
3

J'ai essayé d'écrire une méthode de transformation de DataFrame à DataFrame. Et je veux aussi le tester par scalatest.Meilleure pratique pour créer un objet SparkSession dans Scala pour l'utiliser à la fois dans unittest et spark-submit

Comme vous le savez, en 2.x Spark avec l'API Scala, vous pouvez créer un objet SparkSession comme suit:

import org.apache.spark.sql.SparkSession 

val spark = SparkSession.bulider 
    .config("spark.master", "local[2]") 
    .getOrCreate() 

Ce code fonctionne très bien avec les tests unitaires. Cependant, lorsque j'exécute ce code avec spark-submit, les options du cluster ne fonctionnent pas. Par exemple,

spark-submit --master yarn --deploy-mode client --num-executors 10 ... 

ne crée pas de exécuteurs.

J'ai trouvé que les arguments spark-submit sont appliqués lorsque je supprime config("master", "local[2]") partie du code ci-dessus. Mais, sans le réglage principal, le code de test de l'unité n'a pas fonctionné.

J'ai essayé de diviser la partie de génération d'objet spark (SparkSession) en test et en main. Mais il y a tellement de blocs de code qui ont besoin d'étincelles, par exemple import spark.implicit,_ et spark.createDataFrame(rdd, schema).

Existe-t-il une meilleure pratique pour écrire un code pour créer un objet spark à la fois pour tester et pour exécuter spark-submit?

+1

Pourquoi ne pas utiliser '.config (" master "," yarn-client ")' dans scala? –

+1

@ cricket_007 Parce que je veux exécuter le test en mode local (sur mon ordinateur portable) et exécuter le code dans divers environnements qui peuvent être spécifiés par les options spark-submit. –

+0

Je ne comprends pas le problème, alors. Bien sûr, vous devez réécrire les instructions d'importation dans votre code de test unitaire. –

Répondre

1

Une façon est de créer un trait qui fournit le SparkContext/SparkSession, et l'utiliser dans vos cas de test, comme ceci:

trait SparkTestContext { 
    private val master = "local[*]" 
    private val appName = "testing" 
    System.setProperty("hadoop.home.dir", "c:\\winutils\\") 
    private val conf: SparkConf = new SparkConf() 
    .setMaster(master) 
    .setAppName(appName) 
    .set("spark.driver.allowMultipleContexts", "false") 
    .set("spark.ui.enabled", "false") 

    val ss: SparkSession = SparkSession.builder().config(conf).enableHiveSupport().getOrCreate() 
    val sc: SparkContext = ss.sparkContext 
    val sqlContext: SQLContext = ss.sqlContext 
} 

Et votre en-tête de classe de test ressemble alors à ceci par exemple:

class TestWithSparkTest extends BaseSpec with SparkTestContext with Matchers{

0

Comment définir un objet au sujet dans lequel un procédé crée une instance singleton de SparkSession, comme MySparkSession.get(), et le transmettre comme paramter dans chacun de vos tests unitaires.

Dans votre méthode principale, vous pouvez créer une instance SparkSession distincte, qui peut avoir différentes configurations.