2017-10-01 5 views
1

私は次のことを行いUDFを作成したいと思います:他の列への参照として値を持つUDFを書き込む方法はありますか?

DataFrameは5列があり、その値は、第1および第2の列名が含まれている合計で6番目の列を作成したいと。

私はDataFrameを印刷し、それを説明しましょう:

case class salary(c1: String, c2: String, c3: Int, c4: Int, c5: Int) 

val df = Seq(
    salary("c3", "c4", 7, 5, 6), 
    salary("c5", "c4", 8, 10, 20), 
    salary("c5", "c3", 1, 4, 9)) 
    .toDF() 

DataFrame結果

+---+---+---+---+---+ 
| c1| c2| c3| c4| c5| 
+---+---+---+---+---+ 
| c3| c4| 7| 5| 6| 
| c5| c4| 8| 10| 20| 
| c5| c3| 1| 4| 9| 
+---+---+---+---+---+ 

df.withColumn("c6",UDFName(c1,c2)) 

そして、この列の結果は次のようになります。

1º行(C3、C4)次に7 + 5 = 12

2度行(C5、C4)次に2 0 + 10 = 30

3º行(C5、C3)、そして9 + 1 = 10

+0

あなたが聞いた質問に対する回答を[受け入れる](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work)と考えてください。 – Shaido

答えて

1

ユーザ定義機能(UDF)は、入力パラメータとして直接渡された値へのアクセスを有します。

他の列にアクセスしたい場合、UDFはの場合にのみに入力パラメータとして渡します。それで、あなたはあなたが何をしているのかを簡単に達成するはずです。

struct機能を使用して、他のすべての列を組み合わせることを強くお勧めします。

struct(cols:Column *):Column新しい構造体列を作成します。

Dataset.columnsメソッドを使用して、structの列にアクセスすることもできます。

columns:Array [String]すべての列名を配列として返します。

2

ここでは、実際にはUDFは必要ありません。それははるかに速く、クリーナー、およびUDFsRowsを扱うよりも安全である

df.withColumn("c6", values($"c1") + values($"c2")) 
+---+---+---+---+---+---+ 
| c1| c2| c3| c4| c5| c6| 
+---+---+---+---+---+---+ 
| c3| c4| 7| 5| 6| 12| 
| c5| c4| 8| 10| 20| 30| 
| c5| c3| 1| 4| 9| 10| 
+---+---+---+---+---+---+ 

import org.apache.spark.sql.functions.{col, lit, map} 

// We use an interleaved list of column name and column value 
val values = map(Seq("c3", "c4", "c5").flatMap(c => Seq(lit(c), col(c))): _*) 

// Check the first row 
df.select(values).limit(1).show(false) 
+------------------------------+ 
|map(c3, c3, c4, c4, c5, c5) | 
+------------------------------+ 
|Map(c3 -> 7, c4 -> 5, c5 -> 6)| 
+------------------------------+ 

と表現でそれを使用する:ちょうど仮想MapType列を使用

import org.apache.spark.sql.functions.{struct, udf} 
import org.apache.spark.sql.Row 

val f = udf((row: Row) => for { 
    // Use Options to avoid problems with null columns 
    // Explicit null checks should be faster, but much more verbose 
    c1 <- Option(row.getAs[String]("c1")) 
    c2 <- Option(row.getAs[String]("c2")) 

    // In this case we could (probably) skip Options below 
    // but Ints in Spark SQL can get null 
    x <- Option(row.getAs[Int](c1)) 
    y <- Option(row.getAs[Int](c2)) 
} yield x + y) 

df.withColumn("c6", f(struct(df.columns map col: _*))) 
+---+---+---+---+---+---+ 
| c1| c2| c3| c4| c5| c6| 
+---+---+---+---+---+---+ 
| c3| c4| 7| 5| 6| 12| 
| c5| c4| 8| 10| 20| 30| 
| c5| c3| 1| 4| 9| 10| 
+---+---+---+---+---+---+ 
関連する問題