SparkのDataFrameを使用する場合、列のデータをマッピングするにはユーザー定義関数(UDF)が必要です。 UDFでは、引数の型を明示的に指定する必要があります。私の場合、オブジェクトの配列で構成される列を操作する必要がありますが、使用する型がわかりません。以下に例を示します。
import sqlContext.implicits._
// Start with some data. Each row (here, there's only one row)
// is a topic and a bunch of subjects
val data = sqlContext.read.json(sc.parallelize(Seq(
"""
|{
| "topic" : "pets",
| "subjects" : [
| {"type" : "cat", "score" : 10},
| {"type" : "dog", "score" : 1}
| ]
|}
""")))
組み込みのorg.Apache.spark.sql.functions
を使用して、列のデータに対して基本的な操作を実行するのは比較的簡単です
import org.Apache.spark.sql.functions.size
data.select($"topic", size($"subjects")).show
+-----+--------------+
|topic|size(subjects)|
+-----+--------------+
| pets| 2|
+-----+--------------+
通常、任意の操作を実行するカスタムUDFを書くのは簡単です
import org.Apache.spark.sql.functions.udf
val enhance = udf { topic : String => topic.toUpperCase() }
data.select(enhance($"topic"), size($"subjects")).show
+----------+--------------+
|UDF(topic)|size(subjects)|
+----------+--------------+
| PETS| 2|
+----------+--------------+
しかし、UDFを使用して「件名」列のオブジェクトの配列を操作する場合はどうなりますか? UDFの引数にはどのタイプを使用しますか?たとえば、sparkが提供する関数を使用する代わりに、サイズ関数を再実装する場合:
val my_size = udf { subjects: Array[Something] => subjects.size }
data.select($"topic", my_size($"subjects")).show
明らかにArray[Something]
は機能しません...どのタイプを使用すればよいですか!? Array[]
を完全に捨てるべきですか?ぶらぶらと回るとscala.collection.mutable.WrappedArray
と関係があるかもしれませんが、まだ別のタイプが必要です。
探しているのは_Seq[o.a.s.sql.Row]
_です:
_import org.Apache.spark.sql.Row
val my_size = udf { subjects: Seq[Row] => subjects.size }
_
説明:
ArrayType
の現在の表現は、ご存じのとおり、WrappedArray
なので、Array
は機能しません。安全な側に留まる方が良いでしょう。StructType
のローカル(外部)タイプはRow
です。残念ながら、個々のフィールドへのアクセスはタイプセーフではありません。注:
Spark <2.3でstruct
を作成するには、udf
に渡される関数はProduct
type(_Tuple*
_または_case class
_を返す必要があります)、Row
ではありません。これは、対応するudf
バリアント Scala反射に依存 :
n引数のScalaクロージャーをユーザー定義関数(UDF)として定義します。データ型は、Scalaクロージャの署名に基づいて自動的に推測されます。
Spark> = 2.3では、Row
を直接返すことができます スキーマが提供されている限り 。
def udf(f: AnyRef, dataType: DataType): UserDefinedFunction
Scalaクロージャーを使用して決定論的なユーザー定義関数(UDF)を定義します。このバリアントでは、呼び出し元は出力データ型を指定する必要があり、自動入力型強制はありません。
たとえば、 Spark UDFをJavaに作成する方法/複合型を返すKotlinを参照してください を参照してください。