web-dev-qa-db-ja.com

scalaを使用してpostgreSQLデータベースに接続してApache Sparkに接続するにはどうすればよいですか?

Scalaで物事をフォローするにはどうすればよいですか?

  1. Spark= scala。を使用してpostgreSQLデータベースに接続します。
  2. SELECT、UPDATEなどのSQLクエリを記述して、そのデータベースのテーブルを変更します。

私はscalaを使用してそれを行うことを知っていますが、psqlのコネクタjarをscalaをパッケージングしながらsbtにインポートする方法は?

37
febinsathar

私たちの目標は、Sparkワーカーから並列SQLクエリを実行することです。

ビルドのセットアップ

build.sbtlibraryDependenciesにコネクタとJDBCを追加します。私はこれをMySQLでのみ試したので、私の例でそれを使用しますが、Postgresはほとんど同じです。

libraryDependencies ++= Seq(
  jdbc,
  "mysql" % "mysql-connector-Java" % "5.1.29",
  "org.Apache.spark" %% "spark-core" % "1.0.1",
  // etc
)

コード

SparkContextを作成するとき、どのjarをエグゼキューターにコピーするかを指定します。コネクタjarを含めます。これを行うための見栄えの良い方法:

val classes = Seq(
  getClass,                   // To get the jar with our own code.
  classOf[mysql.jdbc.Driver]  // To get the connector.
)
val jars = classes.map(_.getProtectionDomain().getCodeSource().getLocation().getPath())
val conf = new SparkConf().setJars(jars)

これでSparkはデータベースに接続する準備ができました。各エグゼキュータはクエリの一部を実行するので、結果は分散計算の準備ができています。

これには2つのオプションがあります。古いアプローチは org.Apache.spark.rdd.JdbcRDD を使用することです:

val rdd = new org.Apache.spark.rdd.JdbcRDD(
  sc,
  () => {
    sql.DriverManager.getConnection("jdbc:mysql://mysql.example.com/?user=batman&password=alfred")
  },
  "SELECT * FROM BOOKS WHERE ? <= KEY AND KEY <= ?",
  0, 1000, 10,
  row => row.getString("BOOK_TITLE")
)

パラメータのドキュメントをご覧ください。簡単に:

  • SparkContextがあります。
  • 次に、接続を作成する関数。これは、各ワーカーでデータベースに接続するために呼び出されます。
  • 次に、SQLクエリ。これは例に類似している必要があり、開始キーと終了キーのプレースホルダーが含まれています。
  • 次に、キーの範囲(この例では0〜1000)とパーティションの数を指定します。範囲はパーティション間で分割されます。したがって、この例では、1つのエグゼキュータースレッドがSELECT * FROM FOO WHERE 0 <= KEY AND KEY <= 100を実行します。
  • 最後に、ResultSetを何かに変換する関数があります。この例では、それをStringに変換するため、最終的にRDD[String]になります。

Apache Sparkバージョン1.3.0であるため、DataFrame APIを介して別のメソッドを使用できます。JdbcRDDの代わりに org.Apache.spark.sql.DataFrame

val df = sqlContext.load("jdbc", Map(
  "url" -> "jdbc:mysql://mysql.example.com/?user=batman&password=alfred",
  "dbtable" -> "BOOKS"))

https://spark.Apache.org/docs/1.3.1/sql-programming-guide.html#jdbc-to-other-databases を参照してくださいオプションの完全なリスト(キー範囲とパーティションの数は、JdbcRDDと同様に設定できます)。

更新情報

JdbcRDDは更新をサポートしていません。ただし、foreachPartitionで単純に行うことができます。

rdd.foreachPartition { it =>
  val conn = sql.DriverManager.getConnection("jdbc:mysql://mysql.example.com/?user=batman&password=alfred")
  val del = conn.prepareStatement("DELETE FROM BOOKS WHERE BOOK_TITLE = ?")
  for (bookTitle <- it) {
    del.setString(1, bookTitle)
    del.executeUpdate
  }
}

(これにより、パーティションごとに1つの接続が作成されます。それが懸念される場合は、接続プールを使用してください!)

DataFramesは、createJDBCTableおよびinsertIntoJDBCメソッドによる更新をサポートします。

43
Daniel Darabos