7、hive shell客户端与属性配置、内置运算符、函数(内置运算符与自定义UDF运算符)

Apache Hive 系列文章

1、apache-hive-3.1.2简介及部署(三种部署方式-内嵌模式、本地模式和远程模式)及验证详解
2、hive相关概念详解–架构、读写文件机制、数据存储
3、hive的使用示例详解-建表、数据类型详解、内部外部表、分区表、分桶表
4、hive的使用示例详解-事务表、视图、物化视图、DDL(数据库、表以及分区)管理详细操作
5、hive的load、insert、事务表使用详解及示例
6、hive的select(GROUP BY、ORDER BY、CLUSTER BY、SORT BY、LIMIT、union、CTE)、join使用详解及示例
7、hive shell客户端与属性配置、内置运算符、函数(内置运算符与自定义UDF运算符)
8、hive的关系运算、逻辑预算、数学运算、数值运算、日期函数、条件函数和字符串函数的语法与使用示例详解
9、hive的explode、Lateral View侧视图、聚合函数、窗口函数、抽样函数使用详解
10、hive综合示例:数据多分隔符(正则RegexSerDe)、url解析、行列转换常用函数(case when、union、concat和explode)详细使用示例
11、hive综合应用示例:json解析、窗口函数应用(连续登录、级联累加、topN)、拉链表应用
12、Hive优化-文件存储格式和压缩格式优化与job执行优化(执行计划、MR属性、join、优化器、谓词下推和数据倾斜优化)详细介绍及示例
13、java api访问hive操作示例



本文介绍hive shell客户端的属性配置、内置运算符和函数的内容及使用示例。
本文依赖hive环境可用。
本文分为三个部分,即shell客户端属性配置、内置的运算符使用和函数使用。

一、客户端与属性配置

1、CLIs and Commands客户端和命令

在这里插入图片描述

1)、Beeline CLI

$HIVE_HOME/bin/beeline被称之为第二代客户端或者新客户端,是一个JDBC客户端,是官方强烈推荐使用的Hive命令行工具,和第一代客户端相比,性能加强安全性提高。
Beeline在嵌入式模式和远程模式下均可工作。

[alanchan@server4 bin]$ pwd
/usr/local/bigdata/apache-hive-3.1.2-bin/bin
[alanchan@server4 bin]$ beeline
Beeline version 3.1.2 by Apache Hive
beeline> ! connect jdbc:hive2://server4:10000
Connecting to jdbc:hive2://server4:10000
Enter username for jdbc:hive2://server4:10000: alanchan
Enter password for jdbc:hive2://server4:10000: ********
Connected to: Apache Hive (version 3.1.2)
Driver: Hive JDBC (version 3.1.2)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://server4:10000>

2、Configuration Properties属性配置

Hive配置属性是在HiveConf.Java类中管理的,可以参考文件以获取当前使用版中可用的配置属性列表;
从Hive 0.14.0开始,会从HiveConf.java类中直接生成配置模板文件hive-default.xml.template;
详细的配置参数大全可以参考Hive官网配置参数
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties

1)、方式一:hive-site.xml

在$HIVE_HOME/conf路径下,可以添加一个hive-site.xml文件,把需要定义修改的配置属性添加进去,这个配置文件会影响到基于这个Hive安装包的任何一种服务启动、客户端使用方式。比如使用MySQL作为元数据的存储介质,把连接MySQL的相关属性配置在hive-site.xml文件中,这样不管是本地模式还是远程模式启动,不管客户端本地连接还是远程连接,都将访问同一个元数据存储介质。

<configuration>
    <!-- 存储元数据mysql相关配置 -->
    <property>
        <name>javax.jdo.option.ConnectionURL</name>
        <value> jdbc:mysql://node1:3306/hive?createDatabaseIfNotExist=true&amp;useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8</value>
    </property>

    <property>
        <name>javax.jdo.option.ConnectionDriverName</name>
        <value>com.mysql.jdbc.Driver</value>
    </property>
</configuration>

2)、方式二:–hiveconf命令行参数

hiveconf是一个命令行的参数,用于在使用Hive CLI或者Beeline CLI的时候指定配置参数。
这种方式的配置在整个的会话session中有效,会话结束,失效。
比如在启动hive服务的时候,为了更好的查看启动详情,可以通过hiveconf参数修改日志级别:

hive --hiveconf hive.root.logger=DEBUG,console

3)、方式三:set命令

在Hive CLI或Beeline中使用set命令为set命令之后的所有SQL语句设置配置参数,这个也是会话级别的。
这种方式也是用户日常开发中使用最多的一种配置参数方式。
因为Hive倡导一种:谁需要、谁配置、谁使用的一种思想,避免你的属性修改影响其他用户的修改

