Delen via


Door de gebruiker gedefinieerde scalaire functies - Scala

Dit artikel bevat voorbeelden van een door de gebruiker gedefinieerde functie (UDF) van Scala. Het laat zien hoe u UDF's registreert, UDF's aanroept en opmerkingen maakt met betrekking tot de evaluatievolgorde van subexpressies in Spark SQL. Zie Door de gebruiker gedefinieerde scalaire functies (UDF's) voor meer informatie.

Notitie

Scala UDF's op rekenresources met een Unity-catalogus met gedeelde toegangsmodus vereist Databricks Runtime 14.2 en hoger.

Een functie registreren als een UDF

val squared = (s: Long) => {
  s * s
}
spark.udf.register("square", squared)

De UDF aanroepen in Spark SQL

spark.range(1, 20).createOrReplaceTempView("test")
%sql select id, square(id) as id_squared from test

UDF gebruiken met DataFrames

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"))

Evaluatievolgorde en null-controle

Spark SQL (inclusief SQL en dataframe- en gegevensset-API's) garandeert niet de volgorde van evaluatie van subexpressies. Met name worden de invoer van een operator of functie niet noodzakelijkerwijs van links naar rechts of in een andere vaste volgorde geƫvalueerd. Logische en OR expressies hebben bijvoorbeeld AND geen semantiek van links-naar-rechts 'kortsluiting'.

Daarom is het gevaarlijk om te vertrouwen op de bijwerkingen of de volgorde van evaluatie van Boole-expressies, en de volgorde van WHERE en HAVING componenten, omdat dergelijke expressies en componenten tijdens queryoptimalisatie en -planning opnieuw kunnen worden gerangschikt. Als een UDF afhankelijk is van kortsluitingssemantiek in SQL voor null-controle, is er geen garantie dat de null-controle plaatsvindt voordat de UDF wordt aanroepen. Bijvoorbeeld:

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

Deze WHERE component garandeert niet dat de strlen UDF wordt aangeroepen nadat null-waarden zijn uitgefilterd.

Als u de juiste null-controle wilt uitvoeren, raden we u aan een van de volgende handelingen uit te voeren:

  • De UDF zelf null-aware maken en null-controle uitvoeren in de UDF zelf
  • Gebruik IF of CASE WHEN expressies om de null-controle uit te voeren en de UDF aan te roepen in een voorwaardelijke vertakking
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

Getypte gegevensset-API's

Notitie

Deze functie wordt ondersteund op clusters met een Unity-catalogus met gedeelde toegang in Databricks Runtime 15.4 en hoger.

Met getypte gegevensset-API's kunt u transformaties uitvoeren, zoals toewijzing, filter en aggregaties op resulterende gegevenssets met een door de gebruiker gedefinieerde functie.

De volgende Scala-toepassing gebruikt bijvoorbeeld de map() API om een getal in een resultaatkolom te wijzigen in een voorvoegseltekenreeks.

spark.range(3).map(f => s"row-$f").show()

Hoewel in dit voorbeeld de map() API wordt gebruikt, is dit ook van toepassing op andere getypte gegevensset-API's, zoals filter(), mapPartitions()foreach(), , foreachPartition(), en reduce()flatMap().