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客户端属性配置、内置的运算符使用和函数使用。
$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>
Hive配置属性是在HiveConf.Java类中管理的,可以参考文件以获取当前使用版中可用的配置属性列表;
从Hive 0.14.0开始,会从HiveConf.java类中直接生成配置模板文件hive-default.xml.template;
详细的配置参数大全可以参考Hive官网配置参数
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties
在$HIVE_HOME/conf路径下,可以添加一个hive-site.xml文件,把需要定义修改的配置属性添加进去,这个配置文件会影响到基于这个Hive安装包的任何一种服务启动、客户端使用方式。比如使用MySQL作为元数据的存储介质,把连接MySQL的相关属性配置在hive-site.xml文件中,这样不管是本地模式还是远程模式启动,不管客户端本地连接还是远程连接,都将访问同一个元数据存储介质。
<configuration>
<property>
<name>javax.jdo.option.ConnectionURLname>
<value> jdbc:mysql://node1:3306/hive?createDatabaseIfNotExist=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8value>
property>
<property>
<name>javax.jdo.option.ConnectionDriverNamename>
<value>com.mysql.jdbc.Drivervalue>
property>
configuration>
hiveconf是一个命令行的参数,用于在使用Hive CLI或者Beeline CLI的时候指定配置参数。
这种方式的配置在整个的会话session中有效,会话结束,失效。
比如在启动hive服务的时候,为了更好的查看启动详情,可以通过hiveconf参数修改日志级别:
hive --hiveconf hive.root.logger=DEBUG,console
在Hive CLI或Beeline中使用set命令为set命令之后的所有SQL语句设置配置参数,这个也是会话级别的。
这种方式也是用户日常开发中使用最多的一种配置参数方式。
因为Hive倡导一种:谁需要、谁配置、谁使用的一种思想,避免你的属性修改影响其他用户的修改
#启用hive动态分区,需要在hive会话中设置两个参数:
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
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。
set设置 > hiveconf参数 > hive-site.xml配置文件
set参数声明会覆盖命令行参数hiveconf,命令行参数会覆盖配置文件hive-site.xml设定
日常开发使用中,如果不是核心的需要全局修改的参数属性,建议使用set命令进行设置
Hive支持的运算符可以分为三大类:关系运算、算术运算、逻辑运算。
官方参考文档:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
也可以使用下述方式查看运算符的使用方式
--显示所有的函数和运算符
show functions;
--查看运算符或者函数的使用说明
describe function count;
--使用extended 可以查看更加详细的使用说明
describe function extended count;
关系运算符是二元运算符,执行的是两个操作数的比较运算。
每个关系运算符都返回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$';
-------------------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、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;
通过show functions命令在hive客户端查看当下可用的所有函数;
通过describe function extended funcname命令在hive客户端查看函数的使用方式。
内置函数(build-in)指的是Hive已实现好,直接可以使用的函数,也叫做内建函数。
官方文档地址:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
内置函数根据应用归类整体可以分为8大种类型。
------------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');
--获取当前日期: 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');
--取整函数: 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 |
+--------------------+
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 |
+------+
--集合元素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)
select sort_array(`array`(12,2,32));
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);
--任意数据类型之间转换: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 |
+-------+
--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");
--如果你要调用的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 |
+-----------------------------------+
用户自定义函数简称UDF,源自于英文user-defined function。
根据函数输入输出的行数可以分为3类,分别是:
对于敏感数据往往需要进行脱敏处理。比如手机号
<dependencies>
<dependency>
<groupId>org.apache.hivegroupId>
<artifactId>hive-execartifactId>
<version>3.1.2version>
dependency>
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-commonartifactId>
<version>3.1.4version>
dependency>
dependencies>
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;
}
}
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);
}
}
mvn package clean -Dmaven.test.skip=true
mvn package -Dmaven.test.skip=true
0: jdbc:hive2://server4:10000> add jar /usr/local/bigdata/hive-0.0.1-SNAPSHOT.jar;
No rows affected (0.01 seconds)
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)
0: jdbc:hive2://server4:10000> select encryptPhoneNumber("13788889999");
+--------------+
| _c0 |
+--------------+
| 137****9999 |
+--------------+
以上,完成了hive shell客户端的属性配置、内置运算符和函数的介绍及使用示例。