ユーザー定義のスカラー関数 - Scala
この記事には、Scala ユーザー定義関数 (UDF) の例が含まれています。 UDF を登録する方法、UDF を呼び出す方法、および Spark SQL での部分式の評価順序に関する注意事項を示します。 詳細については、 外部ユーザー定義スカラー関数 (UDF) を参照してください。
Unity Catalog 対応コンピュート リソース上の UDF を標準アクセス モード (以前の共有アクセス モード) でScalaするには、Databricks Runtime 14.2 以降が必要です。
関数を UDF として登録する
val squared = (s: Long) => {
s * s
}
spark.udf.register("square", squared)
Spark SQL で UDF を呼び出す
spark.range(1, 20).createOrReplaceTempView("test")
%sql select id, square(id) as id_squared from test
UDF と データフレーム の併用
import org.apache.spark.sql.functions.{col, udf}
val squared = udf((s: Long) => s * s)
display(spark.range(1, 20).select(squared(col("id")) as "id_squared"))
評価順序と null チェック
Spark SQL ( SQL 、 データフレーム 、データセット APIsを含む)は、部分式の評価順序を保証するものではありません。 特に、演算子または関数の入力は、必ずしも左から右に評価されたり、その他の固定された順序で評価されるわけではありません。 たとえば、論理 AND
式と OR
式には、左から右への "短絡" セマンティクスはありません。
したがって、 Boolean 式の副作用や評価の順序、およびWHERE
句とHAVING
句の順序に依存することは危険です。なぜなら、そのような式や句はクエリの最適化と計画中に並べ替えられる可能性があるためです。 具体的には、UDF が null チェックのために SQL のショートサーキット セマンティクスに依存している場合、UDF を呼び出す前に null チェックが行われる保証はありません。 例えば
spark.udf.register("strlen", (s: String) => s.length)
spark.sql("select s from test1 where s is not null and strlen(s) > 1") // no guarantee
この WHERE
句は、null をフィルターで除外した後に strlen
UDF が呼び出されることを保証するものではありません。
適切な null チェックを実行するには、次のいずれかを実行することをお勧めします。
- UDF 自体を null 対応にし、UDF 自体の内部で null チェックを行います
IF
式またはCASE WHEN
式を使用してヌルチェックを行い、条件分岐でUDFを呼び出します
spark.udf.register("strlen_nullsafe", (s: String) => if (s != null) s.length else -1)
spark.sql("select s from test1 where s is not null and strlen_nullsafe(s) > 1") // ok
spark.sql("select s from test1 where if(s is not null, strlen(s), null) > 1") // ok
Typed データセット APIs
この機能は、 Databricks Runtime 15.4 以降の標準アクセス モードを使用した Unity Catalog 対応クラスターでサポートされています。
型付きデータセット APIs を使用すると、ユーザー定義関数を使用して、結果のデータセットに対してマップ、フィルター、集約などの変換を実行できます。
たとえば、次の Scala アプリケーションは map()
API を使用して、result 列の数値をプレフィックス付きの文字列に変更します。
spark.range(3).map(f => s"row-$f").show()
この例では map()
APIを使用していますが、これは filter()
、mapPartitions()
、foreach()
、foreachPartition()
、reduce()
、flatMap()
などの他の型付きデータセット APIsにも適用されます。