#启用hive动态分区,需要在hive会话中设置两个参数:
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;

4)、方式四:服务特定配置文件

hivemetastore-site.xml、hiveserver2-site.xml
Hive Metastore会加载可用的hive-site.xml以及hivemetastore-site.xml配置文件。
HiveServer2会加载可用的hive-site.xml以及hiveserver2-site.xml。
如果HiveServer2以嵌入式模式使用元存储,则还将加载hivemetastore-site.xml。

5)、配置方式选择

  • 配置方式优先级

set设置 > hiveconf参数 > hive-site.xml配置文件
set参数声明会覆盖命令行参数hiveconf,命令行参数会覆盖配置文件hive-site.xml设定
日常开发使用中,如果不是核心的需要全局修改的参数属性,建议使用set命令进行设置

  • Hive也会读入Hadoop的配置,因为Hive是作为Hadoop的客户端启动的,Hive的配置会覆盖Hadoop的配置

二、Hive内置运算符

Hive支持的运算符可以分为三大类:关系运算、算术运算、逻辑运算。
官方参考文档:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
也可以使用下述方式查看运算符的使用方式

--显示所有的函数和运算符
show functions;
--查看运算符或者函数的使用说明
describe function count;
--使用extended 可以查看更加详细的使用说明
describe function extended count;

1、关系运算符及示例

关系运算符是二元运算符,执行的是两个操作数的比较运算。
每个关系运算符都返回boolean类型结果(TRUE或FALSE)。

  • 环境准备
--1、创建表dual
create table dual(id string);
--2、加载一个文件dual.txt到dual表中
--dual.txt只有一行内容:内容为一个空格
load data local inpath '/root/hivedata/dual.txt' into table dual;
--3、在select查询语句中使用dual表完成运算符、函数功能测试
select 1+1 from dual;

select 1+1;
  • 示例
----------------Hive中关系运算符--------------------------
--is null空值判断
select 1 from dual where 'itcast' is null;

--is not null 非空值判断
select 1 from dual where 'itcast' is not null;

--like比较: _表示任意单个字符 %表示任意数量字符
--否定比较: NOT A like B
select 1 from dual where 'itcast' like 'it_';
select 1 from dual where 'itcast' like 'it%';
select 1 from dual where  'itcast' not like 'hadoo_';
select 1 from dual where  not 'itcast' like 'hadoo_';

--rlike:确定字符串是否匹配正则表达式,是REGEXP_LIKE()的同义词。
select 1 from dual where 'itcast' rlike '^i.*t$';
select 1 from dual where '123456' rlike '^\\d+$';  --判断是否全为数字
select 1 from dual where '123456aa' rlike '^\\d+$';

--regexp:功能与rlike相同 用于判断字符串是否匹配正则表达式
select 1 from dual where 'itcast' regexp '^i.*t$';

2、算术运算符及示例

-------------------Hive中算术运算符---------------------------------
--取整操作: div  给出将A除以B所得的整数部分。例如17 div 3得出5。
select 17 div 3;

--取余操作: %  也叫做取模mod  A除以B所得的余数部分
select 17 % 3;

--位与操作: &  A和B按位进行与操作的结果。 与表示两个都为1则结果为1
select 4 & 8 from dual;  --4转换二进制:0100 8转换二进制:1000
select 6 & 4 from dual;  --4转换二进制:0100 6转换二进制:0110

--位或操作: |  A和B按位进行或操作的结果  或表示有一个为1则结果为1
select 4 | 8 from dual;
select 6 | 4 from dual;

--位异或操作: ^ A和B按位进行异或操作的结果 异或表示两者的值不同,则结果为1
select 4 ^ 8 from dual;
select 6 ^ 4 from dual;

3、逻辑运算符及示例

--3、Hive逻辑运算符
--与操作: A AND B   如果A和B均为TRUE,则为TRUE,否则为FALSE。如果A或B为NULL,则为NULL。
select 1 from dual where 3>1 and 2>1;
--或操作: A OR B   如果A或B或两者均为TRUE,则为TRUE,否则为FALSE。
select 1 from dual where 3>1 or 2!=2;
--非操作: NOT A 、!A   如果A为FALSE,则为TRUE;如果A为NULL,则为NULL。否则为FALSE。
select 1 from dual where not 2>1;
select 1 from dual where !2=1;
--在:A IN (val1, val2, ...)  如果A等于任何值,则为TRUE。
select 1 from dual where 11  in(11,22,33);
--不在:A NOT IN (val1, val2, ...) 如果A不等于任何值,则为TRUE
select 1 from dual where 11 not in(22,33,44);
--逻辑是否存在: [NOT] EXISTS (subquery)
--将主查询的数据,放到子查询中做条件验证,根据验证结果(TRUE 或 FALSE)来决定主查询的数据结果是否得以保留。
select A.* from A
where exists (select B.id from B where A.id = B.id);

