web-dev-qa-db-ja.com

ScalaでSparkSessionオブジェクトを作成して、ユニットテストとspark-submitの両方で使用するためのベストプラクティス)

DataFrameからDataFrameへの変換メソッドを記述しようとしました。そして、それをscalatestでテストしたいと思っています。

ご存知のように、Spark 2.x with Scala APIでは、次のようにしてSparkSessionオブジェクトを作成できます。

_import org.Apache.spark.sql.SparkSession

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

このコードは単体テストで正常に動作します。しかし、spark-submitでこのコードを実行すると、クラスターオプションが機能しませんでした。例えば、

_spark-submit --master yarn --deploy-mode client --num-executors 10 ...
_

エグゼキュータを作成しません。

上記のコードのconfig("master", "local[2]")部分を削除すると、spark-submit引数が適用されることがわかりました。しかし、マスター設定なしではユニットテストコードは機能しませんでした。

spark(SparkSession)オブジェクト生成部分をテストしてメインに分割しようとしましたが、スパークを必要とするコードブロックがたくさんあります。たとえば、_import spark.implicit,__およびspark.createDataFrame(rdd, schema)

テストとspark-submitの両方を実行するsparkオブジェクトを作成するコードを記述するベストプラクティスはありますか?

7
Joo-Won Jung

1つの方法は、SparkContext/SparkSessionを提供する特性を作成し、テストケースで次のように使用することです。

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
}

そして、あなたのテストクラスのヘッダーは、例えばこのようになります:

class TestWithSparkTest extends BaseSpec with SparkTestContext with Matchers{

4
Rick Moritz

テスト後にSparkが正しく閉じるバージョンを作成しました。

import org.Apache.spark.sql.{SQLContext, SparkSession}
import org.Apache.spark.{SparkConf, SparkContext}
import org.scalatest.{BeforeAndAfterAll, FunSuite, Matchers}

trait SparkTest extends FunSuite with BeforeAndAfterAll with Matchers {
  var ss: SparkSession = _
  var sc: SparkContext = _
  var sqlContext: SQLContext = _

  override def beforeAll(): Unit = {
    val master = "local[*]"
    val appName = "MyApp"
    val conf: SparkConf = new SparkConf()
      .setMaster(master)
      .setAppName(appName)
      .set("spark.driver.allowMultipleContexts", "false")
      .set("spark.ui.enabled", "false")

    ss = SparkSession.builder().config(conf).getOrCreate()

    sc = ss.sparkContext
    sqlContext = ss.sqlContext
    super.beforeAll()
  }

  override def afterAll(): Unit = {
    sc.stop()
    super.afterAll()
  }
}
2
Karima Rafes

パラメーター--masterが指定されたspark-submitコマンドは、yarnマスターを設定しています。そして、これは、master( "yarn")のように使用しても、コードmaster( "x")と競合します。

ToDF、toDS、またはその他のfuncのようなimport sparkSession.implicits._を使用したい場合は、以下のように作成されたローカルsparkSession変数を使用できます。

val spark = SparkSession.builder()。appName( "YourName")。getOrCreate()

ローカルマシンではなく、spark-submit --masterヤーンにmaster( "x")を設定しない。

私はアドバイスします。コードではグローバルsparkSessionを使用しないでください。これにより、いくつかのエラーまたは例外が発生する可能性があります。

これがお役に立てば幸いです。幸運を!

1
wusuo li

メソッドがMySparkSession.get()などのSparkSessionのシングルトンインスタンスを作成するオブジェクトを定義し、それを各ユニットテストでパラメーターとして渡します。

メインメソッドでは、個別のSparkSessionインスタンスを作成できます。これには、さまざまな構成を含めることができます。

0