大数据

自定义hive udf 流程步骤 java版本

文 / sptk 来源 / 原创 阅读 / 133 3月前

1. 这里我们用编写一个strip自定义udf,用于删除字符串两端的包含指定的字符

# 示例
strip("abca",'ab')-> 'c'
strip("abc",'ac')-> 'b'

2. 使用java maven 创建自定义udf java 类

下面的是StripUDF.class 以及相关的依赖pom文件 官方提供的https://cwiki.apache.org/confluence/display/Hive/HivePlugins
官方示例提供的指需要继承UDF类,但是这个实现无法对参数做对应的检查, 例如官方的一些udf方法也是这样实现 例如 regex_replace 它也是继承自udf,同样的没做参数检查,https://github.com/apache/hive/blob/master/ql/src/java/org/apache/hadoop/hive/ql/udf/UDFRegExpReplace.java 我们下面的示例,使用继承GenericUDF 可以帮助我们完成更多的检查,但是这个实现难度要大于我们的继承udf的方法.

// StripUDF.class 代码
package com.sptk.udf;

import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDFUtils;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorConverter.TextConverter;
import org.apache.hadoop.io.Text;


import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Description(name = "strip", value = "_FUNC_(str1,str2) - 删除左右两侧指定的字符", extended = "Example:\n" + "  > SELECT _FUNC_('abca','a') FROM src LIMIT 1;\n" + "  bc")
public class StripUDF extends GenericUDF {

    private PrimitiveObjectInspector inputOI;
    private transient TextConverter stringToTrimConverter;   // 指定转换器
    private transient TextConverter trimCharsConverter;

    private Text result = new Text();

    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        // 检查参数个数
        checkArguments(arguments);

        // 设置udf返回的类型
        return PrimitiveObjectInspectorFactory.writableStringObjectInspector;
    }

    private void checkArguments(ObjectInspector[] arguments) throws UDFArgumentException {
        // 参数个数检查
        if (arguments.length != 2) {
            throw new UDFArgumentException(getUdfName() + " requires  two  argument. Found :"
                    + arguments.length);
        }
        // 这个仅仅检查是不是hive支持的基础类型
        for (int i = 0; i < arguments.length; i++) {
            if (arguments[i].getCategory() != ObjectInspector.Category.PRIMITIVE) {
                throw new UDFArgumentTypeException(i, "Only primitive type arguments are accepted but " + arguments[i].getTypeName() + " is passed.");
            }
            // 具体类型检查,由于检查的2个参数都是string类型 所以我们一起写了
            // 转换成具体的类型做检查
            PrimitiveObjectInspector.PrimitiveCategory inputType = ((PrimitiveObjectInspector) arguments[0]).getPrimitiveCategory();
            switch (inputType) {
                case STRING:
                case CHAR:
                case VARCHAR:
                case VOID:
                    break;
                default:
                    throw new UDFArgumentException(getUdfName() + " takes only STRING/CHAR/VARCHAR types. Found " + inputType);
            }
        }
    }

    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        // 获取输入参数的值 (用官方的 推荐使用转换器处理)
        // strimudf 示例 https://github.com/apache/hive/blob/master/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFBaseTrim.java#L33
        String src_str = arguments[0].get().toString();
        String strip_str = arguments[1].get().toString();


        System.out.println(src_str + strip_str);
        if (src_str == null || strip_str == null) {
            return null;
        }
        System.out.println(String.format("^[%s]*(.+)[%s]*$", strip_str, strip_str));
        Pattern com = Pattern.compile(String.format("^[%s]*(.+?)[%s]*$", strip_str, strip_str));
        Matcher m = com.matcher(src_str);
        if (m.find()) {
            result.set(m.group(1));
            return result;
        } else {
            return null;
        }

    }

    @Override
    public String getDisplayString(String[] children) {
        return getStandardDisplayString("Strip str", children);
    }
}

对应的pom.xml文件, 主要提供使用的依赖给大家参考

<?xml version="1.0" encoding="UTF-8"?>
<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>com.sptk</groupId>
    <artifactId>hive-udf</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>3.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>3.1.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>3.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-jdbc</artifactId>
            <version>3.1.2</version>
            <exclusions>
                <exclusion>
                    <groupId>org.glassfish</groupId>
                    <artifactId>javax.el</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>jetty</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-common</artifactId>
            <version>3.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-serde</artifactId>
            <version>3.1.2</version>
        </dependency>

    </dependencies>

</project>

这里给大家提供一份 我自己编写的jar 用于测试 链接:https://pan.baidu.com/s/1_EJge8wZQg8TTdm_iM-XrA?pwd=gzl2 提取码:gzl2

3. 通过maven工具 进行pacakage打包

4. 打包的jar包一般会带着版本号,所以建议将打包的 jar包可以重命名下 hive-udf-strip.jar

5. 将打包的jar包 上传到hdfs目录

方式一: 可以先将jar包上传到 服务器目录 再使用命令 hdfs dfs -put hive-udf-strip.jar /hive_udf
方式二: 使用我们的hadoop wen ui 进行文件上传

6. 启动连接hive 或者 datagrip

7. 执行下面的命令创建并注册udf方法

# 注明下面的命令是hive或者datagrip中执行的
# 创建strip方法 注意 指定包的位置: com.sptk.udf.StripUDF是你自己场景的java包的位置, 这个是我自己的包
# 后面指定jar的位置,替换成你自己的 
create function strip as 'com.sptk.udf.StripUDF' using jar 'hdfs://node1:8020/hive_udf/hive-udf-strip.jar';

# 如果我们测试发现有问题,我们需要重新调整jar包,重新注册. 需要先按照下面的操作进行删除 缓存的jar包 以及 我们hdfs的jar包
# 删除函数
drop function  strip;
# 查看使用的jar包
list jar;     #  我这里显示 /tmp/003dd8b3-0386-48ad-a4b0-8873f023a3d5_resources/hive-udf-strip.jar

# 删除 jar包
delete jar /tmp/003dd8b3-0386-48ad-a4b0-8873f023a3d5_resources/hive-udf-strip.jar  

# 最好再去我的连接hive节点删除对应的jar包 [推荐做的尤其是我们调试jar包的时候]  shell终端完成
rm /tmp/003dd8b3-0386-48ad-a4b0-8873f023a3d5_resources/hive-udf-strip.jar

# 删除hdfs的jar包 可以通过web ui 删除 也可以使用shell命令行删除  `hdfs dfs -delete /hive_udf/hive-udf-strip.jar`

0

站点声明:站点主要用于个人技术文章。

冀ICP备19037883号
相关侵权、举报、投诉及建议等,请发E-mail:804330969@qq.com