--其他运算符
select 'it' || 'cast';
select concat()

select `array`(11,22,33)
from dual;

三、Hive Functions函数

1、Hive 函数概述及分类标准

通过show functions命令在hive客户端查看当下可用的所有函数;
通过describe function extended funcname命令在hive客户端查看函数的使用方式。

2、分类标准

1)、Hive函数分类

  • Hive的函数分为两大类:内置函数(Built-in Functions)、用户定义函数UDF(User-Defined Functions)
  • 内置函数可分为:数值类型函数、日期类型函数、字符串类型函数、集合函数、条件函数等;
  • 用户定义函数根据输入输出的行数可分为3类:UDF、UDAF、UDTF。
    在这里插入图片描述

2)、根据函数输入输出的行数

  • UDF(User-Defined-Function)普通函数,一进一出
  • UDAF(User-Defined Aggregation Function)聚合函数,多进一出
  • UDTF(User-Defined Table-Generating Functions)表生成函数,一进多出
    在这里插入图片描述

2、Hive 内置函数

内置函数(build-in)指的是Hive已实现好,直接可以使用的函数,也叫做内建函数。
官方文档地址:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
内置函数根据应用归类整体可以分为8大种类型。

1)、String Functions 字符串函数示例

------------String Functions 字符串函数------------
select concat("angela","baby");
--带分隔符字符串连接函数:concat_ws(separator, [string | array(string)]+)
select concat_ws('.', 'www', array('win', 'com'));
--字符串截取函数:substr(str, pos[, len]) 或者  substring(str, pos[, len])
select substr("angelababy",-4); --pos是从1开始的索引,如果为负数则倒着数
select substr("angelababy",7,4);
0: jdbc:hive2://server4:10000> select substr("angelababy",-4); 
+-------+
|  _c0  |
+-------+
| baby  |
+-------+
0: jdbc:hive2://server4:10000> select substr("angelababy",7,4);
+-------+
|  _c0  |
+-------+
| baby  |
+-------+

--正则表达式替换函数:regexp_replace(str, regexp, rep)
select regexp_replace('100-200', '(\\d+)', 'num');
--正则表达式解析函数:regexp_extract(str, regexp[, idx]) 提取正则匹配到的指定组内容
select regexp_extract('100-200', '(\\d+)-(\\d+)', 2);
--URL解析函数:parse_url 注意要想一次解析出多个 可以使用parse_url_tuple这个UDTF函数
select parse_url('http://www.win.com/path/p1.php?query=1', 'HOST');
--分割字符串函数: split(str, regex)
select split('apache hive', '\\s+');
--json解析函数:get_json_object(json_txt, path)
--$表示json对象
select get_json_object('[{"website":"www.win.com","name":"allenwoon"}, {"website":"cloud.win.com","name":"carbondata 中文文档"}]', '$.[1].website');
0: jdbc:hive2://server4:10000> select get_json_object('[{"website":"www.win.com","name":"allenwoon"}, {"website":"cloud.win.com","name":"carbondata 中文文档"}]', '$.[1].website');
+----------------+
|      _c0       |
+----------------+
| cloud.win.com  |
+----------------+

--字符串长度函数:length(str | binary)
select length("angelababy");
--字符串反转函数:reverse
select reverse("angelababy");
--字符串连接函数:concat(str1, str2, ... strN)
--字符串转大写函数:upper,ucase
select upper("angelababy");
select ucase("angelababy");
--字符串转小写函数:lower,lcase
select lower("ANGELABABY");
select lcase("ANGELABABY");
--去空格函数:trim 去除左右两边的空格
select trim(" angelababy ");
--左边去空格函数:ltrim
select ltrim(" angelababy ");
--右边去空格函数:rtrim
select rtrim(" angelababy ");
--空格字符串函数:space(n) 返回指定个数空格
select space(4);
--重复字符串函数:repeat(str, n) 重复str字符串n次
select repeat("angela",2);
--首字符ascii函数:ascii
select ascii("angela");  --a对应ASCII 97
--左补足函数:lpad
select lpad('hi', 5, '??');  --???hi
select lpad('hi', 1, '??');  --h
--右补足函数:rpad
select rpad('hi', 5, '??');
--集合查找函数: find_in_set(str,str_array)
select find_in_set('a','abc,b,ab,c,def');

2)、Date Functions 日期函数

