91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spark UDF變長參數的方法是什么

發布時間:2021-12-14 17:55:43 來源:億速云 閱讀:293 作者:iii 欄目:大數據

這篇文章主要介紹“Spark UDF變長參數的方法是什么”,在日常操作中,相信很多人在Spark UDF變長參數的方法是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Spark UDF變長參數的方法是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

引子

變長參數對于我們來說并不陌生,在Java里我們這么寫

public void varArgs(String... args)

在Scala里我們這么寫

def varArgs(cols: String*): String

而在Spark里,很多時候我們有自己的業務邏輯,現成的functions滿足不了我們的需求,而當我們需要處理同一行的多個列,將其經過我們自己的邏輯合并為一個列時,變長參數及其變種實現可以給我們提供幫助。

但是在Spark UDF里我們是 無法使用變長參數傳值  的,但之所以本文以變長參數開頭,是因為需求起于它,而通過對它進行變換,我們可以使用變長參數或Seq類型來接收參數。

下面通過Spark-Shell來做演示,以下三種方法都可以做到多列傳參,分別是

  • 變長參數(接受array類型)

  • Seq類型參數(接受array類型)

  • Row類型參數(接受struct類型)

變長參數類型的UDF

定義UDF方法

def myConcatVarargs(sep: String, cols: String*): String = cols.filter(_ != null).mkString(sep)

注冊UDF函數

由于變長參數只能通過方法定義,所以這里使用部分應用函數來轉換

val myConcatVarargsUDF = udf(myConcatVarargs _)

可以看到該UDF的定義如下

UserDefinedFunction(<function2>,StringType,List(StringType, ArrayType(StringType,true)))

也即變長參數轉換為了ArrayType,而且函數是只包括兩個參數,所以變長參數列表由此也可看出無法使用的。

變長參數列表傳值

我們構造一個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

結果出現如下報錯

java.lang.ClassCastException: anonfun$1 cannot be cast to scala.Function4

由此可以看出,使用變長參數列表的方式Spark是不支持的,它會被識別為四個參數的函數,而UDF確是被定義為兩個參數而不是四個參數的函數!

變換:使用array()轉換做第二個參數

我們使用Spark提供的array() function來轉換參數為Array類型

df.select(myConcatVarargsUDF(lit("-"), array(col("A"), col("B"), col("C")))).show

結果如下

+-------------------+ |UDF(-,array(A,B,C))| +-------------------+ |           aa-bb-cc| |           dd-ee-ff| +-------------------+

由此可以看出,使用變長參數構造的UDF方法,可以通過構造Array的方式傳參,來達到多列合并的目的。

使用Seq類型參數的UDF

上面提到,變長參數***被轉為ArrayType,那不禁要想我們為嘛不使用Array或List類型呢?

實際上在UDF里,類型并不是我們可以隨意定義的,比如使用List和Array就是不行的,我們自己定義的類型也是不行的,因為這涉及到數據的序列化和反序列化。

以Array/List為示例的錯誤

下面以Array類型為示例

定義函數

val myConcatArray = (cols: Array[String], sep: String) => cols.filter(_ != null).mkString(sep)

注冊UDF

val myConcatArrayUDF = udf(myConcatArray)

可以看到給出的UDF簽名是

UserDefinedFunction(<function2>,StringType,List())

應用UDF

df.select(myConcatArrayUDF(array(col("A"), col("B"), col("C")), lit("-"))).show

會發現報錯

scala.collection.mutable.WrappedArray$ofRef cannot be cast to [Ljava.lang.String

同樣List作為參數類型也會報錯,因為反序列化的時候無法構建對象,所以List和Array是無法直接作為UDF的參數類型的

以Seq做參數類型

定義調用如下

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

結果如下

+-------------------+ |UDF(array(A,B,C),-)| +-------------------+ |           aa-bb-cc| |           dd-ee-ff| +-------------------+

使用Row類型參數的UDF

我們可以使用Spark functions里struct方法構造結構體類型傳參,然后用Row類型接UDF的參數,以達到多列傳值的目的。

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

結果如下

+--------------------+ |UDF(struct(A,B,C),-)| +--------------------+ |            aa-bb-cc| |            dd-ee-ff| +--------------------+

使用Row類型還可以使用模式提取,用起來會更方便

row match {   case Row(aa:String, bb:Int) => }

***

對于上面三種方法,變長參數和Seq類型參數都需要array的函數包裝為ArrayType,而使用Row類型的話,則需要struct函數構建結構體類型,其實都是為了數據的序列化和反序列化。三種方法中,Row的方式更靈活可靠,而且支持不同類型并且可以明確使用模式提取,用起來相當方便。

而由此我們也可以看出,UDF不支持List和Array類型的參數,同時 自定義參數類型  如果沒有混合Spark的特質實現序列化和反序列化,那么在UDF里也是 無法用作參數類型 的。當然,Seq類型是可以 的,可以接多列的數組傳值。

此外,我們也可以使用柯里化來達到多列傳參的目的,只是不同參數個數需要定義不同的UDF了。

到此,關于“Spark UDF變長參數的方法是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

安阳市| 晴隆县| 湟源县| 泗水县| 株洲县| 花垣县| 阿拉善左旗| 民权县| 平乡县| 三台县| 阿图什市| 疏勒县| 济宁市| 四会市| 中超| 闻喜县| 金堂县| 图片| 静安区| 马公市| 河源市| 高州市| 龙州县| 东乡族自治县| 元阳县| 军事| 大兴区| 安泽县| 怀远县| 桦南县| 怀宁县| 玉田县| 咸阳市| 横峰县| 封丘县| 泊头市| 沅陵县| 青冈县| 白朗县| 通州市| 天峻县|