在spark中使用sql時一些功能須要自定義方法實現,這時候就能夠使用UDF功能來實現sql
UDF不支持參數*
的方式輸入多個參數,例如String*
,不過能夠使用array來解決這個問題。apache
定義udf方法,此處功能是將多個字段合併爲一個字段spa
def allInOne(seq: Seq[Any], sep: String): String = seq.mkString(sep)
在sql中使用code
sqlContext.udf.register("allInOne", allInOne _) //將col1,col2,col3三個字段合併,使用','分割 val sql = """ |select allInOne(array(col1,col2,col3),",") as col |from tableName """.stripMargin sqlContext.sql(sql).show()
在DataFrame中使用ip
import org.apache.spark.sql.functions.{udf,array,lit} val myFunc = udf(allInOne _) val cols = array("col1","col2","col3") val sep = lit(",") df.select(myFunc(cols,sep).alias("col")).show()
表結構以下,統計出每一個人的愛好個數get
name | hobbies |
---|---|
alice | jogging,Coding,cooking |
lina | travel,dance |
# 將某個字段中逗號分隔的數量統計出來 sqlContext.udf.register("hobby_num", (s: String) => s.split(',').size) sqlContext.sql("select *,hobby_num(hobbies) as hobby_num from table")
結果it
name | hobbies | hobby_num |
---|---|---|
alice | read book,coding,cooking | 3 |
lina | travel,dance | 2 |
表結構以下spark
A | B |
---|---|
null | 123456 |
234234 | 234234 |
# 填補第一個字段的空值 sqlContext.udf.register("combine", (s1: String,s2: String)=> {if(s1 == null) s2 else s1}) sqlContext.sql("select combine(A,B) as A from table")
結果io
A |
---|
123456 |
234234 |
類型轉化,將 String
轉化爲 Int
table
sqlContext.udf.register("str2Int", (s: String) => s.toInt)
或者直接使用cast
sqlContext.sql("select cast(a AS Int) from table")
原始數據,ID(用戶名),loginIP(賬號登陸的ip地址)
ID | loginIP |
---|---|
alice | ip1 |
lina | ip2 |
sven | ip3 |
alice | ip1 |
sven | ip2 |
alice | ip4 |
計算每一個用戶在哪些ip登陸過,並統計數量
ID | ip_list | loginIP_num |
---|---|---|
alice | ip1,ip4 | 2 |
lina | ip2 | 1 |
sven | ip2,ip3 | 2 |
//統計數量 sqlContext.udf.register("list_size", (s: String) => s.split(',').size) val sql = """select ID,ip_list,list_size(ip_list) as loginIP_num |from (select ID,concat_ws(',',collect_set(loginIP)) as ip_list from table) """.stripMargin sqlContext.sql(sql)
[Spark UDF with varargs](
http://stackoverflow.com/questions/33151866/spark-udf-with-varargs)