最全hive学习笔记之十:用户自定义聚合函数(UDAF),社区工作面试经历分享

最后

看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面

小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>

image

针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺

image

全都是一丢一丢的收集整理纯手打出来的

更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~

image

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

public abstract class AbstractGenericUDAFResolver

implements GenericUDAFResolver2

{

@SuppressWarnings(“deprecation”)

@Override

public GenericUDAFEvaluator getEvaluator(GenericUDAFParameterInfo info)

throws SemanticException {

if (info.isAllColumns()) {

throw new SemanticException(

“The specified syntax for UDAF invocation is invalid.”);

}

return getEvaluator(info.getParameters());

}

@Override

public GenericUDAFEvaluator getEvaluator(TypeInfo[] info)

throws SemanticException {

throw new SemanticException(

“This UDAF does not support the deprecated getEvaluator() method.”);

}

}

  1. 既然源码都看了,也就没啥好纠结的了,继承父类还是实现接口都可以,您自己看着选吧,我这里选的是继承AbstractGenericUDAFResolver类;

关于UDAF的四个阶段

  • 在编码前,要先了解UDAF的四个阶段,定义在GenericUDAFEvaluator的Mode枚举中:
  1. COMPLETE:如果mapreduce只有map而没有reduce,就会进入这个阶段;

  2. PARTIAL1:正常mapreduce的map阶段;

  3. PARTIAL2:正常mapreduce的combiner阶段;

  4. FINAL:正常mapreduce的reduce阶段;

每个阶段被调用的方法

  • 开发UDAF时,要继承抽象类GenericUDAFEvaluator,里面有多个抽象方法,在不同的阶段,会调用到这些方法中的一个或多个;

  • 下图对每个阶段调用了哪些方法说得很清楚:

在这里插入图片描述

  • 下图对顺序执行的三个阶段和涉及方法做了详细说明:

在这里插入图片描述

  • 以上两张图片的出处都是kent7306的文章《Hive UDAF开发详解》,地址:https://blog.csdn.net/kent7306/article/details/50110067

  • 上面两幅图将抽象方法和每个阶段的关系都梳理得很清晰了,接下来咱们开始编码;

源码下载

  1. 如果您不想编码,可以在GitHub下载所有源码,地址和链接信息如下表所示:

| 名称 | 链接 | 备注 |

| :-- | :-- | :-- |

| 项目主页 | https://github.com/zq2599/blog_demos | 该项目在GitHub上的主页 |

| git仓库地址(https) | https://github.com/zq2599/blog_demos.git | 该项目源码的仓库地址,https协议 |

| git仓库地址(ssh) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh协议 |

  1. 这个git项目中有多个文件夹,本章的应用在hiveudf文件夹下,如下图红框所示:

在这里插入图片描述

UDAF开发步骤简述

开发UDAF分为以下几步:

  1. 新建类FieldLengthAggregationBuffer,用于保存中间结果,该类需继承AbstractAggregationBuffer;

  2. 新建类FieldLengthUDAFEvaluator,用于实现四个阶段中会被调用的方法,该类需继承GenericUDAFEvaluator;

  3. 新建类FieldLength,用于在hive中注册UDAF,里面会实例化FieldLengthUDAFEvaluator,该类需继承AbstractGenericUDAFResolver;

  4. 编译构建,得到jar;

  5. 在hive添加jar;

  6. 在hive注册函数;

接下来就按照上述步骤开始操作;

开发

  1. 打开前文新建的hiveudf工程,新建FieldLengthAggregationBuffer.java,这个类的作用是缓存中间计算结果,每次计算的结果都放入这里面,被传递给下个阶段,其成员变量value用来保存累加数据:

package com.bolingcavalry.hiveudf.udaf;

import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator;

import org.apache.hadoop.hive.ql.util.JavaDataModel;

public class FieldLengthAggregationBuffer extends GenericUDAFEvaluator.AbstractAggregationBuffer {

private Integer value = 0;

public Integer getValue() {

return value;

}

public void setValue(Integer value) {

this.value = value;

}

public void add(int addValue) {

synchronized (value) {

value += addValue;

}

}

/**

  • 合并值缓冲区大小,这里是用来保存字符串长度,因此设为4byte

  • @return

*/

@Override

public int estimate() {

return JavaDataModel.PRIMITIVES1;

}

}

  1. 新建FieldLengthUDAFEvaluator.java,里面是整个UDAF逻辑实现,关键代码已经添加了注释,请结合前面的图片来理解,核心思路是iterate将当前分组的字段处理完毕,merger把分散的数据合并起来,再由terminate决定当前分组计算结果:

package com.bolingcavalry.hiveudf.udaf;

import org.apache.hadoop.hive.ql.metadata.HiveException;

import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator;

import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;

import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;

import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;

/**

  • @Description: 这里是UDAF的实际处理类

  • @author: willzhao E-mail: zq2599@gmail.com

  • @date: 2020/11/4 9:57

*/