--获取当前日期: current_date
select current_date();
--获取当前时间戳: current_timestamp
--同一查询中对current_timestamp的所有调用均返回相同的值。
select current_timestamp();
--获取当前UNIX时间戳函数: unix_timestamp
select unix_timestamp();
--日期转UNIX时间戳函数: unix_timestamp
select unix_timestamp("2022-10-21 17:47:21");
--指定格式日期转UNIX时间戳函数: unix_timestamp
select unix_timestamp('20221021 17:47:21','yyyyMMdd HH:mm:ss');
--UNIX时间戳转日期函数: from_unixtime
select from_unixtime(1666374441);
select from_unixtime(0, 'yyyy-MM-dd HH:mm:ss');
0: jdbc:hive2://server4:10000> select from_unixtime(0, 'yyyy-MM-dd HH:mm:ss');
+----------------------+
|         _c0          |
+----------------------+
| 1970-01-01 00:00:00  |
+----------------------+
--日期比较函数: datediff  日期格式要求'yyyy-MM-dd HH:mm:ss' or 'yyyy-MM-dd'
select datediff('2022-10-21','2023-10-21');
0: jdbc:hive2://server4:10000> select datediff('2022-10-21','2023-10-21');
+-------+
|  _c0  |
+-------+
| -365  |
+-------+
--日期增加函数: date_add
select date_add('2022-9-21',10);
0: jdbc:hive2://server4:10000> select date_add('2022-9-21',10);
+-------------+
|     _c0     |
+-------------+
| 2022-10-01  |
+-------------+

--日期减少函数: date_sub
select date_sub('2022-10-01',10);


--抽取日期函数: to_date
select to_date('2022-10-21 17:47:21');
--日期转年函数: year
select year('2022-10-21 17:47:21');
--日期转月函数: month
select month('2022-10-21 17:47:21');
--日期转天函数: day
select day('2022-10-21 17:47:21');
--日期转小时函数: hour
select hour('2022-10-21 17:47:21');
--日期转分钟函数: minute
select minute('2022-10-21 17:47:21');
--日期转秒函数: second
select second('2022-10-21 17:47:21');
--日期转周函数: weekofyear 返回指定日期所示年份第几周
select weekofyear('2022-10-21 17:47:21');

3)、Mathematical Functions 数学函数

--取整函数: round  返回double类型的整数值部分 (遵循四舍五入)
select round(3.1415926);
--指定精度取整函数: round(double a, int d) 返回指定精度d的double类型
select round(3.1415926,4);
--向下取整函数: floor
select floor(3.1415926);
select floor(-3.1415926);
--向上取整函数: ceil
select ceil(3.1415926);
select ceil(-3.1415926);
--取随机数函数: rand 每次执行都不一样 返回一个0到1范围内的随机数
select rand();
--指定种子取随机数函数: rand(int seed) 得到一个稳定的随机数序列
select rand(3);

0: jdbc:hive2://server4:10000> select round(3.1415926);
+------+
| _c0  |
+------+
| 3    |
+------+
0: jdbc:hive2://server4:10000> select round(3.1415926,4);
+---------+
|   _c0   |
+---------+
| 3.1416  |
+---------+
0: jdbc:hive2://server4:10000> select floor(3.1415926);
+------+
| _c0  |
+------+
| 3    |
+------+
0: jdbc:hive2://server4:10000> select floor(-3.1415926);
+------+
| _c0  |
+------+
| -4   |
+------+
0: jdbc:hive2://server4:10000> select ceil(3.1415926);
+------+
| _c0  |
+------+
| 4    |
+------+
0: jdbc:hive2://server4:10000> select ceil(-3.1415926);
+------+
| _c0  |
+------+
| -3   |
+------+
0: jdbc:hive2://server4:10000> select rand();
+----------------------+
|         _c0          |
+----------------------+
| 0.45830703128392947  |
+----------------------+
0: jdbc:hive2://server4:10000> select rand(3);
+--------------------+
|        _c0         |
+--------------------+
| 0.731057369148862  |
+--------------------+

4)、二进制函数

bin(BIGINT a)
select bin(18);
--进制转换函数: conv(BIGINT num, int from_base, int to_base)
select conv(17,10,16);
--绝对值函数: abs
select abs(-3.9);

0: jdbc:hive2://server4:10000> select bin(18);
+--------+
|  _c0   |
+--------+
| 10010  |
+--------+
0: jdbc:hive2://server4:10000> select conv(17,10,16);
+------+
| _c0  |
+------+
| 11   |
+------+
0: jdbc:hive2://server4:10000> select abs(-3.9);
+------+
| _c0  |
+------+
| 3.9  |
+------+

