DataFrame
の日付列を解析します。日付列ごとに、日付の解像度が変更される場合があります(つまり、解像度が「月」に設定されている場合、2011/01/10 => 2011/01 )。
次のコードを書きました。
def convertDataFrame(dataframe: DataFrame, schema : Array[FieldDataType], resolution: Array[DateResolutionType]) : DataFrame =
{
import org.Apache.spark.sql.functions._
val convertDateFunc = udf{(x:String, resolution: DateResolutionType) => SparkDateTimeConverter.convertDate(x, resolution)}
val convertDateTimeFunc = udf{(x:String, resolution: DateResolutionType) => SparkDateTimeConverter.convertDateTime(x, resolution)}
val allColNames = dataframe.columns
val allCols = allColNames.map(name => dataframe.col(name))
val mappedCols =
{
for(i <- allCols.indices) yield
{
schema(i) match
{
case FieldDataType.Date => convertDateFunc(allCols(i), resolution(i)))
case FieldDataType.DateTime => convertDateTimeFunc(allCols(i), resolution(i))
case _ => allCols(i)
}
}
}
dataframe.select(mappedCols:_*)
}}
ただし、機能しません。 Column
sのみをUDFに渡すことができるようです。 DataFrame
をRDD
に変換して各行に関数を適用すると、非常に遅くなるのではないかと思います。
誰もが正しい解決策を知っていますか?ありがとうございました!
カレーを少しだけ使ってください:
def convertDateFunc(resolution: DateResolutionType) = udf((x:String) =>
SparkDateTimeConverter.convertDate(x, resolution))
次のように使用します。
case FieldDataType.Date => convertDateFunc(resolution(i))(allCols(i))
補足説明として、sql.functions.trunc
およびsql.functions.date_format
。これらは、UDFをまったく使用せずに、少なくともジョブの一部である必要があります。
注:
Spark 2.2以降では、typedLit
関数を使用できます。
import org.Apache.spark.sql.functions.typedLit
Seq
やMap
などのより広い範囲のリテラルをサポートします。
_org.Apache.spark.sql.functions
_で定義されているlit(...)
関数を使用して、リテラルColumn
を作成してudfに渡すことができます。
例えば:
_val takeRight = udf((s: String, i: Int) => s.takeRight(i))
df.select(takeRight($"stringCol", lit(1)))
_