public class FieldLengthUDAFEvaluator extends GenericUDAFEvaluator {

PrimitiveObjectInspector inputOI;

ObjectInspector outputOI;

PrimitiveObjectInspector integerOI;

/**

  • 每个阶段都会被执行的方法,

  • 这里面主要是把每个阶段要用到的输入输出inspector好,其他方法被调用时就能直接使用了

  • @param m

  • @param parameters

  • @return

  • @throws HiveException

*/

@Override

public ObjectInspector init(Mode m, ObjectInspector[] parameters) throws HiveException {

super.init(m, parameters);

// COMPLETE或者PARTIAL1,输入的都是数据库的原始数据

if(Mode.PARTIAL1.equals(m) || Mode.COMPLETE.equals(m)) {

inputOI = (PrimitiveObjectInspector) parameters[0];

} else {

// PARTIAL2和FINAL阶段,都是基于前一个阶段init返回值作为parameters入参

integerOI = (PrimitiveObjectInspector) parameters[0];

}

outputOI = ObjectInspectorFactory.getReflectionObjectInspector(

Integer.class,

ObjectInspectorFactory.ObjectInspectorOptions.JAVA

);

// 给下一个阶段用的,即告诉下一个阶段,自己输出数据的类型

return outputOI;

}

public AggregationBuffer getNewAggregationBuffer() throws HiveException {

return new FieldLengthAggregationBuffer();

}

/**

  • 重置,将总数清理掉

  • @param agg

  • @throws HiveException

*/

public void reset(AggregationBuffer agg) throws HiveException {

((FieldLengthAggregationBuffer)agg).setValue(0);

}

/**

  • 不断被调用执行的方法,最终数据都保存在agg中

  • @param agg

  • @param parameters

  • @throws HiveException

*/

public void iterate(AggregationBuffer agg, Object[] parameters) throws HiveException {

if(null==parameters || parameters.length<1) {

return;

}

Object javaObj = inputOI.getPrimitiveJavaObject(parameters[0]);

((FieldLengthAggregationBuffer)agg).add(String.valueOf(javaObj).length());

}

/**

  • group by的时候返回当前分组的最终结果

  • @param agg

  • @return

  • @throws HiveException

*/

public Object terminate(AggregationBuffer agg) throws HiveException {

return ((FieldLengthAggregationBuffer)agg).getValue();

}

/**

最后

我还通过一些渠道整理了一些大厂真实面试主要有:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。

新鲜出炉的蚂蚁金服面经,熬夜整理出来的答案,已有千人收藏

还有专门针对JVM、SPringBoot、SpringCloud、数据库、Linux、缓存、消息中间件、源码等相关面试题。

新鲜出炉的蚂蚁金服面经,熬夜整理出来的答案,已有千人收藏

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。**

[外链图片转存中…(img-YvYcEw6L-1715555193695)]

还有专门针对JVM、SPringBoot、SpringCloud、数据库、Linux、缓存、消息中间件、源码等相关面试题。

[外链图片转存中…(img-oqdLBYWZ-1715555193696)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用SparkSQL和Hive API,可以通过以下步骤实现用户自定义函数(UDF)、聚合函数UDAF)和表生成函数(UDTF): 1. 编写自定义函数的代码,例如: ``` // UDF def myUDF(str: String): Int = { str.length } // UDAF class MyUDAF extends UserDefinedAggregateFunction { override def inputSchema: StructType = StructType(StructField("value", StringType) :: Nil) override def bufferSchema: StructType = StructType(StructField("count", IntegerType) :: Nil) override def dataType: DataType = IntegerType override def deterministic: Boolean = true override def initialize(buffer: MutableAggregationBuffer): Unit = { buffer(0) = 0 } override def update(buffer: MutableAggregationBuffer, input: Row): Unit = { buffer(0) = buffer.getInt(0) + input.getString(0).length } override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = { buffer1(0) = buffer1.getInt(0) + buffer2.getInt(0) } override def evaluate(buffer: Row): Any = { buffer.getInt(0) } } // UDTF class MyUDTF extends GenericUDTF { override def initialize(args: Array[ConstantObjectInspector]): StructObjectInspector = { // 初始化代码 } override def process(args: Array[DeferedObject]): Unit = { // 处理代码 } override def close(): Unit = { // 关闭代码 } } ``` 2. 将自定义函数注册到SparkSQL或Hive,例如: ``` // SparkSQL注册UDF spark.udf.register("myUDF", myUDF _) // Hive注册UDF hiveContext.sql("CREATE TEMPORARY FUNCTION myUDF AS 'com.example.MyUDF'") // Hive注册UDAF hiveContext.sql("CREATE TEMPORARY FUNCTION myUDAF AS 'com.example.MyUDAF'") // Hive注册UDTF hiveContext.sql("CREATE TEMPORARY FUNCTION myUDTF AS 'com.example.MyUDTF'") ``` 3. 在SQL语句使用自定义函数,例如: ``` -- 使用SparkSQL的UDF SELECT myUDF(name) FROM users -- 使用Hive的UDF SELECT myUDF(name) FROM users -- 使用HiveUDAF SELECT myUDAF(name) FROM users GROUP BY age -- 使用Hive的UDTF SELECT explode(myUDTF(name)) FROM users ``` 以上就是使用SparkSQL和Hive API实现用户自定义函数(UDF、UDAF、UDTF)的步骤。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值