Hive 函数:内置函数和用户自定义函数 (UDF) 示例

⚡ 智能摘要

Hive 函数分为两类:引擎自带的内置函数,涵盖集合、日期、数学运算、条件语句、字符串和其他各种操作;以及用户自定义函数。 Java Hive 不提供逻辑。

  • 📚 六个内置家庭: HiveQL 中可以直接调用集合函数、日期函数、数学函数、条件函数、字符串函数和其他各种函数。
  • 🧾 签名很重要: 每个函数都有一个固定的参数列表和一个已记录的返回类型,因此返回类型决定了它可以在哪里使用。
  • 🧩 用户自定义函数填补了空白: 当没有内置函数时, Java 继承自 org.apache.hadoop.hive.ql.exec.UDF 的类提供了缺失的操作。
  • 🔢 自定义函数的三种形式: UDF 每次返回一行,UDAF 将多行合并为一行,UDTF 将一行扩展为多行。
  • 🛠️ 注册只需两步: ADD JAR 将代码添加到类路径中,CREATE TEMPORARY FUNCTION 将名称绑定到类。
  • ♻️ 关键在于重复利用: 经过测试的用户自定义函数(UDF),例如词干提取器,可以从每个查询中调用,而无需每次都重新编写。

Hive 函数:内置函数和用户自定义函数

函数是为特定目的而构建的,用于对表列名的操作数执行数学、算术、逻辑和关系运算等操作。

内置函数

这些是 Hive 中已有的函数。首先,我们必须检查应用程序需求,然后才能在我们的应用程序中使用这些内置函数。我们可以在应用程序中直接调用这些函数。

语法和类型在下一节中提到。

Hive 中内置函数的类型:

  • 采集功能
  • 日期函数
  • 数学函数
  • 条件函数
  • 字符串函数
  • 杂项功能

下面将分别介绍这六个系列及其函数签名和返回类型。

采集功能

这些函数用于集合。集合指的是一组ping 它们返回单个元素或元素数组,具体取决于函数名称中提到的返回类型。

返回类型 功能名称 描述
INT 尺寸(地图) 它将获取并返回地图类型中的组件数量
INT 大小(数组) 它将获取并返回数组类型中的元素数量
大批 map_keys(Map ) 它会获取并返回一个包含输入映射中所有键的数组。该数组是无序的。
大批 map_values(Map ) 它会获取并返回一个包含输入映射值的数组。该数组是无序的。
大批 sort_array(数组) 将输入数组按元素升序排序并返回结果。
布尔 array_contains(数组, 价值) 如果数组包含作为第二个参数传递的值,则返回 TRUE。

日期函数

这些工具用于执行日期操作以及将日期类型从一种类型转换为另一种类型:

功能名称 返回类型 描述
unix_timestamp() BigInt有 我们将获得当前信息 Unix的 时间戳以秒为单位。该值在整个查询过程中并非固定不变。
to_date(字符串时间戳) 日期 它将获取并返回时间戳字符串中的日期部分
年份(字符串日期) INT 它将获取日期或时间戳字符串中的年份部分
季度(日期/时间戳/字符串) INT 它将获取并给出 1 到 4 范围内的日期、时间戳或字符串的季度
月(字符串日期) INT 它将给出日期或时间戳字符串的月份部分
小时(字符串日期) INT 它会获取并显示时间戳的小时数
分钟(字符串日期) INT 它会获取并给出时间戳的分钟数。
date_sub(字符串起始日期,整数天数) 日期 它将获取并返回子程序的结果。trac从起始日期起算若干天
当前日期 日期 它会在查询评估开始时获取并返回当前日期。
last_day(字符串日期) 绳子 它会获取并给出该日期所属月份的最后一天
trunc(字符串日期,字符串格式) 绳子 它将获取并给出截断为指定格式单位的日期。 支持格式: 月/月,年/年/年。

数学函数

这些函数用于数学运算。Hive 内置了一些数学函数,因此我们无需创建用户自定义函数 (UDF)。

功能名称 返回类型 描述
圆形(双X) 双盒套装 它将获取并返回 X 的四舍五入后的 BIGINT 值。
圆形(DOUBLE X,INT d) 双盒套装 它将获取并返回四舍五入到小数点后 d 位的 X 值。
圆形(DOUBLE X) 双盒套装 它将使用 HALF_EVEN 舍入模式(也称为银行家舍入)获取并返回 X 的四舍五入后的 BIGINT 值。
地板(DOUBLE X) 大数据 它将获取并返回小于或等于 X 值的最大 BIGINT 值。
天花板(DOUBLE a),天花板(DOUBLE a) 大数据 它将获取并返回大于或等于 a 值的最小 BIGINT 值。
rand(),rand(INT 种子) 双盒套装 它会获取并返回一个均匀分布在 0 到 1 之间的随机数。提供一个种子可以使序列重复生成。

