成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spark UDF變長參數的二三事兒

大數據 Spark
在復雜業務邏輯中,我們經常會用到Spark的UDF,當一個UDF需要傳入多列的內容并進行處理時,UDF的傳參該怎么做呢? 下面通過變長參數引出,逐一介紹三種可行方法以及一些不可行的嘗試...

[[196259]]

在復雜業務邏輯中,我們經常會用到Spark的UDF,當一個UDF需要傳入多列的內容并進行處理時,UDF的傳參該怎么做呢? 下面通過變長參數引出,逐一介紹三種可行方法以及一些不可行的嘗試...

引子

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

  1. public void varArgs(String... args) 

在Scala里我們這么寫

  1. def varArgs(cols: String*): String 

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

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

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

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

變長參數類型的UDF

定義UDF方法

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

注冊UDF函數

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

  1. val myConcatVarargsUDF = udf(myConcatVarargs _) 

可以看到該UDF的定義如下

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

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

變長參數列表傳值

我們構造一個DataFrame如下

  1. val df = sc.parallelize(Array(("aa""bb""cc"),("dd","ee","ff"))).toDF("A""B""C"

然后直接傳入多個String類型的列到myConcatVarargsUDF

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

結果出現如下報錯

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

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

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

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

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

結果如下

  1. +-------------------+ 
  2. |UDF(-,array(A,B,C))| 
  3. +-------------------+ 
  4. |           aa-bb-cc| 
  5. |           dd-ee-ff| 
  6. +-------------------+ 

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

使用Seq類型參數的UDF

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

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

以Array/List為示例的錯誤

下面以Array類型為示例

定義函數

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

注冊UDF

  1. val myConcatArrayUDF = udf(myConcatArray) 

可以看到給出的UDF簽名是

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

應用UDF

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

會發現報錯

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

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

以Seq做參數類型

定義調用如下

  1. val myConcatSeq = (cols: Seq[Any], sep: String) => cols.filter(_ != null).mkString(sep)  
  2. val myConcatSeqUDF = udf(myConcatSeq)  
  3. df.select(myConcatSeqUDF(array(col("A"), col("B"), col("C")), lit("-"))).show 

結果如下

  1. +-------------------+ 
  2. |UDF(array(A,B,C),-)| 
  3. +-------------------+ 
  4. |           aa-bb-cc| 
  5. |           dd-ee-ff| 
  6. +-------------------+ 

使用Row類型參數的UDF

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

  1. def myConcatRow: ((Row, String) => String) = (row, sep) => row.toSeq.filter(_ != null).mkString(sep)  
  2. val myConcatRowUDF = udf(myConcatRow)  
  3. df.select(myConcatRowUDF(struct(col("A"), col("B"), col("C")), lit("-"))).show 

可以看到UDF的簽名如下

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

結果如下

  1. +--------------------+ 
  2. |UDF(struct(A,B,C),-)| 
  3. +--------------------+ 
  4. |            aa-bb-cc| 
  5. |            dd-ee-ff| 
  6. +--------------------+ 

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

  1. row match { 
  2.   case Row(aa:String, bb:Int) => 

***

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

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

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

責任編輯:武曉燕 來源: oschina博客
相關推薦

2012-09-21 09:49:37

HadoopHDFS

2023-12-04 18:31:59

C語言函數

2022-07-03 23:07:48

Go語言參數

2022-07-04 14:41:31

Go 語言變長參數變長參數函數

2014-06-23 09:48:02

VLAN

2022-03-16 19:04:33

設計模式場景

2013-08-07 14:19:30

禁用

2022-01-08 21:33:39

反入侵安全風險攻擊

2020-01-03 07:57:39

UDPTCP網絡協議

2015-06-18 05:55:05

大數據大數據背后的事

2021-03-18 09:01:53

軟件開發軟件選型

2023-04-11 07:34:40

分布式系統算法

2015-12-08 14:49:13

SDN軟件定義網絡

2011-12-26 11:13:24

密碼

2021-03-31 07:39:18

pythonHIVEUDF函數

2012-08-15 16:03:25

Ubuntu 12.0服務器

2020-04-20 10:40:19

紅藍對抗網絡攻擊數據泄露

2021-11-03 06:25:58

確定性網絡網絡無線網絡

2010-10-15 10:31:00

2021-02-01 14:17:53

裝飾器外層函數里層函數
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧洲国产精品视频 | 伊人性伊人情综合网 | 欧美一级毛片在线播放 | 国产精品免费一区二区三区四区 | 免费在线观看成人 | 99综合| 国产丝袜人妖cd露出 | 日本黄视频在线观看 | 欧美精品中文字幕久久二区 | 免费黄色片视频 | 欧美在线一区二区三区 | 欧美日韩国产一区二区三区 | 日日干干 | 性色视频在线观看 | 操人网 | 欧美网站一区二区 | 在线一区 | 午夜在线影院 | 狠狠干天天干 | 91精品一区二区三区久久久久久 | 99热在线播放 | 中文字幕一区二区三区四区五区 | 精品国产乱码久久久久久闺蜜 | 久久99蜜桃综合影院免费观看 | 日韩高清中文字幕 | 成人做爰69片免费观看 | 在线精品国产 | 男女羞羞视频网站 | 国产在线中文字幕 | 久久久91精品国产一区二区三区 | 午夜二区 | 午夜一区二区三区在线观看 | 久久精品天堂 | 欧美大片一区二区 | 一级黄色片毛片 | 99精品电影 | 成年人免费网站 | 久久婷婷色 | 天天干狠狠 | 欧美一级大片免费看 | 亚洲伊人久久综合 |