hive学习之函数

  • Post author:
  • Post category:其他




hive学习之函数



系统内置函数


查看系统自带的函数

show functions;


查看内置函数的用法

desc function 函数名;
desc function extended 函数名;




常用日期函数

1. unix_timestamp:返回当前或指定时间的时间戳	
select unix_timestamp();
select unix_timestamp("2020-10-28",'yyyy-MM-dd');

2. from_unixtime:将时间戳转为日期格式
select from_unixtime(1603843200);

3. current_date:当前日期
select current_date;

4. current_timestamp:当前的日期加时间
select current_timestamp;

5. to_date:抽取日期部分
select to_date('2020-10-28 12:12:12');

6. year:获取年
select year('2020-10-28 12:12:12');

7. month:获取月
select month('2020-10-28 12:12:12');

8. day:获取日
select day('2020-10-28 12:12:12');

9. hour:获取时
select hour('2020-10-28 12:13:14');

10. minute:获取分
select minute('2020-10-28 12:13:14');

11. second:获取秒
select second('2020-10-28 12:13:14');

12. weekofyear:当前时间是一年中的第几周
select weekofyear('2020-10-28 12:12:12');

13. dayofmonth:当前时间是一个月中的第几天
select dayofmonth('2020-10-28 12:12:12');

14. months_between: 两个日期间的月份
select months_between('2020-04-01','2020-10-28');

15. add_months:日期加减月
select add_months('2020-10-28',-3);

16. datediff:两个日期相差的天数
select datediff('2020-11-04','2020-10-28');

17. date_add:日期加天数
select date_add('2020-10-28',4);

18. date_sub:日期减天数
select date_sub('2020-10-28',-4);

19. last_day:日期的当月的最后一天
select last_day('2020-02-30');

20. date_format(): 格式化日期
select date_format('2020-10-28 12:12:12','yyyy/MM/dd HH:mm:ss');




常用取整函数

21. round: 四舍五入
select round(3.14);
select round(3.54);

22. ceil:  向上取整
select ceil(3.14);
select ceil(3.54);

floor: 向下取整
23. select floor(3.14);
select floor(3.54);




常用字符串函数

24. upper: 转大写
select upper('low');

25. lower: 转小写
select lower('low');

26. length: 长度
select length("atguigu");

27. trim:  前后去空格
select trim(" atguigu ");

28. lpad: 向左补齐,到指定长度
select lpad('atguigu',9,'g');

29. rpad:  向右补齐,到指定长度
select rpad('atguigu',9,'g');

30. regexp_replace:使用正则表达式匹配目标字符串,匹配成功后替换!
SELECT regexp_replace('2020/10/25', '/', '-');




操作集合类函数

31. size: 集合中元素的个数
select size(friends) from test3;

32. map_keys: 返回map中的key
select map_keys(children) from test3;

33. map_values: 返回map中的value
select map_values(children) from test3;

34. array_contains: 判断array中是否包含某个元素
select array_contains(friends,'bingbing') from test3;

35. sort_array: 将array中的元素排序
select sort_array(friends) from test3;



多维分析

从多个维度进行统计分析

在这里插入图片描述

# grouping sets
select deptno,sex,count(id) from testgrouping group by deptno,sex,grouping sets( (deptno,sex),sex,deptno )

在这里插入图片描述



常用内置函数




空字段赋值

NVL:给值为NULL的数据赋值,它的格式是NVL( value,default_value)。它的功能是如果value为NULL,则NVL函数返回default_value的值,否则返回value的值,如果两个参数都为NULL ,则返回NULL。其实和oracle中的一样,mysql中的IFNULL

select age,nvl(name,"-") from student;



CASE WHEN

类似mysql中的case when then else end


数据准备

[atguigu@hadoop102 datas]$ vi emp_sex.txt
悟空	A	男
大海	A	男
宋宋	B	男
凤姐	A	女
婷姐	B	女


建表语句

# 创建表
create table emp_sex(
name string, 
dept_id string, 
sex string) 
row format delimited fields terminated by "\t";

# 加载数据
load data local inpath '/opt/module/hive/datas/emp_sex.txt' into table emp_sex;


查询数据

# 统计每个部门中男女的人数
select 
  dept_id,
  sum(case sex when '男' then 1 else 0 end) man,
  sum(case sex when '女' then 1 else 0 end) female
from 
  emp_sex
group by
  dept_id;

在这里插入图片描述

如果只有两个分支的话,不必使用case…when函数,可以直接使用if函数

