Hive从入门到精通(八)Hive函数

完整目录、平台简介、安装环境及版本:参考《Hive从入门到精通-概览》

八、Hive函数

在查询数据的时候,往往需要我们对数据进行清洗和处理,而HSQL提供了很多函数方便我们使用,其实很多函数和普通的SQL是一样的,接下来我们对常用的函数进行分析。

内置函数分类如下:

查看支持的所有函数:show functions;

查看具体某一个函数,比如max:show functions max;

当忘记某个函数具体名称时,可以使用模糊查询,比如查询m开头的函数和查询命令中包含ma的函数。

命令:show functions like 'm*';
命令:show functions like '*ma*';

具体查看某个函数的用法,比如查看max函数的用法:

命令:describe function max;

8.1 内置函数

8.1.1 数学函数

返回类型函数说明
BIGINTround(double a)四舍五入
DOUBLEround(double a,int d)小数部分d位之后数字四舍五入,例如round(21.263,2),返回21.26
BIGINTfloor(double a)对给定数据进行向下舍入最接近的整数。例如floor(21.2),返回21。
BIGINTceil(double a), ceiling(double a)将参数向上舍入为最接近的整数。例如ceil(21.2),返回23.
doublerand(), rand(int seed)返回大于或等于0且小于1的平均分布随机数(依重新计算而变)
doubleexp(double a)返回e的n次方
doubleln(double a)返回给定数值的自然对数
doublelog10(double a)返回给定数值的以10为底自然对数
doublelog2(double a)返回给定数值的以2为底自然对数
doublelog(double base, double a)返回给定底数及指数返回自然对数
doublepow(double a, double p) power(double a, double p)返回某数的乘幂
doublesqrt(double a)返回数值的平方根
stringbin(BIGINT a)返回二进制格式
stringhex(BIGINT a) hex(string a)将整数或字符转换为十六进制格式。  
stringunhex(string a)十六进制字符转换由数字表示的字符。
stringconv(BIGINT num, int from_base, int to_base)将指定数值,由原来的度量体系转换为指定的试题体系。例如CONV(‘a’,16,2),返回。
doubleabs(double a)取绝对值
int doublepmod(int a, int b) pmod(double a, double b)返回a除b的余数的绝对值
doublesin(double a)返回给定角度的正弦值
doubleasin(double a)返回x的反正弦,即是X。如果X是在-1到1的正弦值,返回NULL。
doublecos(double a)返回余弦
doubleacos(double a)返回X的反余弦,即余弦是X,,如果-1<= A <= 1,否则返回null.
int doublepositive(int a) positive(double a)返回A的值,例如positive(2),返回2。
int doublenegative(int a) negative(double a)返回A的相反数,例如negative(2),返回-2。
8.1.1.1 round

功能:四舍五入

命令:select no, score, round(score) from stu_course;

向下取整,比如4.3,四舍五入取整为4:

命令:select round(4.3);

向上取整,比如4.5,四舍五入取整为5:

命令:select round(4.5);

保留最多小数位:最后一位依旧是四舍五入取整,比如最多保留小数点后2位,这是4.2取整后还是4.2,4.255取整后就成4.26,而4.253整后则是4.25。

命令:select round(4.2, 2);
命令:select round(4.255, 2);
命令:select round(4.253, 2);

取整处理,比如145.123按十位数取整为145,按百位数取整为100,155.123按百位数取整则为200。

命令:select round(145.123,-1);
命令:select round(145.123,-2);
命令:select round(155.123,-2);
8.1.1.2 floor

功能:向下取整

命令:select no, score, floor(score) from stu_course;

不同于round的四舍五入,比如3.2向下取整后为3,3.59向下取整后依旧为3。

命令:select floor(3.59);
命令:select floor(3.29);
8.1.1.3 ceil

功能:向上取整

命令:select no, score, ceil(score) from stu_course;

和round四舍五入不同,比如3.2向上取整后为4,359向上取整后依旧为4。

命令:select ceil(3.59);
命令:select ceil(3.29);
8.1.1.4 abs

功能:取绝对值

即不论是整数还是负数,最后返回的都是整数。比如3.59返回的是3.59,-3.59返回的也就是3.59。

