web-dev-qa-db-ja.com

SparkデータフレームUPSERTからPostgresテーブルへ

Apache Spark DataFramesを使用して2つのデータソースを結合し、結果を別のDataFrameとして取得しています。結果を別のPostgresテーブルに書き込みたいのですが、このオプションが表示されます。

myDataFrame.write.jdbc(url, table, connectionProperties)

しかし、私がやりたいのは、テーブルの主キーに基づいてデータフレームをテーブルにUPSERTすることです。これはどのように行われますか?私はSpark 1.6.0。

15
void

サポートされていません。 DataFrameWriterは、既存のテーブルに追加または上書きできます。アプリケーションでより複雑なロジックが必要な場合は、これを手動で処理する必要があります。

1つのオプションは、標準のJDBC接続でアクション(foreachforeachPartition)を使用することです。もう1つは、一時ファイルに書き込み、残りをデータベースで直接処理することです。

SPARK-19335Sparkは、JDBCを介した効率的なDataFrameアップサートの実行をサポートする必要があります)と関連する提案も参照してください。

18
zero323

KrisP にはその権利があります。アップサートを行う最善の方法は、準備されたステートメントを使用することではありません。この方法では、ワーカーの数と同じ数のパーティションで一度に1つずつ挿入されることに注意してください。これをバッチで実行したい場合もできます

import Java.sql._
dataframe.coalesce("NUMBER OF WORKERS").mapPartitions((d) => Iterator(d)).foreach { batch =>
  val dbc: Connection = DriverManager.getConnection("JDBCURL")
  val st: PreparedStatement = dbc.prepareStatement("YOUR PREPARED STATEMENT")

  batch.grouped("# Of Rows you want per batch").foreach { session =>
    session.foreach { x =>
      st.setDouble(1, x.getDouble(1)) 
      st.addBatch()
    }
    st.executeBatch()
  }
  dbc.close()
}

これにより、ワーカーごとにバッチが実行され、DB接続が閉じます。ワーカーの数、バッチの数を制御でき、それらの範囲内で作業できます。

13
jstuartmill

手動で、zero323で言及されているオプション1を使用してこれを行う場合は、Spark ここに挿入ステートメントのソースコード を見てください。

_  def insertStatement(conn: Connection, table: String, rddSchema: StructType): PreparedStatement = {
    val columns = rddSchema.fields.map(_.name).mkString(",")
    val placeholders = rddSchema.fields.map(_ => "?").mkString(",")
    val sql = s"INSERT INTO $table ($columns) VALUES ($placeholders)"
    conn.prepareStatement(sql)
  }
_

PreparedStatement_Java.sql_ の一部であり、execute()executeUpdate()などのメソッドがあります。もちろん、それに応じてsqlを変更する必要があります。

8
KrisP

あなたが使用できるJDBCを挿入するには

dataframe.write.mode(SaveMode.Append).jdbc(jdbc_url,table_name,connection_properties)

また、Dataframe.writeはDataFrameWriterを提供し、データフレームを挿入するメソッドがいくつかあります。

def insertInto(tableName: String): Unit

DataFrameのコンテンツを指定されたテーブルに挿入します。 DataFrameのスキーマがテーブルのスキーマと同じである必要があります。

既存のテーブルにデータを挿入するため、フォーマットやオプションは無視されます。

http://spark.Apache.org/docs/latest/api/scala/index.html#org.Apache.spark.sql.DataFrameWriter

sparkただし

2
Soumitra