select 
  dept_id,
  sum(if(sex='男',1,0)) man,
  sum(if(sex='女',1,0)) female
from 
  emp_sex
group by
  dept_id;



行转列


1.相关函数

concat

select concat(empno,'_',ename) from emp;

concat_ws

# 注意:只支持字符串或者字符串数组的拼接
select concat_ws('_',cast(empno as string),ename) from emp;

collect_set

该函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型字段。
# 去重汇总
select collect_set(ename) from emp;

在这里插入图片描述

collect_list

# 不去重,只汇总
select collect_list(job) from emp;

在这里插入图片描述



列转行


相关函数

EXPLODE:

将hive一列中复杂的array或者map结构拆分成多行,用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合。

在这里插入图片描述

LATERAL VIEW

侧写表(虚拟表),把原有的一列跟已经查分开的列作对应关系,适合一对多的场景下。


数据准备

+-------------------+----------------------+
| movie_info.movie  | movie_info.category  |
+-------------------+----------------------+
| 《疑犯追踪》            | 悬疑,动作,科幻,剧情          
| 《Lie to me》          | 悬疑,警匪,动作,心理,剧情       
| 《战狼2》              | 战争,动作,灾难             
+-------------------+----------------------+


期望结果

《疑犯追踪》      悬疑
《疑犯追踪》      动作
《疑犯追踪》      科幻
《疑犯追踪》      剧情
《Lie to me》   悬疑
《Lie to me》   警匪
《Lie to me》   动作
《Lie to me》   心理
《Lie to me》   剧情
《战狼2》        战争
《战狼2》        动作
《战狼2》        灾难


执行

select movie,category_name from movie_info
LATERAL view explode(split(category,',')) movie_info_emp as category_name;


# 结果
+--------------+----------------+
|    movie     | category_name  |
+--------------+----------------+
| 《疑犯追踪》       | 悬疑             |
| 《疑犯追踪》       | 动作             |
| 《疑犯追踪》       | 科幻             |
| 《疑犯追踪》       | 剧情             |
| 《Lie to me》  | 悬疑             |
| 《Lie to me》  | 警匪             |
| 《Lie to me》  | 动作             |
| 《Lie to me》  | 心理             |
| 《Lie to me》  | 剧情             |
| 《战狼2| 战争             |
| 《战狼2| 动作             |
| 《战狼2| 灾难             |
+--------------+----------------+
12 rows selected (1.211 seconds)
0: jdbc:hive2://hadoop102:10000> 



窗口函数

over()

指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的改变而变化。


参数解释

CURRENT ROW:当前行
n PRECEDING:往前n行数据 (注意:是一个范围)
n FOLLOWING:往后n行数据
UNBOUNDED:起点,
UNBOUNDED PRECEDING 表示从前面的起点, 
UNBOUNDED FOLLOWING表示到后面的终点
LAG(col,n,default_val):往前第n行数据 (注意:是一个条数据)
LEAD(col,n, default_val):往后第n行数据
NTILE(n):把有序窗口的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。注意:n必须为int类型。


数据准备:name,orderdate,cost

jack,2017-01-01,10
tony,2017-01-02,15
jack,2017-02-03,23
tony,2017-01-04,29
jack,2017-01-05,46
jack,2017-04-06,42
tony,2017-01-07,50
jack,2017-01-08,55
mart,2017-04-08,62
mart,2017-04-09,68
neil,2017-05-10,12
mart,2017-04-11,75
neil,2017-06-12,80
mart,2017-04-13,94


建表