命令:select abs(-3.59);
命令:select abs(3.59);
8.1.1.5 least

功能:返回提供数据的最小值

不同于min,min是求一组数据的最小值。一般是配合聚合函数使用。而least是单数据的中的一些数据最小值处理。比如(1,-1,2,-1.5,3),返回的最小值为-1.5。

命令:select least(1,-1,2,-1.5,3);
8.1.1.6 greatest

功能:返回提供数据的最大值

和max的区别,max是求一组数据的最大值。一般是配合聚合函数使用。而greatest是单数据的中的一些数据最大值处理。,比如(1,-1,2,-1.5,3),返回的最大值为3。

命令:select greatest(1,-1,2,-1.5,3);

8.1.2 字符函数

返回类型函数说明
intlength(string A)返回字符串的长度
stringreverse(string A)返回倒序字符串
stringconcat(string A, string B…)连接多个字符串,合并为一个字符串,可以接受任意数量的输入字符串
stringconcat_ws(string SEP, string A, string B…)链接多个字符串,字符串之间以指定的分隔符分开。
stringsubstr(string A, int start) substring(string A, int start)从文本字符串中指定的起始位置后的字符。
stringsubstr(string A, int start, int len) substring(string A, int start, int len)从文本字符串中指定的位置指定长度的字符。
stringupper(string A) ucase(string A)将文本字符串转换成字母全部大写形式
stringlower(string A) lcase(string A)将文本字符串转换成字母全部小写形式
stringtrim(string A)删除字符串两端的空格,字符之间的空格保留
stringltrim(string A)删除字符串左边的空格,其他的空格保留
stringrtrim(string A)删除字符串右边的空格,其他的空格保留
stringregexp_replace(string A, string B, string C)字符串A中的B字符被C字符替代
stringregexp_extract(string subject, string pattern, int index)通过下标返回正则表达式指定的部分。regexp_extract(‘foothebar’, ‘foo(.*?)(bar)’, 2) returns ‘bar.’
stringparse_url(string urlString, string partToExtract [, string keyToExtract])返回URL指定的部分。parse_url(‘http://facebook.com/path1/p.php?k1=v1&k2=v2#Ref1′, ‘HOST’) 返回:’facebook.com’
stringget_json_object(string json_string, string path)select a.timestamp, get_json_object(a.appevents, ‘$.eventid’), get_json_object(a.appenvets, ‘$.eventname’) from log a;
stringspace(int n)返回指定数量的空格
stringrepeat(string str, int n)重复N次字符串
intascii(string str)返回字符串中首字符的数字值
stringlpad(string str, int len, string pad)返回指定长度的字符串,给定字符串长度小于指定长度时,由指定字符从左侧填补。
stringrpad(string str, int len, string pad)返回指定长度的字符串,给定字符串长度小于指定长度时,由指定字符从右侧填补。
arraysplit(string str, string pat)将字符串转换为数组。
intfind_in_set(string str, string strList)返回字符串str第一次在strlist出现的位置。如果任一参数为NULL,返回NULL;如果第一个参数包含逗号,返回0。
array<array<string>>sentences(string str, string lang, string locale)将字符串中内容按语句分组,每个单词间以逗号分隔,最后返回数组。 例如sentences(‘Hello there! How are you?’) 返回:( (“Hello”, “there”), (“How”, “are”, “you”) )
array<struct<string,double>>ngrams(array<array<string>>, int N, int K, int pf)SELECT ngrams(sentences(lower(tweet)), 2, 100 [, 1000]) FROM twitter;
array<struct<string,double>>context_ngrams(array<array<string>>, array<string>, int K, int pf)SELECT context_ngrams(sentences(lower(tweet)), array(null,null), 100, [, 1000]) FROM twitter;
8.1.2.1 substr

功能:截取字符串

格式:substr(string, int start, [int len]) ,其中len表示截取长度可选,没有的话,则默认截取到字符串末尾,注意此处start不是从0开始,而是从1开始,比如substr(‘abc’,1)返回的是abc,而不是bc。

命令:select substr('abc', 1);
命令:select substr('abc', 1, 2);
8.1.2.2 concat、concat_ws

功能:字符串拼接

其中concat_ws在拼接功能的基础上增加了字符串拼接之间插入的字符串。比如concat_ws(‘–‘, ‘123’,’456′,’789′),拼接后为123–456—789。

命令:select concat('123','456','789');
命令:select concat_ws('--', '123','456','789');
8.1.2.3 length

功能:获取字符串长度

命令:select length('我爱祖国');
命令:select length('abc');

对于中文,一个汉字是2个字节,但是是一个字符。

8.1.2.4 split

功能:将字符串按指定字符串进行切割,并返回数组

格式:split(字符串, 分割符)

如果字符串最后跟的是分割字符串,则返回的数组最后一个会为空。比如split(‘a–b–c–‘, ‘–‘)会返回[“a”,”b”,”c”,””]。

命令:select split('a--b--c', '--');
命令:select split('a--b--c--', '--');

有些分割符,是需要进行转义处理的,比如split(‘192.168.56.103′,’.’),其中’.’需要进行转义,否则因为正则返回[“”,””,””,””,””,””,””,””,””,””,””,””,””,””,””]

命令:select split('192.168.56.103','\\.');
命令:select split('192.168.56.103','.');
8.1.2.5 upper、lower

功能:upper将字符串转换为大写,lower则是将字符串转换为小写。

将指定字符串中的字符按要求转换为大写或者小写,有些字符比如’-’以及数字没有大小写之分的,则不转换。

命令:select upper('aAbBcC-');
命令:select lower('aAbBcC-');
8.1.2.6 trim

功能:裁剪字符串前后空格

命令:select trim('   abdc   e  ');
8.1.2.7 lpad、rpad

功能:左右填充字符串

命令:select lpad('abc',10,'*');左填充长度为10的字符串,不足的用*填充
命令:select lpad('abcefghijklmn',10,'*');超过长度时,进行截取

右填充和左填充规则一样,区别是在右边补充填充符号

命令:select rpad('abc',10,'*');
命令:select rpad('abcefghijklmn',10,'*');

8.1.3 收集函数

返回类型函数说明
intsize(Map<K.V>)返回的map类型的元素的数量
intsize(Array<T>)返回数组类型的元素数量
8.1.3.1 size(Array<T>)
命令:select size(array(1,2,3));
命令:select no, course, size(course) from stu_course;
8.1.3.2 size(Map<K.V>)
命令:select size(map(1,'value1',2,'value2'));
命令:select no, family, size(family) from stu_basic;

8.1.4 转换函数

返回类型函数说明
指定 “type”cast(expr as <type>)类型转换。 例如将字符”1″转换为整数: cast(‘1’ as bigint);,如果转换失败返回NULL。
8.1.4.1 case

注意:数据类型必须是可以进行相互转化的,类似于JAVA的强制转化,否则会返回NULL。

比如:将字符串转’1’化成整型,这个在JAVA里面是可以强制转化的:

命令:select cast('1' as bigint);
select no, cast(no as int) from stu_basic;

将float型转换为double型:

命令:select no, score, cast(score as double) from stu_course;

将字符串’2019-08-21’转换成date:

命令:select cast('2019-08-21' as date);
命令:select no, birthday, cast(birthday as date) from stu_basic;

再比如将字符串’a’转化为整型,这个不可以强制转化,会返回NULL:

命令:select cast('a' as bigint);
命令:select no, name, cast(name as int) from stu_basic;

8.1.5 日期函数

返回类型函数说明
stringfrom_unixtime(bigint unixtime[, string format])UNIX_TIMESTAMP参数表示返回一个值’YYYY- MM – DD HH:MM:SS’或YYYYMMDDHHMMSS.uuuuuu格式,这取决于是否是在一个字符串或数字语境中使用的功能。该值表示在当前的时区。
bigintunix_timestamp()如果不带参数的调用,返回一个Unix时间戳(从’1970- 01 – 0100:00:00′到现在的UTC秒数)为无符号整数。
bigintunix_timestamp(string date)指定日期参数调用UNIX_TIMESTAMP(),它返回参数值’1970- 01 – 0100:00:00′到指定日期的秒数。
bigintunix_timestamp(string date, string pattern)指定时间输入格式,返回到1970年秒数:unix_timestamp(’2009-03-20′, ‘yyyy-MM-dd’) = 1237532400 参考:http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html
stringto_date(string timestamp)返回时间中的年月日: to_date(“1970-01-01 00:00:00″) = “1970-01-01″
stringto_dates(string date)给定一个日期date,返回一个天数(0年以来的天数)
intyear(string date)返回指定时间的年份,范围在1000到9999,或为”零”日期的0。
intmonth(string date)返回指定时间的月份,范围为1至12月,或0一个月的一部分,如’0000-00-00′或’2008-00-00′的日期。
intday(string date) dayofmonth(date)返回指定时间的日期
inthour(string date)返回指定时间的小时,范围为0到23。
intminute(string date)返回指定时间的分钟,范围为0到59。
intsecond(string date)返回指定时间的秒,范围为0到59。
intweekofyear(string date)返回指定日期所在一年中的星期号,范围为0到53。
intdatediff(string enddate, string startdate)两个时间参数的日期之差。
intdate_add(string startdate, int days)给定时间,在此基础上加上指定的时间段。
intdate_sub(string startdate, int days)给定时间,在此基础上减去指定的时间段。
datecurrent_timestamp获取当前时间,格式如:2018-08-07 17:21:46.749
8.1.5.1 to_date

功能:将一个字符串中日期部分取出来

格式:to_date(‘ yyyy-MM-dd HH:mm:ss ‘);

命令:select to_date('2019-08-21 10:44:44');
命令:select no, birthday, to_date(birthday) from stu_basic;
8.1.5.2 year、month、day

功能:取出日期当中的年、月、日

格式:year/month/day (‘ yyyy-MM-dd **********’);

命令:select year('2019-08-21 14:48:28'), month('2019-08-21 14:48:28'), day('2019-08-21 14:48:28');
命令:select year('2019-08-21'), month('2019-08-21'), day('2019-08-21');
命令:select no, birthday, year(birthday), month(birthday), day(birthday) from stu_basic;
8.1.5.3 weakofyear

功能:计算一个日期在一年中,是第几周

命令:select weekofyear('2019-08-21 14:55:55');
命令:select weekofyear('2019-08-21');
命令:select no, birthday, weekofyear(birthday) from stu_basic;
8.1.5.4 datediff

功能:计算两个日期相差的天数

命令:select datediff('2019-08-21 14:55:55', '2018-08-21 14:55:55');
命令:select datediff('2019-08-21', '2018-08-21');
8.1.5.5 date_add、date_sub

功能:在一个日期的基础上加上或者减去多少天

命令:select date_add('2019-08-21 14:55:55', 20), date_sub('2019-08-21 14:55:55', 20);
命令:select date_add('2019-08-21', 20), date_sub('2019-08-21', 20);
命令:select no, birthday, date_add(birthday,1), date_sub(birthday,1) from stu_basic;
8.1.5.6 current_timestamp

功能:获取当前时间

格式:yyyy-MM-dd HH:mm:ss.ZZZ

命令:select current_timestamp;
8.1.5.7 current_date

功能:获取当前日期

格式:yyyy-MM-dd

命令:select current_date;
8.1.5.8 unix_timestamp

功能:获取当前系统时间戳,是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。

命令:select unix_timestamp();
8.1.5.9 时间转换

将时间戳转换为时间格式字符串。

格式:select from_unixtime(unix_timestamp(), [时间格式]);
其中时间格式可选,默认为yy-MM-dd HH:mm:ss
命令:select from_unixtime(unix_timestamp());
命令:select from_unixtime(unix_timestamp(), "yyyy/MM/dd HH:mm:ss");

将字符串转换为时间戳

格式:unix_timestamp(时间字符串, [时间格式]),默认的世界格式是 yy-MM-dd HH:mm:ss,可以指定

命令:select unix_timestamp('2019-08-21 10:44:44');
命令:select unix_timestamp('2019/08/21 10:44:44', 'yyyy/MM/dd HH:mm:ss');
命令:select no, birthday, unix_timestamp(birthday) from stu_basic;

8.1.6 条件函数

返回类型函数说明
Tif(boolean testCondition, T valueTrue, T valueFalseOrNull)判断是否满足条件,如果满足返回一个值,如果不满足则返回另一个值。
TCOALESCE(T v1, T v2, …)返回一组数据中,第一个不为NULL的值,如果均为NULL,返回NULL。
TCASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END当a=b时,返回c;当a=d时,返回e,否则返回f。
TCASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END当值为a时返回b,当值为c时返回d。否则返回e。
8.1.6.1 if

功能:条件判断

格式:if(boolean testCondition, T valueTrue, T valueFalseOrNull)

说明:当条件testCondition为TRUE时,返回valueTrue;否则返回valueFalseOrNull

命令:select if(1=1, 100, 101);返回100
命令:select if(1=2, 100, 101);返回101
命令:select no, age, if(age>21, 30, 10) from stu_basic;

查看当年龄大于21时,返回30,小于21时返回10,等于21时不变。

8.1.6.2 coalesce

功能:从左往右找到第一个不为空的值,如果所有都为NULL,那么返回NULL

命令:select coalesce(1,null);返回1
命令:select coalesce(null, 1);返回1
命令:select coalesce(null, null);返回空null

比如查询姓名、年龄和成绩,并返回年龄和成绩中第一个不为空的值

hive> select basic.no, name, age, score, coalesce(age, score)
    > from stu_basic basic join stu_course
    > where basic.no=stu_course.no;
8.1.6.3 case…when…

条件表达式,实现if..else逻辑

比如,如果年龄为21岁的加10岁,年龄为22岁的则设为20,其他加30岁。

hive> select no, name, age, case age
    > when 21 then age+10
    > when 22 then 20
    > else age+30
    > end from stu_basic;

8.2 聚合函数

返回类型函数说明
bigintcount(*)  count(expr)  count(DISTINCT expr[, expr_., expr_.])返回记录条数。
doublesum(col), sum(DISTINCT col)求和
doubleavg(col), avg(DISTINCT col)求平均值
doublemin(col)返回指定列中最小值
doublemax(col)返回指定列中最大值
doublevar_pop(col)返回指定列的方差
doublevar_samp(col)返回指定列的样本方差
doublestddev_pop(col)返回指定列的偏差
doublestddev_samp(col)返回指定列的样本偏差
doublecovar_pop(col1, col2)两列数值协方差
doublecovar_samp(col1, col2)两列数值样本协方差
doublecorr(col1, col2)返回两列数值的相关系数
doublepercentile(col, p)返回数值区域的百分比数值点。0<=P<=1,否则返回NULL,不支持浮点型数值。
array<double>percentile(col, array(p~1,,\ [, p,,2,,]…))返回数值区域的一组百分比值分别对应的数值点。0<=P<=1,否则返回NULL,不支持浮点型数值。
doublepercentile_approx(col, p[, B])Returns an approximate p^th^ percentile of a numeric column (including floating point types) in the group. The B parameter controls approximation accuracy at the cost of memory. Higher values yield better approximations, and the default is 10,000. When the number of distinct values in col is smaller than B, this gives an exact percentile value.
array<double>percentile_approx(col, array(p~1,, [, p,,2_]…) [, B])Same as above, but accepts and returns an array of percentile values instead of a single one.
array<struct\{‘x’,’y’\}>histogram_numeric(col, b)Computes a histogram of a numeric column in the group using b non-uniformly spaced bins. The output is an array of size b of double-valued (x,y) coordinates that represent the bin centers and heights
arraycollect_set(col)返回无重复记录

查询学生数:

命令:select count(*) from stu_basic;

查询学生最高成绩,最低成绩,平均成绩:

命令:select max(score), min(score), avg(score) from stu_course;

8.3 表生成函数

返回类型函数说明
数组explode(array<TYPE> a)数组一条记录中有多个参数,将参数拆分,每个参数生成一列。
 json_tupleget_json_object语句:select a.timestamp, get_json_object(a.appevents, ‘$.eventid’), get_json_object(a.appenvets, ‘$.eventname’) from log a; json_tuple语句: select a.timestamp, b.* from log a lateral view json_tuple(a.appevent, ‘eventid’, ‘eventname’) b as f1, f2

8.3.1 explode

功能:可以将集合的数据遍历出来,遍历出的每一个元素为新的一行。注意,使用explode会生成一个新的表

比如将split(‘a,b,c,d,e’,’,’)拆分成多行:

命令:select explode(split('a,b,c,d,e',','));

针对array字段进行转换:

命令:select explode(course) from stu_course;

针对map字段进行转换:

命令:select explode(family) from stu_basic;

注意,explode生成的是一个表,所以下面命令会报错

命令:select no, explode(course) from stu_course;

8.3.2 lateral view

lateral view是一个虚拟表,常和split、explode等UDTF一起使用的,能将一行数据拆分成多行数据,在此基础上可以对拆分的数据进行聚合,lateral view首先为原始表的每行调用UDTF,UDTF会把一行拆分成一行或者多行,lateral view再把结果组合,产生一个支持别名表的虚拟表。即explode将复杂结构一行拆成多行,然后再用lateral view做各种聚合。

格式:

lateral view udtf(expression) tableAlias as columnAlias (,columnAlias)*

lateral view在UDTF前使用,表示连接UDTF所分裂的字段。
UDTF(expression):使用的UDTF函数,例如explode()。
tableAlias:表示UDTF函数转换的虚拟表的名称。
columnAlias:表示虚拟表的虚拟字段名称,如果分裂之后有一个列,则写一个即可;如果分裂之后有多个列,按照列的顺序在括号中声明所有虚拟列名,以逗号隔开。

Lateral view相当于两个表在join,左边的表stu_course是原表,右边的表时explode之后产生的表,这个join只在同一行数据之间进行。

hive> select id, no, cour from stu_course
    > lateral view explode(course)tmp as cour
    > where id<5;

同理针对map,两个别名的情况,其中sub1和sub2分别代表map中key和value的别名。

hive> select id, name, sub1, sub2 from stu_basic
    > lateral view explode(family)tmp as sub1, sub2
    > where id<5;

8.4 其他

8.4.1 集合函数

8.4.1.1 array_contains

格式:array_contains(Array<T>, value)  返回boolean值,存在返回true,不存在则返回false。

命令:select array_contains(split('a,b,c,d,e',','), 'a');
命令:select array_contains(split('a,b,c,d,e',','), 'f');
8.4.1.2 sort_array

格式:sort_array(Array<T>) 返回排序后的数组

命令:select sort_array(array('b','a', 'd'));
命令:select sort_array(array(3,2,1));
8.4.1.3 map_keys

格式:map_keys(Map<T,T>),返回map的key数组

命令:select id, name, map_keys(family) from stu_basic;
8.4.1.4 map_values

格式:map_values(Map<T,T>),返回map的value数组

命令:select id, name, map_values(family) from stu_basic;

8.4.2 json函数

8.4.2.1 get_json_object

格式:get_json_object(json字符串,’$.key’)

作用:解析json字符串对象,通过 ‘$.key’ 来获取json串的value值

命令:select get_json_object('{"key1":1, "key2":2}', '$.key1');

其中json字符串为'{“key1”:1, “key2”:2}’

8.4.2.2 json_tuple

格式:json_tuple(json字符串,key值1,key值2) as (key1, key2)

作用:将json字符串的value值进行提取

命令:select json_tuple('{"key1":1, "key2":2, "key3":3}', 'key1', 'key2');

8.5 自定义函数

开发自定义UDF函数有两种方式:

  • 继承org.apache.hadoop.hive.ql.exec.UDF;
  • 继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF;

如果是针对简单的数据类型(比如String、Integer等)可以使用UDF,如果是针对复杂的数据类型(比如Array、Map、Struct等),可以使用GenericUDF,另外,GenericUDF还可以在函数开始之前和结束之后做一些初始化和关闭的处理操作。

步骤:

  • 1、创建集成自org.apache.hadoop.hive.ql.exec.UDF的java类;
  • 2、重写evaluate函数,支持函数重载;
  • 3、将java程序编译打包成jar包上传到节点;
  • 4、上传jar包
    • 对于临时自定义函数,在客户端使用add jar 命令添加Jar包;
    • 对于永久性函数,则直接将Jar包上传到HDFS目录;
  • 5、创建函数
    • 临时函数格式:create temporary function * as ‘JAVA类名’;
    • 永久函数格式:create function * as ‘JAVA类名’ using jar ‘HDFS jar包路径 ‘;
  • 6、使用select * (参数);
  • 7、删除
    • 临时函数:关闭hive客户端后自动删除,或者drop temporary function *;
    • 永久函数:需要使用drop function * 进行删除;

8.5.1 新建Eclipse工程

8.5.2 UDF

创建一个打印日志的自定义函数udflog,再输出信息是,输出日志时间。

8.5.2.1 创建工程

启动MyEclipse,点击File->New->JavaProject,创建Java工程

输入工程名:UDFUtil,点击下一步

点击下一步

点击完成

再点击完成

8.5.2.2 导入lib库

右键选中工程,选择New->Folder,新建文件夹

输入文件夹名lib,点击完成

将图中jar包拷贝到新建文件夹lib中

选中jar包,选择Add to Build Path,将lib库里面的Jar包添加进工程

添加完成后

8.5.2.3 创建类文件

右键选中工程,选择New->Source Folder,新建代码文件夹

输入文件夹名src,点击完成

右键选中新建的代码文件夹src,选择New->Class,新建类

输入包名,类名子,选择基类Browse…

输入UDF,选中第一项,点击OK

点击完成

8.5.2.4 编写JAVA代码

在新建类中输入如下代码:com.udf.UDFLog.java

package com.udf;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Calendar;

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

public class UDFLog extends UDF {
	public Text evaluate(Text msg){
		DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
		Calendar calendar = Calendar.getInstance();
		String dateName = df.format(calendar.getTime());

		StringBuilder sb = new StringBuilder();
		sb.append(dateName);
		sb.append(": ");
		sb.append("msg.toString()");
		return new Text(sb.toString());		
	}
}
8.5.2.5 导出JAR包

右键选中程序包,选择Export导出

在导出对话框中,选择Java下的导出JAR file,点击下一步

点击Browser…,选择JAR包导出位置即名称

选择位置,并输入名称

点击完成

8.5.2.6 上传Jar包

将生成的JAR包上传到app-12节点的:/home/hadoop/UDF目录,

创建/home/hadoop/UDF目录:mkdir /home/hadoop/UDF

上传UDFLog.jar文件到/home/hadoop/UDF目录

8.5.2.7 临时函数

在app-12节点,启动hive客户端:hive

添加Jar包:add jar /home/hadoop/UDF/UDFLog.jar;

创建临时函数,函数名为UDFLog(这个名字可以自己命名),后面跟着JAVA的包名和类名

命令:create temporary function UDFLog as 'com.udf.UDFLog';

使用自定义函数:select UDFLog(‘hello!’);

销毁自定义函数:drop temporary function UDFLog;

可以看出,销毁完成后就找不到了。

重新生成临时函数,然后退出命令行后,再登录测试能否使用

重新登录hive,可以看到自定义函数依旧无法使用。

8.5.2.8 永久函数

在HDFS上创建根目录/udf,用来存放Jar包

命令:dfs -mkdir /udf

将/home/Hadoop/UDF/UDFLog.jar上传到/udf目录下

命令:dfs -put /home/hadoop/UDF/UDFLog.jar /udf;

创建永久函数:

hive> create function UDFLog as 'com.udf.UDFLog'
    > using jar 'hdfs://dmcluster/udf/UDFLog.jar';

此处‘hdfs://dmcluster’只的是HDFS路径,这个在/hadoop/Hadoop/hadoop-3.1.2/etc/hadoop hdfs-site.xml里面有配置

查找函数是否创建成功:show functions like ‘*Log*’;

使用该函数:select udflog(‘hello!’);

退出后重新登录,检查是否能用:quit;

重新登录:hive

重新登录后,自定义函数还可以使用

销毁自定义函数:drop function udflog;

8.5.3 GenricUDF

将一个以逗号分隔的字符串,切分成List,并返回:

8.5.3.1 创建工程

参照之前方式创建工程:GenericUDFUtil

8.5.3.2 导入lib库

参照之前方式导入Lib库文件

8.5.3.3 创建类文件

参照之前方式创建类文件com.gudf.GUDFSplit,注意此处类继承自GenericUDF

8.5.3.4 编写JAVA代码

在新建类中输入如下代码:com.udf. GUDFSplit.java

package com.gudf;

import java.util.ArrayList;

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.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;


public class GUDFSplit extends GenericUDF {
	private transient ArrayList<String> ret = new ArrayList<String>();

	@Override
	public Object evaluate(DeferredObject[] arg0) throws HiveException {
		ret.clear();
		if (arg0.length < 1)
			return ret;
		// 获取第一个参数
		String str = arg0[0].get().toString();
		String[] s = str.split(",", -1);
		for (String word : s) {
			ret.add(word);
		}
		return ret;
	}

	@Override
	public String getDisplayString(String[] arg0) {
		return "Usage: getDisplayString(String str)";
	}

	@Override
	public ObjectInspector initialize(ObjectInspector[] arg0)throws UDFArgumentException {
		// 定义函数的返回类型为java的List
		ObjectInspector returnOI = PrimitiveObjectInspectorFactory.getPrimitiveJavaObjectInspector(PrimitiveObjectInspector.PrimitiveCategory.STRING);
		return ObjectInspectorFactory.getStandardListObjectInspector(returnOI);
	}
}

GenericUDF 继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF之后,需要重写几个重要的方法:

public void configure(MapredContext context) {}

可选,该方法中可以通过context.getJobConf()获取job执行时候的Configuration;可以通过Configuration传递参数值。

public ObjectInspector initialize(ObjectInspector[] arguments)

必选,该方法用于函数初始化操作,并定义函数的返回值类型;比如,在该方法中可以初始化对象实例,初始化数据库链接,初始化读取文件等;

public Object evaluate(DeferredObject[] args){}

必选,函数处理的核心方法,用途和UDF中的evaluate一样;

public String getDisplayString(String[] children)

必选,显示函数的帮助信息

public void close(){}

可选,map完成后,执行关闭操作

8.5.3.5 导出JAR包

参照之前方式导出Jar包GUDFSplit.jar

8.5.3.6 上传Jar包

将生成的JAR包上传到app-12节点的:/home/hadoop/GUDF目录,

创建/home/hadoop/GUDF目录:mkdir /home/hadoop/GUDF

上传UDFLog.jar文件到/home/hadoop/GUDF目录

8.5.3.7 临时函数

在app-12节点,启动hive客户端:hive

添加Jar包:

命令:add jar /home/hadoop/GUDF/GUDFSplit.jar;

创建临时函数,函数名为UDFLog(这个名字可以自己命名),后面跟着JAVA的包名和类名

命令:create temporary function GUDFSplit as 'com.gudf.GUDFSplit';

使用自定义函数:select GUDFSplit(‘hello,world!’);

销毁自定义函数:drop temporary function GUDFSplit;

可以看出,销毁完成后就找不到了。

重新生成临时函数,然后退出命令行后,再登录测试能否使用

重新登录hive,可以看到自定义函数依旧无法使用。

8.5.3.8 永久函数

将/home/hadoop/GUDF/GUDFSplit.jar上传到/udf目录下

命令:dfs -put /home/hadoop/GUDF/GUDFSplit.jar /udf;

创建永久函数:

hive> create function GUDFSplit as 'com.gudf.GUDFSplit'
    > using jar 'hdfs://dmcluster/udf/GUDFSplit.jar'
    > ;

此处‘hdfs://dmcluster’只的是HDFS路径,这个在/hadoop/Hadoop/hadoop-3.1.2/etc/hadoop hdfs-site.xml里面有配置

查找函数是否创建成功:show functions like ‘*Split*’;

使用该函数:select GUDFSplit(‘hello,world!’);

退出后重新登录,检查是否能用:quit;

重新登录:hive

重新登录后,自定义函数还可以使用

销毁自定义函数:drop function gudfsplit;

发表回复