5)、Collection Functions 集合函数

--集合元素size函数: 
size(Map<K.V>) 
size(Array<T>)
select size(`array`(11,22,33));
select size(`map`("id",10086,"name","zhangsan","age",18));

--取map集合keys函数: 
map_keys(Map<K.V>)
select map_keys(`map`("id",10086,"name","zhangsan","age",18));
0: jdbc:hive2://server4:10000> select map_keys(`map`("id",10086,"name","zhangsan","age",18));
+----------------------+
|         _c0          |
+----------------------+
| ["id","name","age"]  |
+----------------------+

--取map集合values函数: 
map_values(Map<K.V>)
select map_values(`map`("id",10086,"name","zhangsan","age",18));

--判断数组是否包含指定元素: 
array_contains(Array<T>, value)
select array_contains(`array`(11,22,33),11);
select array_contains(`array`(11,22,33),66);

--数组排序函数:sort_array(Array<T>)
select sort_array(`array`(12,2,32));

6)、Conditional Functions 条件函数

select * from student limit 3;

describe function extended isnull;

--if条件判断: if(boolean testCondition, T valueTrue, T valueFalseOrNull)
select if(1=2,100,200);
select *,if(sex ='男','M','W') from student limit 3;
0: jdbc:hive2://server4:10000> select if(sex ='男','M','W') from student limit 3;
+------+
| _c0  |
+------+
| M    |
| W    |
| W    |
+------+
3 rows selected (0.107 seconds)
0: jdbc:hive2://server4:10000> select *,if(sex ='男','M','W') from student limit 3;
+--------------+---------------+--------------+--------------+---------------+------+
| student.num  | student.name  | student.sex  | student.age  | student.dept  | _c1  |
+--------------+---------------+--------------+--------------+---------------+------+
| 95001        | 李勇            || 20           | CS            | M    |
| 95002        | 刘晨            || 19           | IS            | W    |
| 95003        | 王敏            || 22           | MA            | W    |
+--------------+---------------+--------------+--------------+---------------+------+


--空判断函数: isnull( a )
select isnull("allen");
select isnull(null);

--非空判断函数: isnotnull ( a )
select isnotnull("allen");
select isnotnull(null);

--空值转换函数: nvl(T value, T default_value)
select nvl("alan","win");
select nvl(null,"win");

--非空查找函数: COALESCE(T v1, T v2, ...)
--返回参数中的第一个非空值;如果所有值都为NULL,那么返回NULL
select COALESCE(null,11,22,33);
select COALESCE(null,null,null,33);
select COALESCE(null,null,null);
0: jdbc:hive2://server4:10000> select COALESCE(null,11,22,33);
+------+
| _c0  |
+------+
| 11   |
+------+

--条件转换函数: CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END
select case 100 when 50 then 'tom' when 100 then 'mary' else 'tim' end;
select case sex when '男' then 'male' else 'female' end from student limit 3;
select *,
    case sex 
        when '男' then 'male' 
            else 'female' end 
from student limit 3;
0: jdbc:hive2://server4:10000> select case sex when '男' then 'male' else 'female' end from student limit 3;
+---------+
|   _c0   |
+---------+
| male    |
| female  |
| female  |
+---------+
3 rows selected (0.095 seconds)
0: jdbc:hive2://server4:10000> select *,case sex when '男' then 'male' else 'female' end from student limit 3;
+--------------+---------------+--------------+--------------+---------------+---------+
| student.num  | student.name  | student.sex  | student.age  | student.dept  |   _c1   |
+--------------+---------------+--------------+--------------+---------------+---------+
| 95001        | 李勇            || 20           | CS            | male    |
| 95002        | 刘晨            || 19           | IS            | female  |
| 95003        | 王敏            || 22           | MA            | female  |
+--------------+---------------+--------------+--------------+---------------+---------+

--nullif( a, b ):
-- 如果a = b,则返回NULL,否则返回一个
select nullif(11,11);
select nullif(11,12);

--assert_true(condition)
--如果'condition'不为真,则引发异常,否则返回null
SELECT assert_true(11 >= 0);
SELECT assert_true(-1 >= 0);

7)、Type Conversion Functions 类型转换函数

--任意数据类型之间转换:cast
select cast(12.14 as bigint);
select cast(12.14 as string);
select cast("hello" as int);
0: jdbc:hive2://server4:10000> select cast("hello" as int);
+-------+
|  _c0  |
+-------+
| NULL  |
+-------+

8)、Data Masking Functions 数据脱敏函数

