spark +hive 自定义聚合函数回顾--group_concat实现

开发十年,就只剩下这套Java开发体系了 >>>   hot3.png

闲下来再回顾下spark 和 hive 的聚合函数 使用:

spark自定义聚合函数类

class GroupConcatUDAF extends  UserDefinedAggregateFunction{
  /**
    * 指定输入字段的字段及类型
    * group by  之后会有1到多个数据被归到一组,所以用Array()封装
    */
  override def inputSchema: StructType = {
    StructType(Array(
      StructField("str",StringType,true)
    ))
  }
  //聚合过程中的中间结果集类型
  override def bufferSchema: StructType ={
    StructType(Array(
      StructField("strings",StringType,true)
    ))
  }
  //函数的返回类型
  override def dataType: DataType = {
    StringType
  }

  override def deterministic: Boolean = {
    true
  }
  //为每个分组的数据初始化
  override def initialize(buffer: MutableAggregationBuffer): Unit = {
    buffer(0)=""
  }
  //指的是,每个分组,有新的值进来时,如何进行分组的聚合计算
  //相当于map的combiner,buffer里面存放着累计的执行结果,input是当前的执行结果
  override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
    buffer(0)=buffer.getAs[String](0)+"|"+input.getAs[String](0)
  }
  //由于Spark是分布式的,所以一个分组的数据,可能会在不同的节点上进行局部聚合,就是update
  //但是最后一个分组,在各节点上的聚合值,要进行Merge,也就是合并
  //相当于reduce端的合并
  override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit =  {
    buffer1(0)=buffer1.getAs[String](0) + buffer2.getAs[String](0)
  }
  //一个分组的聚合值,如何通过中间的聚合值,最后返回一个最终的聚合值
  override def evaluate(buffer: Row): Any ={
    buffer.getAs[String](0)
  }
}

spark自定义聚合函数的调用:

object 测试spark的聚合函数 extends App{
  val spark=SparkSession.builder().appName("spark udaf").master("local[*]").getOrCreate()
  strCount()
  //1--测试strCount的使用+group_concat函数的使用
  def strCount(): Unit ={
    //导入隐式转化
    import spark.implicits._
    //构造用户的访问数据,并创建DataFrame
    val names=Array("张三","李四","王五","赵六","赵六","张三")
    val namesRDD: RDD[String] = spark.sparkContext.parallelize(names)
    //将RDD转换为DataFram
    val namesRowRDD=namesRDD.map(name=>Row(name))
    val structType=StructType(Array(
      StructField("name",StringType,true)
    ))
    val namesDF=spark.sqlContext.createDataFrame(namesRowRDD,structType)
    //注册表
    namesDF.createOrReplaceTempView("names")
    //定义和注册自定义函数
    spark.sqlContext.udf.register("group_concat",new GroupConcatUDAF)
    //使用自定义函数
   spark.sqlContext.sql("select name,concat_ws('|',collect_set(name)), concat_ws('|',collect_list(name)),group_concat(name) from names group by name").show()

  }
}

下图为调用自定义聚合函数group_concat的结果,其实直接使用concat_ws()函数也能实现group_concat功能,不过如果需要保持顺序对应关系,则使用concat_ws('|',collect_list(name))。若需要去重则使用concat_ws('|',collect_set(name))。

spark +hive 自定义聚合函数回顾--group_concat实现_第1张图片

hive的自定义聚合函数---group_concat

public class GroupConcat extends UDAF {
    public static class ConcatUDAFEvaluator implements UDAFEvaluator {
        //定义一个构造类,封装结果
        public static class PartialResult{
            String result;
            String delimiter;
        }

        private PartialResult partial;
        //init函数类似于构造函数,用于UDAF的初始化
        public void init() {
            partial = null;
        }
        // iterate接收传入的参数,并进行内部的轮转。其返回类型为boolean
        public boolean iterate(String value,String deli){
            if (value == null){
                return true;
            }
            if (partial == null){
                partial = new PartialResult();//构造类
                partial.result = new String("");//初始化值
                if(  deli == null || deli.equals("") )
                {
                    partial.delimiter = new String(",");//设置分隔符,没有设置默认使用 ','
                }
                else
                {
                    partial.delimiter = new String(deli);//设置分隔符
                }

            }
            if ( partial.result.length() > 0 )//处理传入的值
            {
                partial.result = partial.result.concat(partial.delimiter);//值 拼接 分隔符
            }

            partial.result = partial.result.concat(value);//拼接每次传入的值

            return true;
        }
        //terminatePartial无参数,其为iterate函数遍历结束后,返回轮转结果
        public PartialResult terminatePartial(){
            return partial;
        }
        //合并两个部分聚集值
        public boolean merge(PartialResult other){
            if (other == null){
                return true;
            }
            if (partial == null){
                partial = new PartialResult();
                partial.result = new String(other.result);
                partial.delimiter = new String(other.delimiter);
            }
            else
            {
                if ( partial.result.length() > 0 )
                {
                    partial.result = partial.result.concat(partial.delimiter);
                }
                partial.result = partial.result.concat(other.result);
            }
            return true;
        }
        //terminate返回最终的聚集函数结果 * * @return
        public String terminate(){
            return new String(partial.result);
        }
    }
}

使用方法:

1.将程序打成jar包,上传至服务器。

2.进入hive客户端

3.添加jar包。

hive>add jar /opt/hive-1.0-SNAPSHOT.jar
4.创建临时函数

hive>create temporary function group_concat as 'GroupConcat';

5.调用临时函数

hive>select group_concat (ykd018) as pdxCode from t_kc21k1 group by akc190;

 

你可能感兴趣的:(spark +hive 自定义聚合函数回顾--group_concat实现)