1

I FallklasseSpark-SQL UDF scala unveränderliche Karte mit df.WithColumn Rückkehr()

case class MyCaseClass(City : String, Extras : Map[String, String]) 

und benutzerdefinierte Funktion haben, die scala.collection.immutable.Map gibt

def extrasUdf = spark.udf.register(
    "extras_udf", 
    (age : Int, name : String) => Map("age" -> age.toString, "name" -> name) 
) 

aber das bricht mit Ausnahme:

import spark.implicits._ 

spark.read.options(...).load(...) 
     .select('City, 'Age, 'Name) 
     .withColumn("Extras", extrasUdf('Age, 'Name)) 
     .drop('Age) 
     .drop('Name) 
     .as[MyCaseClass] 

ich Funke SQLs MapType (DataTypes.StringType, DataTypes.IntegerType) 01 verwenden solltenaber ich kann jedes Arbeitsbeispiel nicht gefunden ...

Und das funktioniert, wenn ich scala.collection.Map benutzen, aber ich unveränderlich Karte benötigen

Antwort

2

Es gibt viele Probleme mit Ihrem Code:

  • Sie verwenden def extrastUdf =, wodurch eine Funktion zum Registrieren einer UDF erstellt wird, anstatt eine UDF tatsächlich zu erstellen/registrieren. Verwenden Sie stattdessen val extrasUdf =.

  • Sie mischen Werttypen in Ihrer Karte (String und Int), die die Karte Map[String, Any] als Any sein macht, ist die gemeinsame übergeordnete Klasse von String und Int. Spark unterstützt Any nicht. Sie können mindestens zwei Dinge tun: (a) Wechseln Sie zur Verwendung einer Zeichenfolgemap (mit age.toString, in diesem Fall benötigen Sie keine UDF, wie Sie einfach map() verwenden können) oder (b) wechseln zu verwenden benannte Strukturen mit named_struct() (wieder, ohne die Notwendigkeit einer UDF). Schreiben Sie in der Regel nur dann eine UDF, wenn Sie nicht mit den vorhandenen Funktionen arbeiten können. Ich schaue mir lieber die Hive-Dokumentation an, da die Spark-Dokumente eher spärlich sind.

  • auch im Auge behalten, dass Typ-Spezifikation in Spark-Schema (zum Beispiel MapType) ist völlig verschieden von Scala-Typen (zum Beispiel Map[_, _]) und getrennt von, wie Typen werden intern dargestellt und zwischen Scala & Spark-Datenstrukturen abgebildet. Mit anderen Worten, dies hat nichts mit veränderlichen vs. unveränderbaren Sammlungen zu tun.

Hoffe, das hilft!

+0

Ist es möglich, ohne/mit UDF, WithColumn() -Ausdruck zu setzen, um 'Age,' Name in map nur zu setzen, wenn sie nicht null sind, weil ich keine Nullwerte in map haben möchte? – fpopic

+1

Sie könnten 'if()' oder einen 'case wenn ... then' Ausdruck verwenden. – Sim