--mask
--将查询回的数据,大写字母转换为X,小写字母转换为x,数字转换为n。
select mask("abc123DEF");
select mask("abc123DEF",'-','.','^'); --自定义替换的字母
0: jdbc:hive2://server4:10000> select mask("abc123DEF");
+------------+
|    _c0     |
+------------+
| xxxnnnXXX  |
+------------+
1 row selected (0.158 seconds)
0: jdbc:hive2://server4:10000> select mask("abc123DEF",'-','.','^'); 
+------------+
|    _c0     |
+------------+
| ...^^^---  |
+------------+

--mask_first_n(string str[, int n]
--对前n个进行脱敏替换
select mask_first_n("abc123DEF",4);

--mask_last_n(string str[, int n])
select mask_last_n("abc123DEF",4);

--mask_show_first_n(string str[, int n])
--除了前n个字符,其余进行掩码处理
select mask_show_first_n("abc123DEF",4);

--mask_show_last_n(string str[, int n])
select mask_show_last_n("abc123DEF",4);

--mask_hash(string|char|varchar str)
--返回字符串的hash编码。
select mask_hash("abc123DEF");

9)、Misc. Functions 其他杂项函数

--如果你要调用的java方法所在的jar包不是hive自带的 可以使用add jar添加进来
--hive调用java方法: java_method(class, method[, arg1[, arg2..]])
select java_method("java.lang.Math","max",11,22);

--反射函数: reflect(class, method[, arg1[, arg2..]])
select reflect("java.lang.Math","max",11,22);

--取哈希值函数:hash
select hash("alan");

--current_user()、logged_in_user()、current_database()、version()

--SHA-1加密: sha1(string/binary)
select sha1("alan");

--SHA-2家族算法加密:sha2(string/binary, int)  (SHA-224, SHA-256, SHA-384, SHA-512)
select sha2("alan",224);
select sha2("alan",512);

--crc32加密:
select crc32("alan");

--MD5加密: md5(string/binary)
select md5("alan");

0: jdbc:hive2://server4:10000> select java_method("java.lang.Math","max",11,22);
+------+
| _c0  |
+------+
| 22   |
+------+
0: jdbc:hive2://server4:10000> select reflect("java.lang.Math","max",11,22);
+------+
| _c0  |
+------+
| 22   |
+------+
0: jdbc:hive2://server4:10000> select hash("alan");
+----------+
|   _c0    |
+----------+
| 2996632  |
+----------+
0: jdbc:hive2://server4:10000> select sha1("alan");
+-------------------------------------------+
|                    _c0                    |
+-------------------------------------------+
| 91e38e63b890fbb214c8914809fde03c73e7f24d  |
+-------------------------------------------+
0: jdbc:hive2://server4:10000> select md5("alan");
+-----------------------------------+
|                _c0                |
+-----------------------------------+
| 02558a70324e7c4f269c69825450cec8  |
+-----------------------------------+

3、Hive 用户自定义函数(UDF、UDTF、UDAF)

用户自定义函数简称UDF,源自于英文user-defined function。
根据函数输入输出的行数可以分为3类,分别是:

  • UDF(User-Defined-Function)普通函数,一进一出
  • UDAF(User-Defined Aggregation Function)聚合函数,多进一出
  • UDTF(User-Defined Table-Generating Functions)表生成函数,一进多出
    在这里插入图片描述

1)、示例需求:UDF实现手机号****加密

对于敏感数据往往需要进行脱敏处理。比如手机号

  • 能够对输入数据进行非空判断、手机号位数判断
  • 能够实现校验手机号格式,把满足规则的进行****处理
  • 对于不符合手机号规则的数据直接返回,不处理

2)、UDF实现步骤

  1. 写一个java类,继承UDF,并重载evaluate方法,方法中实现函数的业务逻辑(重载意味着可以在一个java类中实现多个函数功能)
  2. 程序打成jar包,上传HS2服务器本地或者HDFS
  3. 客户端命令行中添加jar包到Hive的classpath: hive>add JAR /xxxx/udf.jar
  4. 注册成为临时函数(给UDF命名):create temporary function 函数名 as ‘UDF类全路径’
  5. HQL中使用函数

3)、pom.xml

<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-common</artifactId>
        <version>3.1.4</version>
    </dependency>
</dependencies>

4)、UDF和GenericUDF实现