create table business(
name string, 
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
load data local inpath "/opt/module/hive/datas/business.txt" into table business;


需求

+----------------+---------------------+----------------+
| business.name  | business.orderdate  | business.cost  |
+----------------+---------------------+----------------+
| jack           | 2017-01-01          | 10             |
| tony           | 2017-01-02          | 15             |
| jack           | 2017-02-03          | 23             |
| tony           | 2017-01-04          | 29             |
| jack           | 2017-01-05          | 46             |
| jack           | 2017-04-06          | 42             |
| tony           | 2017-01-07          | 50             |
| jack           | 2017-01-08          | 55             |
| mart           | 2017-04-08          | 62             |
| mart           | 2017-04-09          | 68             |
| neil           | 2017-05-10          | 12             |
| mart           | 2017-04-11          | 75             |
| neil           | 2017-06-12          | 80             |
| mart           | 2017-04-13          | 94             |
+----------------+---------------------+----------------+


(1)查询在2017年4月份购买过的顾客及总人数

-- 方式一:
select t1.name,count(t1.name) over()
from (select name,orderdate,cost from business 
      where substring(orderdate,0,7) = '2017-04') t1
group by t1.name; 

-- 方式二:
select 
   t2.name, count(t2.name) over()
from 
(select
  distinct(t1.name)
from 
  (select
  name, orderdate, cost 
from 
  business 
where substring(orderdate,0,7) = '2017-04')t1) t2

-- 结果集
+----------+-----------------+
| t1.name  | count_window_0  |
+----------+-----------------+
| mart     | 2               |
| jack     | 2               |
+----------+-----------------+


(2)查询顾客的购买明细及所有顾客的月购买总额

select 
  name,
  orderdate,
  cost,
  sum(cost) over(partition by substring(orderdate,0,7)) month_cost
from 
  business;
  
# 结果集
+-------+-------------+-------+-------------+
| name  |  orderdate  | cost  | month_cost  |
+-------+-------------+-------+-------------+
| jack  | 2017-01-01  | 10    | 205         |
| jack  | 2017-01-08  | 55    | 205         |
| tony  | 2017-01-07  | 50    | 205         |
| jack  | 2017-01-05  | 46    | 205         |
| tony  | 2017-01-04  | 29    | 205         |
| tony  | 2017-01-02  | 15    | 205         |
| jack  | 2017-02-03  | 23    | 23          |
| mart  | 2017-04-13  | 94    | 341         |
| jack  | 2017-04-06  | 42    | 341         |
| mart  | 2017-04-11  | 75    | 341         |
| mart  | 2017-04-09  | 68    | 341         |
| mart  | 2017-04-08  | 62    | 341         |
| neil  | 2017-05-10  | 12    | 12          |
| neil  | 2017-06-12  | 80    | 80          |
+-------+-------------+-------+-------------+


# 扩展需求
查询顾客的购买明细及各个顾客的月购买总额
select 
  name,
  orderdate,
  cost,
  sum(cost) over(partition by name,substring(orderdate,0,7)) name_month_cost
from 
  business;
  

## 结果集
+-------+-------------+-------+-------------+
| name  |  orderdate  | cost  | name_month_cost  |
+-------+-------------+-------+-------------+
| jack  | 2017-01-05  | 46    | 111         |
| jack  | 2017-01-08  | 55    | 111         |
| jack  | 2017-01-01  | 10    | 111         |
| jack  | 2017-02-03  | 23    | 23          |
| jack  | 2017-04-06  | 42    | 42          |
| mart  | 2017-04-13  | 94    | 299         |
| mart  | 2017-04-11  | 75    | 299         |
| mart  | 2017-04-09  | 68    | 299         |
| mart  | 2017-04-08  | 62    | 299         |
| neil  | 2017-05-10  | 12    | 12          |
| neil  | 2017-06-12  | 80    | 80          |
| tony  | 2017-01-04  | 29    | 94          |
| tony  | 2017-01-02  | 15    | 94          |
| tony  | 2017-01-07  | 50    | 94          |
+-------+-------------+-------+-------------+

# 小总结:
over():
会为每条数据都开启一个窗口,默认的窗口大小就是当前数据集的大小。
over(partition by...):
会按照指定的字段进行分区,将分区字段的值相同的数据划分到相同的分区。每个区中的没条数据都会开启一个窗口,每条数据的窗口大小默认为当前分区数据集的大小


(3)将每个顾客的cost按照日期进行累加

-- 方式一:
select 
  name,
  orderdate,
  cost,
  sum(cost) over(partition by name order by orderdate rows between UNBOUNDED PRECEDING         and CURRENT ROW) leijia
from 
  business;
  
-- 方式二:
select 
  name,
  orderdate,
  cost,
  sum(cost) over(partition by name order by orderdate) leijia
from 
  business;

# 结果集
+-------+-------------+-------+---------+
| name  |  orderdate  | cost  | leijia  |
+-------+-------------+-------+---------+
| jack  | 2017-01-01  | 10    | 10      |
| jack  | 2017-01-05  | 46    | 56      |
| jack  | 2017-01-08  | 55    | 111     |
| jack  | 2017-02-03  | 23    | 134     |
| jack  | 2017-04-06  | 42    | 176     |
| mart  | 2017-04-08  | 62    | 62      |
| mart  | 2017-04-09  | 68    | 130     |
| mart  | 2017-04-11  | 75    | 205     |
| mart  | 2017-04-13  | 94    | 299     |
| neil  | 2017-05-10  | 12    | 12      |
| neil  | 2017-06-12  | 80    | 92      |
| tony  | 2017-01-02  | 15    | 15      |
| tony  | 2017-01-04  | 29    | 44      |
| tony  | 2017-01-07  | 50    | 94      |
+-------+-------------+-------+---------+


# 扩展
将所有顾客的cost按照日期进行累加
select 
  name,
  orderdate,
  cost,
  sum(cost) over(order by orderdate) leijia
from 
  business;

# 结果集
+-------+-------------+-------+---------+
| name  |  orderdate  | cost  | leijia  |
+-------+-------------+-------+---------+
| jack  | 2017-01-01  | 10    | 10      |
| tony  | 2017-01-02  | 15    | 25      |
| tony  | 2017-01-04  | 29    | 54      |
| jack  | 2017-01-05  | 46    | 100     |
| tony  | 2017-01-07  | 50    | 150     |
| jack  | 2017-01-08  | 55    | 205     |
| jack  | 2017-02-03  | 23    | 228     |
| jack  | 2017-04-06  | 42    | 270     |
| mart  | 2017-04-08  | 62    | 332     |
| mart  | 2017-04-09  | 68    | 400     |
| mart  | 2017-04-11  | 75    | 475     |
| mart  | 2017-04-13  | 94    | 569     |
| neil  | 2017-05-10  | 12    | 581     |
| neil  | 2017-06-12  | 80    | 661     |
+-------+-------------+-------+---------+

  
# 小总结:
over(order by ...):
会在窗口中按照指定的字段对数据进行排序,会为每条数据都开启一个窗口,默认的窗口大小为从数据集开始到当前行。
over(partition by...order by...):
会按照指定的字段进行分区。将分区字段的值相同的数据划分到同一个区,在每个区中会按照指定的字段进行排序,会为每条数据都开启一个窗口,默认的窗口大小为当前分区中从数据集开始到当前行。
over(partition by...order by...rows between ...and...):
指定每条数据的窗口大小,强调数据范围 between and


扩展需求

求所有顾客的购买明细及按照日期进行排序后
求 所有顾客的cost  第一行 到 当前行 累加
所有顾客的cost 上一行 到 当前行 的累加和 
所有顾客的cost 上一行 到 下一行 的累加和
所有顾客的cost 当前行 到 下一行 的累加和
所有顾客的cost 当前行 到 最后一行的累加和

select
  name,
  orderdate,
  cost,
  sum(cost) over(order by orderdate) f_c, -- order by默认开口范围是第一行到当前行
  sum(cost) over(order by orderdate rows between 1 PRECEDING and CURRENT ROW) p_c,
  sum(cost) over(order by orderdate rows between 1 PRECEDING and 1 FOLLOWING) p_n,
  sum(cost) over(order by orderdate rows between CURRENT ROW and 1 FOLLOWING) c_n,
  sum(cost) over(order by orderdate rows between CURRENT ROW and UNBOUNDED FOLLOWING) c_l
from 
  business;
  
# 结果集
+-------+-------------+-------+------+------+------+------+------+
| name  |  orderdate  | cost  | f_c  | p_c  | p_n  | c_n  | c_l  |
+-------+-------------+-------+------+------+------+------+------+
| jack  | 2017-01-01  | 10    | 10   | 10   | 25   | 25   | 661  |
| tony  | 2017-01-02  | 15    | 25   | 25   | 54   | 44   | 651  |
| tony  | 2017-01-04  | 29    | 54   | 44   | 90   | 75   | 636  |
| jack  | 2017-01-05  | 46    | 100  | 75   | 125  | 96   | 607  |
| tony  | 2017-01-07  | 50    | 150  | 96   | 151  | 105  | 561  |
| jack  | 2017-01-08  | 55    | 205  | 105  | 128  | 78   | 511  |
| jack  | 2017-02-03  | 23    | 228  | 78   | 120  | 65   | 456  |
| jack  | 2017-04-06  | 42    | 270  | 65   | 127  | 104  | 433  |
| mart  | 2017-04-08  | 62    | 332  | 104  | 172  | 130  | 391  |
| mart  | 2017-04-09  | 68    | 400  | 130  | 205  | 143  | 329  |
| mart  | 2017-04-11  | 75    | 475  | 143  | 237  | 169  | 261  |
| mart  | 2017-04-13  | 94    | 569  | 169  | 181  | 106  | 186  |
| neil  | 2017-05-10  | 12    | 581  | 106  | 186  | 92   | 92   |
| neil  | 2017-06-12  | 80    | 661  | 92   | 92   | 80   | 80   |
+-------+-------------+-------+------+------+------+------+------+


(4)查询每个顾客上次的购买时间以及下一次的购买时间

select 
  name,
  cost,
  orderdate c_orderdate,
  lag(orderdate,1,'1970-01-01') over(partition by name order by orderdate) p_orderdate,
  lead(orderdate,1,'2099-01-01') over(partition by name order by orderdate) n_orderdate
from 
  business;
  
# 结果集
+-------+-------+--------------+--------------+--------------+
| name  | cost  | c_orderdate  | p_orderdate  | n_orderdate  |
+-------+-------+--------------+--------------+--------------+
| jack  | 10    | 2017-01-01   | 1970-01-01   | 2017-01-05   |
| jack  | 46    | 2017-01-05   | 2017-01-01   | 2017-01-08   |
| jack  | 55    | 2017-01-08   | 2017-01-05   | 2017-02-03   |
| jack  | 23    | 2017-02-03   | 2017-01-08   | 2017-04-06   |
| jack  | 42    | 2017-04-06   | 2017-02-03   | 2099-01-01   |
| mart  | 62    | 2017-04-08   | 1970-01-01   | 2017-04-09   |
| mart  | 68    | 2017-04-09   | 2017-04-08   | 2017-04-11   |
| mart  | 75    | 2017-04-11   | 2017-04-09   | 2017-04-13   |
| mart  | 94    | 2017-04-13   | 2017-04-11   | 2099-01-01   |
| neil  | 12    | 2017-05-10   | 1970-01-01   | 2017-06-12   |
| neil  | 80    | 2017-06-12   | 2017-05-10   | 2099-01-01   |
| tony  | 15    | 2017-01-02   | 1970-01-01   | 2017-01-04   |
| tony  | 29    | 2017-01-04   | 2017-01-02   | 2017-01-07   |
| tony  | 50    | 2017-01-07   | 2017-01-04   | 2099-01-01   |
+-------+-------+--------------+--------------+--------------+


(5)查询前20%时间的订单信息

select 
  t1.name,
  t1.orderdate,
  t1.cost,
  t1.gid
from
 (
  select name,orderdate,cost,ntile(5) over (order by orderdate) gid
  from business
 ) t1
where t1.gid=1;

# 结果集
+----------+---------------+----------+---------+
| t1.name  | t1.orderdate  | t1.cost  | t1.gid  |
+----------+---------------+----------+---------+
| jack     | 2017-01-01    | 10       | 1       |
| tony     | 2017-01-02    | 15       | 1       |
| tony     | 2017-01-04    | 29       | 1       |
+----------+---------------+----------+---------+


关键字总结

- order by			全局排序或者窗口函数中排序
- distribute by		分区
- sort by			区内排序
- cluster by		分区排序
- partition by		窗口函数中分区
- partitioned by	建表指定分区字段
- clustered by		建表指定分桶字段



Rank

RANK() 排序相同时会重复,总数不变

DENSE_RANK 排序相同时会重复,总数会减少

ROW_NUMBER 会根据顺序计算


数据准备 score.txt

name subject score
孙悟空 语文 87
孙悟空 数学 95
孙悟空 英语 68
大海 语文 94
大海 数学 56
大海 英语 84
宋宋 语文 64
宋宋 数学 86
宋宋 英语 84
婷婷 语文 65
婷婷 数学 85
婷婷 英语 78
create table score(
name string,
subject string, 
score int) 
row format delimited fields terminated by "\t";

load data local inpath '/opt/module/hive/datas/score.txt' into table score;
# sql,求每个学科的学生成绩排名
select 
    name,
    subject,
    score,
    rank() over(partition by subject order by score desc) rp,
    dense_rank() over(partition by subject order by score desc) drp,
    row_number() over(partition by subject order by score desc) rmp
from score;

# 结果集
name  subject score   rp      drp     rmp
孙悟空  数学    95      1       1       1
宋宋    数学    86      2       2       2
婷婷    数学    85      3       3       3
大海    数学    56      4       4       4
宋宋    英语    84      1       1       1
大海    英语    84      1       1       2
婷婷    英语    78      3       2       3
孙悟空  英语    68      4       3       4
大海    语文    94      1       1       1
孙悟空  语文    87      2       2       2
婷婷    语文    65      3       3       3
宋宋    语文    64      4       4       4



自定义函数

当系统自带的函数已经满足不了我们的业务需求,会考虑自定义函数


根据用户自定函数类别可以分为三种

  • UDF(user-defined-function) 一斤多出
  • UDAF(user-defined-aggregation-function) 聚集函数,多进一出
  • UDTF(user-defined-generating function) 一进多出


官方文档地址

https://cwiki.apache.org/confluence/display/Hive/HivePlugins


编程步骤

(1)继承Hive提供的类	
    org.apache.hadoop.hive.ql.udf.generic.GenericUDF  
    org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
(2)实现类中的抽象方法
(3)在hive的命令行窗口创建函数
添加jar
    add jar XXX/XXX.jar
创建function
	create [temporary] function [dbname.]function_name AS 类路径;
(4)在hive的命令行窗口删除函数
	drop [temporary] function [if exists] [dbname.]function_name;



自定义UDF函数

这边主要是学一下自定义函数的格式。

需求:实现一个求字符串长度的函数


1.创建一个maven工程,并导入依赖

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

**2.创建类,继承GenericUDF **

package com.pihao.hive;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
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.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

/**
 * 自定义UDF函数,需要继承GenericUDF类
 * 需求: 计算指定字符串的长度
 */
public class MyStringLength extends GenericUDF {
    /**
     *
     * @param arguments 输入参数类型的鉴别器对象
     * @return 返回值类型的鉴别器对象
     * @throws UDFArgumentException
     */
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        // 判断输入参数的个数
        if(arguments.length !=1){
            throw new UDFArgumentLengthException("Input Args Length Error!!!");
        }
        // 判断输入参数的类型
        if(!arguments[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)){
            throw new UDFArgumentTypeException(0,"Input Args Type Error!!!");
        }
        //函数本身返回值为int,需要返回int类型的鉴别器对象
        return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
    }

    /**
     * 函数的逻辑处理
     * @param arguments 输入的参数
     * @return 返回值
     * @throws HiveException
     */
    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
       if(arguments[0].get() == null){
           return 0 ;
       }
       return arguments[0].get().toString().length();
    }

    @Override
    public String getDisplayString(String[] children) {
        return "";
    }
}