条件函数

这些函数用于条件值检查。

功能名称 返回类型 描述
if(布尔测试条件,T 值 True,T 值 FalseOrNull) T 当 testCondition 为真时,它将返回 valueTrue;否则,它将返回 valueFalse 或 null。
isnull(X) 布尔 如果 X 为 NULL,则返回 true;否则返回 false。
isnotnull(X) 布尔 如果 X 不为 NULL,则返回 true;否则返回 false。
nvl(T 值,T 默认值) T 当值为 NULL 时,它将返回 default_value;否则,它将返回 value。

字符串函数

字符串操作和字符串运算由以下函数处理。

功能名称 返回类型 描述
反转(字符串 X) 绳子 它将给出 X 的反转字符串
rpad(字符串 str,整数长度,字符串 pad) 绳子 它将获取并给出带有填充物的 str,总长度为 length。
rtrim(字符串 X) 绳子 它将获取并返回从 X 的末尾(右侧)去除空格后得到的字符串。
举个例子, rtrim(' results ') 导致 ' results'
空格(INT n) 绳子 它将获取并返回一个包含 n 个空格的字符串。
拆分(STRING str,STRING pat) 排列 围绕 pat 分割 str (pat 是一个正则表达式)。
str_to_map(text[, delimiter1, delimiter2]) 地图 它将使用两个分隔符将文本拆分成键值对。分隔符1分隔键值对,分隔符2再将每个键值对拆分成多个键值对。

杂项功能

一些内置函数不属于上述任何类别。这些函数涵盖哈希、会话信息和任意调用。 Java 方法。

功能名称 返回类型 描述
hash(a1[, a2…]) INT 返回参数的哈希值
当前用户() 绳子 返回已配置身份验证器管理器中的当前用户名
当前数据库() 绳子 返回当前数据库的名称
md5(字符串/二进制) 绳子 返回 MD5 128 位校验和,以 32 位十六进制数字字符串的形式返回;如果参数为 NULL,则返回 NULL。
sha1(字符串/二进制) 绳子 返回参数的 SHA-1 摘要,以十六进制字符串形式表示。
crc32(字符串/二进制) BigInt有 返回字符串或二进制参数的循环冗余校验值
版本() 绳子 返回 Hive 版本,格式为构建编号后跟构建哈希值。
reflect(class, method[, arg1…]) 变化 打电话给 Java 通过反射匹配参数签名来获取方法。java_method() 是其同义词。

UDF(用户定义函数)

在 Hive 中,用户可以定义自己的函数来满足特定的客户端需求。这些函数在 Hive 中被称为用户自定义函数 (UDF)。用户自定义函数是用 Hive 编写的。 Java 对于特定模块。

有些用户自定义函数 (UDF) 专门设计用于在应用程序框架中重用代码。开发人员在代码中编写这些函数。 Java 并将这些用户自定义函数与 Hive 集成。

在查询执行过程中,开发人员可以直接使用代码,用户自定义函数 (UDF) 将根据用户定义的任务返回输出。它在编码和执行方面都提供了高性能。

例如,Hive 中没有预定义的字符串词干提取函数。为此,我们可以编写一个词干提取用户自定义函数 (UDF)。 Java凡是需要茎功能的地方,我们都可以直接在 Hive 中调用这个茎 UDF。

词干提取功能是指从词根中提取单词。词干提取算法会将“wishing”、“wished”和“wishes”还原为词根“wish”。为了实现这种功能,我们可以编写一个用户自定义函数 (UDF)。 Java 并将其与 蜂房.

根据使用场景的不同,UDF 可以编写成接受和生成不同数量的输入和输出值。

一般情况下,用户自定义函数 (UDF) 接受单个输入值并产生单个输出值。如果 UDF 用于查询中,则对于结果数据集中的每一行,UDF 都会被调用一次。

反过来,函数也可以接受一组值作为输入,并返回单个输出值。这种区别正是接下来要介绍的三种自定义函数类型之间的区别所在。

Hive 中的 UDF、UDAF 和 UDTF 的区别

Hive 中的自定义函数按输入和输出的行数进行分组。选择错误的数据类型是导致自定义函数无法编译或仅返回一行数据(而预期返回的是表格)的最常见原因。