UDF函数按照继承类可以分为2种,一个是UDF,一个是GenericUDF,GenericUDF的开发会比UDF复杂一些,一般在以下几种场景下考虑使用GenericUDF:

  • 传参情况复杂
    比如某UDF要传参数有多种数量或多种类型的情况,在UDF中支持这种场景我们需要实现N个不同的evaluate()方法分别对应N种场景的传参,在GenericUDF我们只需在一个方法内加上判断逻辑,对不同的输入路由到不同的处理逻辑上即可。还有比如某UDF参数既要支持String list参数,也要支持Integer list参数。Java不支持同一个方法重载参数只有泛型类型不一样,所以该场景只能用GenericUDF。

  • 需要传非Writable的或复杂数据类型作为参数
    比如嵌套数据结构,传入Map的key-value中的value为list数据类型,或者比如数据域数量不确定的Struct结构,都更适合使用GenericUDF在运行时捕获数据的内部构造

  • 该UDF被大量、高频地使用
    从收益上考虑,会尽可能地优化一切可以优化的地方,则GenericUDF相比UDF在operator中避免了多次反射转化的资源消耗,更适合被考虑

  • 该UDF函数功能未来预期的重构、扩展场景较多,需要做得足够可扩展,则GenericUDF在这方面更优秀

  • UDF

public class EncryptPhoneNumber extends UDF {
    /**
     * 重载evaluate方法 实现函数的业务逻辑
     * @param phoNum  入参:未加密手机号
     * @return 返回:加密后的手机号字符串
     */
    public String evaluate(String phoNum){
        String encryptPhoNum = null;
        //手机号不为空 并且为11位
        if (StringUtils.isNotEmpty(phoNum) && phoNum.trim().length() == 11 ) {
            //判断数据是否满足中国大陆手机号码规范
                String regex = "^(1[3-9]\\d{9}$)";
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(phoNum);
            if (m.matches()) {//进入这里都是符合手机号规则的
                //使用正则替换 返回加密后数据
                encryptPhoNum = phoNum.trim().replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2");
            }else{
                //不符合手机号规则 数据直接原封不动返回
                encryptPhoNum = phoNum;
            }
        }else{
            //不符合11位 数据直接原封不动返回
            encryptPhoNum = phoNum;
        }
        return encryptPhoNum;
    }
}


  • GenericUDF
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.JavaStringObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;

public class EncryptPhoneNumber extends GenericUDF {
	StringObjectInspector elementOI;
	/**
	 * Initialize this GenericUDF. This will be called once and only once per
	 * GenericUDF instance.
	 */
	@Override
	public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
		// 1. 检查该记录是否传过来正确的参数数量
		if (arguments.length != 1) {
			throw new UDFArgumentException("输入参数错误,必须是一个参数。");
		}
		// 2. 检查该条记录是否传过来正确的参数类型
		ObjectInspector a = arguments[0];
		if (!(a instanceof StringObjectInspector)) {
			throw new UDFArgumentException("輸入參數錯誤,需要是一個字符串");
		}

		// 3. 检查通过后,将参数赋值给成员变量ObjectInspector,为了在evaluate()中使用
		this.elementOI = (StringObjectInspector) a;
		return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
	}

	/**
	 * Evaluate the GenericUDF with the arguments. 重载evaluate方法 实现函数的业务逻辑
	 */
	@Override
	public Object evaluate(DeferredObject[] arguments) throws HiveException {
		String phoNum = elementOI.getPrimitiveJavaObject(arguments[0].get()).toString();
		String encryptPhoNum = null;
		// 手机号不为空 并且为11位
		if (StringUtils.isNotEmpty(phoNum) && phoNum.trim().length() == 11) {
			// 判断数据是否满足中国大陆手机号码规范
			String regex = "^(1[3-9]\\d{9}$)";
			Pattern p = Pattern.compile(regex);
			Matcher m = p.matcher(phoNum);
			if (m.matches()) {// 进入这里都是符合手机号规则的
				// 使用正则替换 返回加密后数据
				encryptPhoNum = phoNum.trim().replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
			} else {
				// 不符合手机号规则 数据直接原封不动返回
				encryptPhoNum = phoNum;
			}
		} else {
			// 不符合11位 数据直接原封不动返回
			encryptPhoNum = phoNum;
		}
		return encryptPhoNum;
	}

	/**
	 * Get the String to be displayed in explain.
	 */
	@Override
	public String getDisplayString(String[] children) {
		return "this is a EncryptPhoneNumber pro.";
	}

	public static void main(String[] args) throws Exception {
		EncryptPhoneNumber ep = new EncryptPhoneNumber();
		JavaStringObjectInspector stringOI = PrimitiveObjectInspectorFactory.javaStringObjectInspector;

		JavaStringObjectInspector resultInspector = (JavaStringObjectInspector) ep.initialize(new ObjectInspector[] { stringOI });

		Object result = ep.evaluate(new DeferredObject[] { new DeferredJavaObject("13917885967") });
		System.out.println("result:" + result);
	}

}

5)、打包

mvn package clean -Dmaven.test.skip=true

