前言
本文介紹如何在Spark Sql和DataFrame中使用UDF,如何利用UDF給一個表或者一個DataFrame根據需求添加幾列,並給出了舊版(Spark1.x)和新版(Spark2.x)完整的代碼示例。sql
關於UDF:UDF:User Defined Function,用戶自定義函數apache
建立測試用DataFrame
spark2.0建立DataFrame函數
// 構造測試數據,有兩個字段、名字和年齡 val userData = Array(("A", 16), ("B", 21), ("B", 14), ("B", 18)) //建立測試df val userDF = spark.createDataFrame(userData).toDF("name", "age") userDF.show
+-----+---+
| name|age|
+-----+---+
| A | 16|
| B | 21|
| C | 14|
| D | 18|
+-----+---+
// 註冊一張user表
userDF.createOrReplaceTempView("user")
spark1.0建立DataFrame性能
// 構造測試數據,有兩個字段、名字和年齡 val userData = Array(("A", 16), ("B", 21), ("C", 14), ("D", 18)) //建立測試df val userDF = sc.parallelize(userData).toDF("name", "age") // 註冊一張user表 userDF.registerTempTable("user")
spark-sql中SQL中UDF用法
1. 經過匿名函數註冊UDF測試
下面的UDF的功能是計算某列的長度,該列的類型爲Stringspa
// Spark2.x: spark.udf.register("strLen", (str: String) => str.length()) // Spark1.x: sqlContext.udf.register("strLen", (str: String) => str.length()) // 僅以Spark2.x爲例 spark.sql("select name,strLen(name) as name_len from user").show
2. 經過實名函數註冊UDFcode
實名函數的註冊有點不一樣,要在後面加 _(注意前面有個空格) blog
// 定義一個實名函數 /** * 根據年齡大小返回是否成年 成年:true,未成年:false */ def isAdult(age: Int) = { if (age < 18) { false } else { true } } // 註冊(僅以Spark2.x爲例) spark.udf.register("isAdult", isAdult _)
spark-sql中DataFrame中UDF用法
DataFrame的udf方法雖然和Spark Sql的名字同樣,可是屬於不一樣的類,它在org.apache.spark.sql.functions裏,下面是它的用法源碼
1. 註冊it
import org.apache.spark.sql.functions._
//方法一:註冊自定義函數(經過匿名函數) val strLen = udf((str: String) => str.length()) //方法二:註冊自定義函數(經過實名函數) val udf_isAdult = udf(isAdult _)
2. 使用
可經過withColumn和select使用,下面的代碼已經實現了給user表添加兩列的功能
* 經過看源碼,下面的withColumn和select方法Spark2.0.0以後纔有的,關於spark1.xDataFrame怎麼使用註冊好的UDF沒有研究
// 經過withColumn添加列 userDF.withColumn("name_len", strLen(col("name"))).withColumn("isAdult", udf_isAdult(col("age"))).show //經過select添加列 userDF.select(col("*"), strLen(col("name")) as "name_len", udf_isAdult(col("age")) as "isAdult").show +-----+---+--------+-------+ | name|age|name_len|isAdult| +-----+---+--------+-------+ | A | 16| 3| false| | B | 21| 5| true| | C | 14| 4| false| | D | 18| 3| true| +-----+---+--------+-------+
withColumn和select的區別
可經過withColumn的源碼看出withColumn的功能是實現增長一列,或者替換一個已存在的列,他會先判斷DataFrame裏有沒有這個列名,若是有的話就會替換掉原來的列,沒有的話就用調用select方法增長一列,因此若是咱們的需求是增長一列的話,二者實現的功能同樣,且最終都是調用select方法,可是withColumn會提早作一些判斷處理,因此withColumn的性能不如select好。
注:select方法和sql 裏的select同樣,若是新增的列名在表裏已經存在,那麼結果裏容許出現兩列列名相同但數據不同,你們能夠本身試一下。
參考:https://dongkelun.com/2018/08/02/sparkUDF/