以下で説明するようにコードで同じことをしようとしているとき
dataframe.map(row => {
val row1 = row.getAs[String](1)
val make = if (row1.toLowerCase == "tesla") "S" else row1
Row(row(0),make,row(2))
})
私はここから上記の参照を取りました: Scala:どのようにscalaを使用してDataframsの値を置き換えることができます しかし、
データセットに保存されているタイプのエンコーダが見つかりません。プリミティブ型(Int、Stringなど)および製品型(ケースクラス)は、spark.im plicitsをインポートすることでサポートされています。他の型のシリアル化のサポートは、将来のリリースで追加される予定です。
注:spark 2.0!
ここでは予期しないことは何もありません。 Spark 1.xで記述され、Spark 2.0でサポートされなくなったコードを使用しようとしています。
DataFrame.map
は((Row) ⇒ T)(ClassTag[T]) ⇒ RDD[T]
Dataset[Row].map
は((Row) ⇒ T)(Encoder[T]) ⇒ Dataset[T]
正直なところ、1.xでもあまり意味がありませんでした。バージョンに関係なく、単にDataFrame
APIを使用できます。
import org.Apache.spark.sql.functions.{when, lower}
val df = Seq(
(2012, "Tesla", "S"), (1997, "Ford", "E350"),
(2015, "Chevy", "Volt")
).toDF("year", "make", "model")
df.withColumn("make", when(lower($"make") === "tesla", "S").otherwise($"make"))
本当にmap
を使用する場合は、静的に型指定されたDataset
を使用する必要があります。
import spark.implicits._
case class Record(year: Int, make: String, model: String)
df.as[Record].map {
case tesla if tesla.make.toLowerCase == "tesla" => tesla.copy(make = "S")
case rec => rec
}
または、暗黙のエンコーダーを持つオブジェクトを少なくとも返します。
df.map {
case Row(year: Int, make: String, model: String) =>
(year, if(make.toLowerCase == "tesla") "S" else make, model)
}
最後に、何らかの理由で完全にクレイジー理由で、本当にDataset[Row]
必要なエンコーダーを提供する必要があります。
import org.Apache.spark.sql.catalyst.encoders.RowEncoder
import org.Apache.spark.sql.types._
import org.Apache.spark.sql.Row
// Yup, it would be possible to reuse df.schema here
val schema = StructType(Seq(
StructField("year", IntegerType),
StructField("make", StringType),
StructField("model", StringType)
))
val encoder = RowEncoder(schema)
df.map {
case Row(year, make: String, model) if make.toLowerCase == "tesla" =>
Row(year, "S", model)
case row => row
} (encoder)
データフレームスキーマが事前にわかっているシナリオでは、@ zero323で指定された答えがソリューションです
しかし、動的スキーマを使用したシナリオ/または複数のデータフレームを汎用関数に渡す場合:1.6.1から2.2.0への移行中に、次のコードが機能しました
import org.Apache.spark.sql.Row
val df = Seq(
(2012, "Tesla", "S"), (1997, "Ford", "E350"),
(2015, "Chevy", "Volt")
).toDF("year", "make", "model")
val data = df.rdd.map(row => {
val row1 = row.getAs[String](1)
val make = if (row1.toLowerCase == "tesla") "S" else row1
Row(row(0),make,row(2))
})
このコードは両方のバージョンのsparkで実行されます。
欠点:sparkによって提供される最適化は、dataframe/datasets APIに適用されません。