mvn package -Dmaven.test.skip=true

6)、添加jar包到Hive的classpath

0: jdbc:hive2://server4:10000> add jar /usr/local/bigdata/hive-0.0.1-SNAPSHOT.jar;
No rows affected (0.01 seconds)

7)、注册成为临时函数

create temporary function 函数名 as 'UDF类全路径';

create temporary function encryptPhoneNumber as 'org.hive.udf.EncryptPhoneNumber';

0: jdbc:hive2://server4:10000> create temporary function encryptPhoneNumber as 'org.hive.udf.EncryptPhoneNumber';
No rows affected (0.023 seconds)

8)、验证

0: jdbc:hive2://server4:10000> select encryptPhoneNumber("13788889999");
+--------------+
|     _c0      |
+--------------+
| 137****9999  |
+--------------+

以上,完成了hive shell客户端的属性配置、内置运算符和函数的介绍及使用示例。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 写好Hive UDF自定义函数需要完成以下步骤:1、定义UDF函数类,继承org.apache.hadoop.hive.ql.exec.UDF类;2、重写evaluate()方法,实现UDF函数的功能;3、将UDF函数编译成jar包;4、将jar包上传到Hive客户端机器上;5、使用add jar语句将UDF函数加载到Hive中;6、使用create temporary function语句注册UDF函数;7、使用UDF函数。 ### 回答2: Java写Hive UDF(User-Defined Function,用户自定义函数)是一种用于扩展Hive功能的方法。当Hive内置函数无法满足特定的需求时,可以使用Java编写自定义函数来处理数据。 编写Hive UDF的第一步是创建一个Java类,该类需要继承Hive提供的UDF基类,并重写evaluate()方法。evaluate()方法是自定义函数的核心逻辑,它会对每条输入数据进行处理,并返回结果。 在evaluate()方法中,可以利用Java的强大功能实现自定义的逻辑。例如,可以使用字符串处理函数、数学函数、日期函数等来处理输入的数据。还可以使用条件语句、循环语句等控制结构来实现复杂的业务逻辑。 在编写完自定义函数的Java代码后,需要进行编译,并将生成的jar包上传到Hive的classpath中。为了在Hive中调用自定义函数,需要使用CREATE FUNCTION语句来注册函数。在CREATE FUNCTION语句中,需要指定函数的名称、参数类型和返回类型,并指定要调用的Java类和方法。 在Hive中调用自定义函数时,可以像调用内置函数一样使用它。例如,可以将自定义函数应用于SELECT语句的字段中,以对数据进行处理和转换。 使用自定义函数可以使Hive具有更强大的功能,使其能够满足特定的业务需求。通过Java编写UDF,我们可以在Hive中使用自己熟悉和喜欢的编程语言来实现复杂的逻辑和算法。这为数据处理和分析提供了更多的可能性,使Hive成为一个强大且灵活的数据处理工具。 ### 回答3: Java写Hive UDF(User-Defined Function)自定义函数需要遵循一定的步骤和规范。下面是一个简单示例来说明如何编写Java代码来实现自定义Hive函数。 首先,创建一个Java类并命名为CustomFunction。该类需要继承org.apache.hadoop.hive.ql.exec.UDF类,实现evaluate方法。 ```java import org.apache.hadoop.hive.ql.exec.UDF; import org.apache.hadoop.io.Text; public class CustomFunction extends UDF { public Text evaluate(Text input) { if (input == null) { return null; } String value = input.toString(); // 在这里编写自定义函数的逻辑 String result = value + " processed"; return new Text(result); } } ``` 接下来,编译Java代码并创建一个JAR文件。可以使用Maven或者手动编译代码。 在Hive中,使用CREATE FUNCTION语句来注册自定义函数。假设将JAR文件命名为custom-function.jar,可以使用以下语句注册: ```sql CREATE FUNCTION custom_function AS 'com.example.CustomFunction' USING JAR 'hdfs:///path/to/custom-function.jar'; ``` 通过以上语句,注册了名为custom_function的自定义函数,并指定了自定义函数类的完全限定名以及JAR文件的位置。 最后,在Hive中使用自定义函数。例如,可以在SELECT语句中调用自定义函数: ```sql SELECT custom_function(column_name) FROM table_name; ``` 以上代码通过custom_function函数对column_name列中的值进行处理,并返回处理后的结果。 这是一个简单的示例来解释如何使用Java编写Hive UDF自定义函数。实际上,根据具体的需求,可能需要更复杂的逻辑和参数。编写自定义函数需要理解Hive的数据类型和函数接口,并根据需要进行相应的实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一瓢一瓢的饮 alanchanchn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值