Spark 2.x管理与开发-Spark SQL-【Spark SQL案例】(三)UDF和UDAF*

UDF-UserDefineFunction:每条数据都会过一下UDF。

UDAF-UserDefineAggregateFunction :UDAF是在分组里面使用的,只有加了group by之后才能使用它。

                                                                      每组数据使用UDAF。

Scala代码:

package sqlExamples

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext
import org.apache.spark.sql.Row
import org.apache.spark.sql.types.StructType
import org.apache.spark.sql.types.StructField
import org.apache.spark.sql.types.StringType
import org.apache.spark.sql.expressions.MutableAggregationBuffer;
import org.apache.spark.sql.expressions.UserDefinedAggregateFunction
import org.apache.spark.sql.types.IntegerType
import org.apache.spark.sql.types.DataType
import org.apache.calcite.linq4j.function.Deterministic

object UDFandUDAF {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local").setAppName("UDFandUDAF")
    val sc = new SparkContext(conf)
    val sqlContext = new SQLContext(sc) //在SparkSession之前都是用SQLContext的
    val bigData = Array("Spark", "Spark", "Hadoop", "spark", "Hadoop", "spark", "Hadoop", "Hadoop", "spark", "spark")
    //创建DataFrame
    //1.创建RDD
    val bigDataRDD = sc.parallelize(bigData)
    //2.映射
    val bigDataRDDRow = bigDataRDD.map(item => Row(item))
    //3.创建表结构
    val structType = StructType(Array(
      new StructField("word", StringType)))
    //4.创建DF
    val bigdataDF = sqlContext.createDataFrame(bigDataRDDRow, structType)
    //创建视图
    bigdataDF.createOrReplaceTempView("bigDataView")
//*****************************定义UDF*************************************
    //                      "函数的名字"   ,  函数的实现逻辑-word的长度
    //注意:UDF最多是22个参数,再多的话建议分表
    sqlContext.udf.register("computeLength", (input: String, input2: String) => input.length())
    //现在执行SQL语句
    sqlContext.sql("select * from bigDataView").show()
    sqlContext.sql("select word,computeLength(word,word) from bigDataView").show()
    //注意:如果UDF设的是两个参数,那么sql查询它的时候也得是两个参数
//*****************************定义UDAF*************************************
    sqlContext.udf.register("wordCount", new MyUDAF)
    sqlContext.sql("select word,wordCount(word) as count from bigDataView group by word").show()
    sc.stop()
  }
}
class MyUDAF extends UserDefinedAggregateFunction {

  /**
   * 该方法指定具体输入数据的类型--StringType
   * "input"是给输入数据取的别名
   * @return
   */
  override def inputSchema: StructType = StructType(Array(StructField("input", StringType, true)))
  /**
   * 再进行聚合操作的时候buffer可以临时存一些数据,这些所要处理的数据的类型--IntegerType
   * @return
   */
  override def bufferSchema: StructType = StructType(Array(StructField("count", IntegerType, true)))
  /**
   * 指定UDF函数计算后返回的数据(这里就是单词出现的次数)类型--IntegerType
   * 和buffer里数据的类型相同
   * @return
   */
  override def dataType: DataType = IntegerType
  /**
   * 确保一致性,一般都用true
   * @return
   */
  override def deterministic: Boolean = true
  /**
   * 在Aggregate-合计 之前每组数据的初始化结果--buffer(0)=0就是让buffer(0)从0开始计数
   * @param buffer
   */
  override def initialize(buffer: MutableAggregationBuffer): Unit = { buffer(0) = 0 }
  /**
   * 在进行聚合的时候,每当有新的值进来,对分组后的聚合如何计算
   * 本地的聚合操作,相当于Hadoop MapReduce模型中的Combiner
   * 每组的Key都是相同的
   * @param buffer
   * @param input-->Row(一行的)
   */
  override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
    buffer(0) = buffer.getAs[Int](0) + 1 //将原来的值加一并覆盖掉
  }
  /**
   * 最后在分布式节点进行Local Reduce完成后需要进行全局级别的Merge操作
   * @param buffer1
   * @param buffer2
   */
  override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
    buffer1(0) = buffer1.getAs[Int](0) + buffer2.getAs[Int](0)
  }
  /**
   * 返回UDAF最终的结果
   * @param buffer
   * @return
   */
  override def evaluate(buffer: Row): Any = buffer.getAs[Int](0)
}

 

结果:

 

 

 

 

 

 

 

博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3