类型 输入行 → 输出行 扩展类 内置示例
UDF 一行 → 一行 org.apache.hadoop.hive.ql.exec.UDF length()、round()、reverse()
UDAF 多行 → 单行 org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver count()、min()、max()
UDTF 一行 → 多行 org.apache.hadoop.hive.ql.udf.generic.GenericUDTF explode()、json_tuple()、parse_url_tuple()

从表格中可以得出两条实用规则:

  • UDAF 几乎总是与 GROUP BY 子句搭配使用,因为它将每个组折叠成一行。
  • UDTF 不能与同一 SELECT 列表中的其他列一起选择,因此通常与横向视图一起使用。

此外,还有一个功能更强大的基类 GenericUDF,用于行级工作,它接受数组、映射和结构体等复杂类型以及可变数量的参数。

如何在 Hive 中编写和注册 UDF

上面描述的茎叶示例可以通过四个步骤构建成一个实际函数。除此之外,没有其他内容。 Java 需要编译器和正在运行的 Hive 会话。

步骤1) 写一个 Java 继承自用户自定义函数 (UDF) 并实现公共 evaluate() 方法的类。Hive 会为每一行调用一次 evaluate() 方法,因此该方法必须能够处理 NULL 输入。

package com.guru99.hive.udf;

import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

public final class Stem extends UDF {

    public Text evaluate(final Text input) {
        if (input == null) {
            return null;
        }
        String word = input.toString().toLowerCase();
        if (word.endsWith("ing")) {
            word = word.substring(0, word.length() - 3);
        } else if (word.endsWith("ed") || word.endsWith("es")) {
            word = word.substring(0, word.length() - 2);
        }
        return new Text(word);
    }
}

步骤2) 编译该类并将其打包成 JAR 文件,例如 hive-udf-1.0.jar,以及它所依赖的任何类。

步骤3) 将 JAR 文件添加到 Hive 类路径中,并将函数名绑定到该类。临时函数仅在当前会话期间有效。

ADD JAR /home/hduser/hive-udf-1.0.jar;

CREATE TEMPORARY FUNCTION stem AS 'com.guru99.hive.udf.Stem';

步骤4) 调用新函数的方式与调用内置函数完全相同。对于单词“wishing”、“wished”和“wishes”,此类函数都返回“wish”。

SELECT word, stem(word) FROM words;

为了确保每个会话和每个用户都能使用该函数,请将其永久注册到数据库中。JAR 文件必须位于整个集群可以读取的路径上,通常这意味着 HDFS。

CREATE FUNCTION default.stem AS 'com.guru99.hive.udf.Stem'
USING JAR '/user/hive/udfs/hive-udf-1.0.jar';

一个类可以声明多个 `evaluate()` 方法。Hive 会将调用与参数签名进行匹配,这就是为什么一个函数可以同时接受字符串和整数参数的原因。

常见问题

SHOW FUNCTIONS 命令会列出所有已注册的名称,包括自定义名称。DESCRIBE FUNCTION name 命令会打印一行函数签名,而 DESCRIBE FUNCTION EXTENDED name 命令则会在实现类提供用法示例的情况下添加这些示例。

几乎总是名称或作用域问题:AS 后面的字符串必须是完全限定的类名,并且 ADD JAR 仅适用于运行它的会话。重新连接会删除 JAR 文件和任何临时函数。

当函数接受复杂类型(例如数组、映射或结构体)、可变数量的参数,或者需要自行验证参数类型时,请使用 GenericUDF。简单的 UDF 类通过反射解析类型,并且仅处理原始可写类型。

真正的用户自定义函数(UDF)必须在JVM上运行。对于其他语言, 蜂房 提供了 TRANSFORM 子句,该子句会将每一行数据通过外部脚本进行处理,例如: Python 它采用标准输入输出。速度较慢,但​​避免了…… Java 完全。

可以。`evaluate()` 函数每行运行一次,因此开销较大的逻辑会乘以行数,而且方法内部的对象分配会增加垃圾回收的压力。如果存在内置函数,请优先使用内置函数,并尽量避免 `evaluate()` 函数进行 I/O 操作。

不。函数名不区分大小写,所以 ROUND()、Round() 和 round() 都是同一个函数。 Java AS 子句中的类名是另一回事,它必须与编译后的类完全匹配,包括其包名。

机器学习助手会将纯文本描述映射到候选签名,并在返回类型与目标列不匹配时发出警告。请务必根据文档中的签名验证建议,因为生成的名称有时属于其他 SQL 方言。

它根据描述操作的注释生成一个可用的框架——类声明、导入语句和一个 evaluate() 方法。空值处理、可写类型和打包步骤仍需审查,并且该函数必须在真实数据行上进行测试。

总结一下这篇文章: