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

闲下来再回顾下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))。

4edfd38608897ca39ecff1035c0957184ff.jpg

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;

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值