15 Hive 函数与自定义函数
来源:互联网 发布:软件开发代码 编辑:程序博客网 时间:2024/05/18 22:54
Hive函数介绍
HQL内嵌函数只有195个函数(包括操作符,使用命令show functions查看),基本能够胜任基本的hive开发,但是当有较为复杂的需求的时候,可能需要进行定制的HQL函数开发。HQL支持三种方式来进行功能的扩展(只支持使用java编写实现自定义函数),分别是:UDF(User-Defined Function)、UDAF(User-Defined Aggregate Function)和UDTF(User-Defined Table-Generating Function)。当我们使用java语言进行开发完成后,将生成的jar包移到linux机器(hive机器)上,进行函数的创建,然后进行使用即可。
hive (default)> show functions;show functions "x.*";
函数创建命令
HQL函数的创建一般分为以下几步:
1. 添加jar(0.13.*不支持hdfs上的jar添加,14版本才开始支持)
add jar linux_jar_path
2. 创建function,语法规则如下:
create [temporary] function [dbname.]function_name AS class_name;
class_name:是package+类名的全称。
3. 使用function,和使用其他函数一样。
函数删除命令
我们可以通过drop命令删除自定义函数,语法规则如下:
drop [temporary] function [if exists] [dbname.]function_name;
创建Function命令: CREATE FUNCTION [db_name.]function_name AS class_name [USING JAR|FILE|ARCHIVE ‘file_uri’ [, JAR|FILE|ARCHIVE ‘file_uri’] ]; file_uri可以为hdfs上文件路径
删除: drop function function_name;
显示: show functions [‘regex’]
一、自定义UDF介绍
UDF(User-Defined Function)支持一个输入产生一个输出,是一个最常用的自定义函数类型。实现自定义UDF要求继承类org.apache.hadoop.hive.ql.exec.UDF,并且在自定义UDF类中重载实现evaluate方法,我们可以通过重载多个evaluate方法达到函数参数多样化的需求。
实现案例:实现一个大小写转换的函数,要求函数通过参数的不同决定是进行那种转换,默认是转换为小写。
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>beifeng14</groupId> <artifactId>beifeng14</artifactId> <version>0.0.1</version> <dependencies> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-exec</artifactId> <version>0.13.1</version> </dependency> <dependency> <groupId>jdk.tools</groupId> <artifactId>jdk.tools</artifactId> <version>1.7</version> <scope>system</scope> <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath> </dependency> </dependencies> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build></project>
UDFLowerOrUpperCase
package com.beifeng.hive.ql;import org.apache.hadoop.hive.ql.exec.UDF;/** * 自定义UDF,要求继承UDF,并重载实现evaluate方法 * @author Administrator * */import org.apache.hadoop.io.Text;public class UDFLowerOrUpperCase extends UDF { /** * 转换成小写 * * @param t * @return */ public Text evaluate(Text t) { // 默认进行小写转换 return this.evaluate(t, "lower"); } /** * 对参数t进行大小写转换 * * @param t * @param lowerOrUpper * 如果该值为lower,则进行小写转换,如果该值为upper则进行大写转换,其它情况不进行转换。 * @return */ public Text evaluate(Text t, String lowerOrUpper) { if (t == null) { return t; } if ("lower".equals(lowerOrUpper)) { return new Text(t.toString().toLowerCase()); } else if ("upper".equals(lowerOrUpper)) { return new Text(t.toString().toUpperCase()); } // 转换参数错误的情况下,直接返回原本的值 return t; }}
导出:右击项目–runas–maven install
使用database:beifeng13
1. 实现一个大小写转换的自定义函数。
实现完成后
1. 添加jar:add jar /home/hadoop/bigdater/jobs/beifeng14-0.0.1.jar;
2. 创建function:
create temporary function temp_f as ‘com.beifeng.hive.ql.UDFLowerOrUpperCase’;
永久function:
create function lower_upper as ‘com.beifeng.hive.ql.UDFLowerOrUpperCase’;
3. 使用
select [dbname.]lower_upper(studentname) from beifeng13.students;
【function与数据库关联,在其它的数据库则使用dbname.function来使用】
二、UDAF介绍
UDAF(User-Defined Aggregate Function)支持多个输入,一个输出。在原来的版本中可以通过继承UDAF类来实现自定义UDAF,但是现在hive已经将这个类标注为弃用状态。现在一般通过继承AbstractGenericUDAFResolver类来实现自定义UDAF,通过这种方式要求实现自定义的GenericUDAFEvaluator类。也就是说在现在的hive版本中,实现自定义UDAF,那么需要实现两个类,分别是AbstractGenericUDAFResolver和GenericUDAFEvaluator。
AbstractGenericUDAFResolver介绍
AbstractGenericUDAFResolver类主要作用就是根据hql调用时候的函数参数来获取具体的GenericUDAFEvaluator实例对象,也就是说实现方法getEvaluator即可,该方法的主要作用就是根据参数的不同返回不同的evaluator实例对象,实现多态性。
GenericUDAFEvaluator介绍
GenericUDAFEvaluator类主要作用就是根据job的不同阶段执行不同的方法。hive通过GenericUDAFEvaluator.Model来确定job的执行阶段。
PARTIAL1:从原始数据到部分聚合,会调用方法iterate和terminatePartial方法;
PARTIAL2:从部分数据聚合和部分数据聚合,会调用方法merge和terminatePartial;
FINAL:从部分数据聚合到全部数据聚合,会调用方法merge和terminate;
COMPLETE:从原始数据到全部数据聚合,会调用方法iterate和terminate。
除了上面提到的iterate、merge、terminate和terminatePartial以外,还有init(初始化并返回返回值的类型)、getNewAggregationBuffer(获取新的buffer对象,也就是方法之间传递参数的对象),reset(重置buffer对象)。
自定义UDAF(多个输入,一个输出) 和group by一起操作
1. UDAF介绍
PARTIAL1:iterate&terminatePartial map的输入阶段
PARTIAL2: merge&terminatePartial map输出阶段
FINAL: merge&terminate reducer输入&reducer输出阶段
COMPLETE: iterate&terminate 没有reducer的map输出阶段
2. UDAF实例:实现自定义sum函数
create function self_sum as ‘com.beifeng.hive.ql.UDAFSumCase’;
UDAF案例:
实现一个自定义的sum函数。要求函数支持整形和浮点型的sum操作。
package com.beifeng.hive.ql;import org.apache.hadoop.hive.ql.exec.UDFArgumentException;import org.apache.hadoop.hive.ql.metadata.HiveException;import org.apache.hadoop.hive.ql.parse.SemanticException;import org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver;import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator;import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFParameterInfo;import org.apache.hadoop.hive.serde2.io.DoubleWritable;import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.primitive.AbstractPrimitiveWritableObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils;import org.apache.hadoop.io.LongWritable;/** * 自定义UDAF函数实现 * * @author gerry * */@SuppressWarnings("deprecation")public class UDAFSumCase extends AbstractGenericUDAFResolver { @Override public GenericUDAFEvaluator getEvaluator(GenericUDAFParameterInfo info) throws SemanticException { if (info.isAllColumns()) { // 函数允许使用“*”查询的时候会返回true。 throw new SemanticException("不支持使用*查询"); } // 获取函数参数列表 ObjectInspector[] inspectors = info.getParameterObjectInspectors(); if (inspectors.length != 1) { throw new UDFArgumentException("只支持一个参数进行查询"); } AbstractPrimitiveWritableObjectInspector apwoi = (AbstractPrimitiveWritableObjectInspector) inspectors[0]; switch (apwoi.getPrimitiveCategory()) { case BYTE: case INT: case SHORT: case LONG: // 都是进行整修的sum操作 return new SumLongEvaluator(); case FLOAT: case DOUBLE: // 进行浮点型的sum操作 return new SumDoubleEvaluator(); default: throw new UDFArgumentException("参数异常"); } } /** * 进行浮点型操作 * * @author gerry * */ static class SumDoubleEvaluator extends GenericUDAFEvaluator { private PrimitiveObjectInspector inputOI; static class SumDoubleAgg implements AggregationBuffer { double sum; boolean empty; } @Override public ObjectInspector init(Mode m, ObjectInspector[] parameters) throws HiveException { super.init(m, parameters); this.inputOI = (PrimitiveObjectInspector) parameters[0]; return PrimitiveObjectInspectorFactory.writableDoubleObjectInspector; } @Override public AggregationBuffer getNewAggregationBuffer() throws HiveException { SumDoubleAgg sda = new SumDoubleAgg(); this.reset(sda); return sda; } @Override public void reset(AggregationBuffer agg) throws HiveException { SumDoubleAgg sda = (SumDoubleAgg) agg; sda.empty = true; sda.sum = 0; } @Override public void iterate(AggregationBuffer agg, Object[] parameters) throws HiveException { this.merge(agg, parameters[0]); } @Override public Object terminatePartial(AggregationBuffer agg) throws HiveException { return this.terminate(agg); } @Override public void merge(AggregationBuffer agg, Object partial) throws HiveException { if (partial != null) { SumDoubleAgg sda = (SumDoubleAgg) agg; sda.sum += PrimitiveObjectInspectorUtils.getDouble(partial, inputOI); sda.empty = false; } } @Override public Object terminate(AggregationBuffer agg) throws HiveException { SumDoubleAgg sda = (SumDoubleAgg) agg; if (sda.empty) { return null; } return new DoubleWritable(sda.sum); } } /** * 进行整形的sum操作 * * @author gerry * */ static class SumLongEvaluator extends GenericUDAFEvaluator { private PrimitiveObjectInspector inputOI; @Override public ObjectInspector init(Mode m, ObjectInspector[] parameters) throws HiveException { super.init(m, parameters); if (parameters.length != 1) { throw new UDFArgumentException("参数异常"); } inputOI = (PrimitiveObjectInspector) parameters[0]; return PrimitiveObjectInspectorFactory.writableLongObjectInspector; } /** * 自定义类型 * * @author gerry * */ static class SumLongAgg implements AggregationBuffer { long sum; boolean empty; } @Override public AggregationBuffer getNewAggregationBuffer() throws HiveException { SumLongAgg sla = new SumLongAgg(); this.reset(sla); return sla; } @Override public void reset(AggregationBuffer agg) throws HiveException { SumLongAgg sla = (SumLongAgg) agg; sla.sum = 0; sla.empty = true; } /** * 循环处理会调用的方法 */ @Override public void iterate(AggregationBuffer agg, Object[] parameters) throws HiveException { if (parameters.length != 1) { throw new UDFArgumentException("参数异常"); } this.merge(agg, parameters[0]); } /** * 部分聚合后的数据输出 * */ @Override public Object terminatePartial(AggregationBuffer agg) throws HiveException { return this.terminate(agg); } /** * 合并操作 */ @Override public void merge(AggregationBuffer agg, Object partial) throws HiveException { if (partial != null) { SumLongAgg sla = (SumLongAgg) agg; sla.sum += PrimitiveObjectInspectorUtils.getLong(partial, inputOI); sla.empty = false; } } /** * 全部输出 */ @Override public Object terminate(AggregationBuffer agg) throws HiveException { SumLongAgg sla = (SumLongAgg) agg; if (sla.empty) { return null; } return new LongWritable(sla.sum); } }}
三、UDTF介绍–主要用于收集日志的解析
UDTF(User-Defined Table-Generating Function)支持一个输入多个输出。一般用于解析工作,比如说解析url,然后获取url中的信息。要求继承类org.apache.hadoop.hive.ql.udf.generic.GenericUDTF,实现方法:initialize(返回返回值的参数类型)、process具体的处理方法,一般在这个方法中会调用父类的forward方法进行数据的写出、close关闭资源方法,最终会调用close方法,同MR程序中的cleanUp方法。
UDTF实例:解析爬虫数据,从数据中读取产品id、产品名称、价格。
1. 实现udtf,并打包jar,copy到linux机器上。
package com.beifeng.hive.ql;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.StringTokenizer;import org.apache.hadoop.hive.ql.exec.UDFArgumentException;import org.apache.hadoop.hive.ql.metadata.HiveException;import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;public class UDTFCase extends GenericUDTF { @Override public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException { // 比较参数大小 if (argOIs.getAllStructFieldRefs().size() != 1) { throw new UDFArgumentException("参数异常"); } ArrayList<String> fieldNames = new ArrayList<>(); ArrayList<ObjectInspector> fieldOIs = new ArrayList<>(); fieldNames.add("id"); fieldNames.add("name"); fieldNames.add("price"); fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs); } // "p_id":"100001","p_name":"<张家界-凤凰-天门山-玻璃栈道飞机5日游>","price":"2141" // pid:xxx // pname:xxx // price:xxx @Override public void process(Object[] args) throws HiveException { if (args == null && args.length != 1) { return; } // 只有一个参数的情况 String line = args[0].toString(); // 调用函数解析字符串 Map<String, String> map = transfoerContent2Map(line); List<String> result = new ArrayList<>(); result.add(map.get("p_id")); result.add(map.get("p_name")); result.add(map.get("price")); super.forward(result.toArray(new String[0])); } @Override public void close() throws HiveException { // nothing super.forward(new String[] { "12345689", "close", "123" }); } /** * 转换字符串为map对象 * * @param content * @return */ static Map<String, String> transfoerContent2Map(String content) { Map<String, String> map = new HashMap<String, String>(); int i = 0; String key = ""; // 删掉不需要的字符 StringTokenizer tokenizer = new StringTokenizer(content, "({|}|\"|:|,)"); while (tokenizer.hasMoreTokens()) { if (++i % 2 == 0) { // 当前的值是value map.put(key, tokenizer.nextToken()); } else { // 当前的值是key key = tokenizer.nextToken(); } } return map; }}
- 创建hbase关联表(将hbase中数据导入hive表中。。)
create external table hive_data(rowkey string,content string) row format serde ‘org.apache.hadoop.hive.hbase.HBaseSerDe’ stored by ‘org.apache.hadoop.hive.hbase.HBaseStorageHandler’ with serdeproperties(‘hbase.columns.mapping’=’:key,f:content’) tblproperties (‘hbase.table.name’=’data’); - 创建函数
add jar /home/hadoop/bigdater/jobs/beifeng14-0.0.1.jar;
create function f1 as ‘com.beifeng.hive.ql.UDTFCase’;
4.运行f1函数
select f1(content) as(id,name,price) from hive_data;
四、常用的三种集成自定义函数的方式
首先要求创建的function是永久function,不能是临时function。
第一种:修改hive-site.xml文件,添加参数hive.aux.jars.path,value为jar包的linux本地路径,要求是以file:///开头的绝对路径。
第二种:直接将jar包移动到hive的lib文件夹中。
第三种:将jar包移动到hdfs上,然后在创建function的时候指定function使用的hdfs上的jar文件绝对路径(包括hdfs://hh:8020/前缀),这样在使用的时候,hive会自动将jar下载到本地进行缓存的。
- 修改hive-site.xml
<property> <name>hive.aux.jars.path</name> <value>file:///home/hadoop/bigdater/jobs/beifeng14-0.0.1.jar</value></property>
最常用的:使用将jar上传到hdfs中,然后再进行操作的方式。
1. 上传文件到hdfs:【hive上传特别快】
hive> dfs -put /home/hadoop/bigdater/jobs/beifeng14-0.0.1.jar /beifeng/beifeng14-0.0.1.jar
2. 创建函数:create function f2 as ‘com.beifeng.hive.ql.UDTFCase’ using jar ‘hdfs://hh:8020/beifeng/beifeng14-0.0.1.jar’;
3. 正常使用
另外一种hive集成自定义函数的方式【很少用】
我们可以通过修改hive的源码,进行自定义函数的添加,添加完成后,我们就不需要再手动创建函数。添加步骤如下:
1. 假设自定义函数的整个包名为com.beifeng.ql.udf.UDFTest, jar文件为beifengUserUDF.jar。将该jar包移动到hive的lib文件夹中。
2. 修改hive源文件
$HIVE_HOME/src/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java,添加import com.beifeng.ql.udf.UDFTest; registerUDF(“test”, UDFTest.class,false);
3. 编译hive后,进行jar包的替换,然后就可以使用函数了。
- 15 Hive 函数与自定义函数
- Hive 自定义函数函数
- Hive 自定义函数函数
- 【Hive自定义UDF函数】 与 【hive字符串函数】
- 自定义-Hive自定义函数
- hadoop(十) - hive安装与自定义函数
- Hive自定义函数与transform的使用
- HIVE中的自定义函数
- hive用户自定义函数
- HIVE中的自定义函数 .
- HIVE中的自定义函数
- HIVE 自定义函数 UDF
- HIVE中的自定义函数
- hive中的自定义函数
- Hive自定义函数
- Hive自定义函数
- Hive自定义函数
- HIVE 自定义函数
- C++Primer第五版 第十五章习题答案(21~30)
- Hibernate关系映射(3) 一对多关系映射
- 正则表达式
- Spring事务管理之最实用的注解创建事务【Spring入门】
- lucene倒排索引缓冲池的细节
- 15 Hive 函数与自定义函数
- VS2012中添加头文件和库文件
- 26.session聚合统计之计算统计结果并写入MySQL
- 简介JAVA类库与import的用法
- Maven相关一-POM概述
- Python使用HTTP代理 Proxy
- L1-024. 后天
- Spring mvc中@RequestMapping 6个基本用法小结
- Linux 点滴