您好,登錄后才能下訂單哦!
這篇文章主要介紹“Spark UDF變長參數(shù)的方法是什么”,在日常操作中,相信很多人在Spark UDF變長參數(shù)的方法是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Spark UDF變長參數(shù)的方法是什么”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
引子
變長參數(shù)對于我們來說并不陌生,在Java里我們這么寫
public void varArgs(String... args)
在Scala里我們這么寫
def varArgs(cols: String*): String
而在Spark里,很多時候我們有自己的業(yè)務(wù)邏輯,現(xiàn)成的functions滿足不了我們的需求,而當(dāng)我們需要處理同一行的多個列,將其經(jīng)過我們自己的邏輯合并為一個列時,變長參數(shù)及其變種實現(xiàn)可以給我們提供幫助。
但是在Spark UDF里我們是 無法使用變長參數(shù)傳值 的,但之所以本文以變長參數(shù)開頭,是因為需求起于它,而通過對它進行變換,我們可以使用變長參數(shù)或Seq類型來接收參數(shù)。
下面通過Spark-Shell來做演示,以下三種方法都可以做到多列傳參,分別是
變長參數(shù)(接受array類型)
Seq類型參數(shù)(接受array類型)
Row類型參數(shù)(接受struct類型)
變長參數(shù)類型的UDF
定義UDF方法
def myConcatVarargs(sep: String, cols: String*): String = cols.filter(_ != null).mkString(sep)
注冊UDF函數(shù)
由于變長參數(shù)只能通過方法定義,所以這里使用部分應(yīng)用函數(shù)來轉(zhuǎn)換
val myConcatVarargsUDF = udf(myConcatVarargs _)
可以看到該UDF的定義如下
UserDefinedFunction(<function2>,StringType,List(StringType, ArrayType(StringType,true)))
也即變長參數(shù)轉(zhuǎn)換為了ArrayType,而且函數(shù)是只包括兩個參數(shù),所以變長參數(shù)列表由此也可看出無法使用的。
變長參數(shù)列表傳值
我們構(gòu)造一個DataFrame如下
val df = sc.parallelize(Array(("aa", "bb", "cc"),("dd","ee","ff"))).toDF("A", "B", "C")
然后直接傳入多個String類型的列到myConcatVarargsUDF
df.select(myConcatVarargsUDF(lit("-"), col("A"), col("B"), col("C"))).show
結(jié)果出現(xiàn)如下報錯
java.lang.ClassCastException: anonfun$1 cannot be cast to scala.Function4
由此可以看出,使用變長參數(shù)列表的方式Spark是不支持的,它會被識別為四個參數(shù)的函數(shù),而UDF確是被定義為兩個參數(shù)而不是四個參數(shù)的函數(shù)!
變換:使用array()轉(zhuǎn)換做第二個參數(shù)
我們使用Spark提供的array() function來轉(zhuǎn)換參數(shù)為Array類型
df.select(myConcatVarargsUDF(lit("-"), array(col("A"), col("B"), col("C")))).show
結(jié)果如下
+-------------------+ |UDF(-,array(A,B,C))| +-------------------+ | aa-bb-cc| | dd-ee-ff| +-------------------+
由此可以看出,使用變長參數(shù)構(gòu)造的UDF方法,可以通過構(gòu)造Array的方式傳參,來達到多列合并的目的。
使用Seq類型參數(shù)的UDF
上面提到,變長參數(shù)***被轉(zhuǎn)為ArrayType,那不禁要想我們?yōu)槁锊皇褂肁rray或List類型呢?
實際上在UDF里,類型并不是我們可以隨意定義的,比如使用List和Array就是不行的,我們自己定義的類型也是不行的,因為這涉及到數(shù)據(jù)的序列化和反序列化。
以Array/List為示例的錯誤
下面以Array類型為示例
定義函數(shù)
val myConcatArray = (cols: Array[String], sep: String) => cols.filter(_ != null).mkString(sep)
注冊UDF
val myConcatArrayUDF = udf(myConcatArray)
可以看到給出的UDF簽名是
UserDefinedFunction(<function2>,StringType,List())
應(yīng)用UDF
df.select(myConcatArrayUDF(array(col("A"), col("B"), col("C")), lit("-"))).show
會發(fā)現(xiàn)報錯
scala.collection.mutable.WrappedArray$ofRef cannot be cast to [Ljava.lang.String
同樣List作為參數(shù)類型也會報錯,因為反序列化的時候無法構(gòu)建對象,所以List和Array是無法直接作為UDF的參數(shù)類型的
以Seq做參數(shù)類型
定義調(diào)用如下
val myConcatSeq = (cols: Seq[Any], sep: String) => cols.filter(_ != null).mkString(sep) val myConcatSeqUDF = udf(myConcatSeq) df.select(myConcatSeqUDF(array(col("A"), col("B"), col("C")), lit("-"))).show
結(jié)果如下
+-------------------+ |UDF(array(A,B,C),-)| +-------------------+ | aa-bb-cc| | dd-ee-ff| +-------------------+
使用Row類型參數(shù)的UDF
我們可以使用Spark functions里struct方法構(gòu)造結(jié)構(gòu)體類型傳參,然后用Row類型接UDF的參數(shù),以達到多列傳值的目的。
def myConcatRow: ((Row, String) => String) = (row, sep) => row.toSeq.filter(_ != null).mkString(sep) val myConcatRowUDF = udf(myConcatRow) df.select(myConcatRowUDF(struct(col("A"), col("B"), col("C")), lit("-"))).show
可以看到UDF的簽名如下
UserDefinedFunction(<function2>,StringType,List())
結(jié)果如下
+--------------------+ |UDF(struct(A,B,C),-)| +--------------------+ | aa-bb-cc| | dd-ee-ff| +--------------------+
使用Row類型還可以使用模式提取,用起來會更方便
row match { case Row(aa:String, bb:Int) => }
***
對于上面三種方法,變長參數(shù)和Seq類型參數(shù)都需要array的函數(shù)包裝為ArrayType,而使用Row類型的話,則需要struct函數(shù)構(gòu)建結(jié)構(gòu)體類型,其實都是為了數(shù)據(jù)的序列化和反序列化。三種方法中,Row的方式更靈活可靠,而且支持不同類型并且可以明確使用模式提取,用起來相當(dāng)方便。
而由此我們也可以看出,UDF不支持List和Array類型的參數(shù),同時 自定義參數(shù)類型 如果沒有混合Spark的特質(zhì)實現(xiàn)序列化和反序列化,那么在UDF里也是 無法用作參數(shù)類型 的。當(dāng)然,Seq類型是可以 的,可以接多列的數(shù)組傳值。
此外,我們也可以使用柯里化來達到多列傳參的目的,只是不同參數(shù)個數(shù)需要定義不同的UDF了。
到此,關(guān)于“Spark UDF變長參數(shù)的方法是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。