3.mvn package打包成test_length.jar

打包后并上传到服务器/opt/module/hive/datas/test_length.jar,

一般放到hive的lib目录下,这里是临时测试的


4.将jar添加到hive的classpath

hive (default)> add jar /opt/module/hive/datas/test_length.jar


5.创建临时函数关联jar包

# 如果不是临时不用加 temporary
hive (default)> create temporary function my_len as "com.pihao.hive.MyStringLength";


6.在sql中使用自定义的函数

hive (default)> select ename,my_len(ename) ename_len from emp;



自定义UDTF函数

需求:自定义一个UDTF实现将一个任意分割符的字符串切割成独立的单词


核心代码

package com.pihao.udtf;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

import java.util.ArrayList;
import java.util.List;

public class MyUDTF extends GenericUDTF {

    private ArrayList<String> outList = new ArrayList<>();

    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {


        //1.定义输出数据的列名和类型
        List<String> fieldNames = new ArrayList<>();
        List<ObjectInspector> fieldOIs = new ArrayList<>();

        //2.添加输出数据的列名和类型
        fieldNames.add("lineToWord");
        fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
    }

    @Override
    public void process(Object[] args) throws HiveException {
        
        //1.获取原始数据
        String arg = args[0].toString();

        //2.获取数据传入的第二个参数,此处为分隔符
        String splitKey = args[1].toString();

        //3.将原始数据按照传入的分隔符进行切分
        String[] fields = arg.split(splitKey);

        //4.遍历切分后的结果,并写出
        for (String field : fields) {

            //集合为复用的,首先清空集合
            outList.clear();

            //将每一个单词添加至集合
            outList.add(field);

            //将集合内容写出
            forward(outList);
        }
    }

    @Override
    public void close() throws HiveException {

    }
}
2)打成jar包上传到服务器/opt/module/hive/data/myudtf.jar
3)将jar包添加到hive的classpath下
hive (default)> add jar /opt/module/hive/data/myudtf.jar;
4)创建临时函数与开发好的java class关联
hive (default)> create temporary function myudtf as "com.pihao.hive.MyUDTF";
5)使用自定义的函数
hive (default)> select myudtf("hello,world,hadoop,hive",",") ;



版权声明:本文为weixin_44178366原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。