文章目录
1. 系统内置函数
-
查看系统自带的函数
hive> show functions;
-
显示自带的函数的用法
hive> desc function upper;
-
详细显示自带的函数的用法
hive> desc function extended upper;
2. 常用函数
2.1 指标函数
-
求总行数(count)
hive (default)> select count(*) cnt from emp;
-
求工资的最大值(max)
hive (default)> select max(sal) max_sal from emp;
-
求工资的最小值(min)
hive (default)> select min(sal) min_sal from emp;
-
求工资的总和(sum)
hive (default)> select sum(sal) sum_sal from emp;
-
求工资的平均值(avg)
hive (default)> select avg(sal) avg_sal from emp;
2.2 collect_set 函数
函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型字段。
把同一分组的不同行的数据聚合成一个集合
hive (default)> select collect_set(ename),avg(sal) avg_sal from emp group by deptno;
2.3 日期处理函数
-
date_format
函数(根据格式整理日期)hive (default)> select date_format('2020-12-19','yyyy-MM'); 2020-12
-
date_add
函数(加减日期)hive (default)> select date_add('2019-12-19',-1); 2020-12-18 hive (default)> select date_add('2019-12-19',1); 2020-12-20
-
next_day
函数-
取当前天的下一个周一
hive (default)> select next_day('2020-12-19','MO'); 2020-12-21
说明:星期一到星期日的英文(Monday,Tuesday、Wednesday、Thursday、Friday、Saturday、Sunday)
-
取当前周的周一
hive (default)> select date_add(next_day('2020-12-19','MO'),-7); 2020-12-14
-
-
last_day
函数(求当月最后一天日期)hive (default)> select last_day('2020-12-19'); 2020-12-31
2.4 字符串连接函数
-
concat 函数
返回输入字符串连接后的结果,支持任意个输入字符串;
hive (default)> select concat ('2020-12-19','_','2020-12-20'); 2020-12-19_2020-12-20
-
concat_ws 函数
它是一个特殊形式的 CONCAT()。第一个参数剩余参数间的分隔符。分隔符可以是与剩余参数一样的字符串。如果分隔符是 NULL,返回值也将为 NULL。这个函数会跳过分隔符参数后的任何 NULL 和空字符串。分隔符将被加到被连接的字符串之间;
hive (default)> select concat_ws ('_','2020-12-19','2020-12-20'); 2020-12-19_2020-12-20
2.5 json 解析函数
hive (default)> select get_json_object(json,'$.mid') mid_id from table_name;
3. 其他常用查询函数
3.1 空字段赋值
-
函数说明
NVL
:给值为 NULL 的数据赋值,它的格式是NVL( string1, replace_with)
。它的功能是如果string1为NULL,则NVL函数返回replace_with的值,否则返回string1的值,如果两个参数都为NULL ,则返回NULL。 -
数据准备:采用员工表
-
查询:如果员工的 comm 为 NULL,则用 -1代替
hive (default)> select nvl(comm,-1) from emp; OK _c0 -1.0 300.0 500.0 -1.0 1400.0 -1.0 -1.0 -1.0 -1.0 0.0 -1.0 -1.0 -1.0 -1.0 Time taken: 0.11 seconds, Fetched: 14 row(s)
-
查询:如果员工的comm为NULL,则用领导id代替
hive (default)> select nvl(comm,mgr) from emp; OK _c0 7902.0 300.0 500.0 7839.0 1400.0 7839.0 7839.0 7566.0 NULL 0.0 7788.0 7698.0 7566.0 7782.0 Time taken: 0.115 seconds, Fetched: 14 row(s)
3.2 CASE WHEN
-
数据准备
悟空 A 男 大海 A 男 宋宋 B 男 凤姐 A 女 婷姐 B 女 婷婷 B 女
-
需求
求出不同部门男女各多少人。结果如下:
A 2 1 B 1 2
-
创建hive表并导入数据
create table emp_sex( name string, dept_id string, sex string ) row format delimited fields terminated by "\t"; load data local inpath '/opt/module/datas/emp_sex.txt' into table emp_sex;
-
按需求查询数据
select dept_id, sum(case sex when '男' then 1 else 0 end) male_count, sum(case sex when '女' then 1 else 0 end) female_count from emp_sex group by dept_id;
3.3 行转列
-
相关函数说明
CONCAT(string A/col, string B/col…)
:返回输入字符串连接后的结果,支持任意个输入字符串;CONCAT_WS(separator, str1, str2,...)
:它是一个特殊形式的 CONCAT()。第一个参数是分隔符。分隔符可以是与剩余参数一样的字符串。如果分隔符是 NULL,返回值也将为 NULL。这个函数会跳过分隔符参数后的任何 NULL 和空字符串。分隔符将被加到被连接的字符串之间;COLLECT_SET(col)
:函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型字段。 -
数据准备
表 数据准备
name | constellation | blood_type |
---|---|---|
孙悟空 | 白羊座 | A |
沙僧 | 射手座 | A |
唐僧 | 白羊座 | B |
猪八戒 | 白羊座 | A |
白龙马 | 射手座 | A |
-
需求
把星座和血型一样的人归类到一起。结果如下:
射手座,A 沙僧|白龙马 白羊座,A 孙悟空|猪八戒 白羊座,B 唐僧
-
创建本地
constellation.txt
,导入数据[dwjf321@hadoop102 ~]$ vim /opt/module/datas/constellation.txt 孙悟空 白羊座 A 沙僧 射手座 A 唐僧 白羊座 B 猪八戒 白羊座 A 白龙马 射手座 A
-
创建hive表并导入数据
create table person_info( name string, constellation string, blood_type string) row format delimited fields terminated by "\t"; load data local inpath '/opt/module/datas/constellation.txt' into table person_info;
-
按需求查询结果
select t.base, concat_ws('|', collect_set(t.name)) name from ( select concat(constellation, ',', blood_type) base, name from person_info ) t group by t.base
3.4 列转行
-
函数说明
EXPLODE(col):将hive一列中复杂的array或者map结构拆分成多行。
LATERAL VIEW
用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias
解释:用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合。
-
数据准备
表 数据准备
movie | category |
---|---|
《疑犯追踪》 | 悬疑,动作,科幻,剧情 |
《Lie to me》 | 悬疑,警匪,动作,心理,剧情 |
《战狼2》 | 战争,动作,灾难 |
-
需求
将电影分类中的数组数据展开。结果如下:
《疑犯追踪》 悬疑 《疑犯追踪》 动作 《疑犯追踪》 科幻 《疑犯追踪》 剧情 《Lie to me》 悬疑 《Lie to me》 警匪 《Lie to me》 动作 《Lie to me》 心理 《Lie to me》 剧情 《战狼2》 战争 《战狼2》 动作 《战狼2》 灾难
-
创建本地
movie.txt
,导入数据[dwjf321@hadoop102 ~]$ vim /opt/module/datas/movie.txt 《疑犯追踪》 悬疑,动作,科幻,剧情 《Lie to me》 悬疑,警匪,动作,心理,剧情 《战狼2》 战争,动作,灾难
-
创建 hive 表并导入数据
create table movie_info( movie string, category array<string>) row format delimited fields terminated by "\t" collection items terminated by ","; load data local inpath '/opt/module/datas/movie.txt' into table movie_info;
-
按需求查询数据
select movie, category_name from movie_info lateral view explode(category) temp_col as category_name;
3.5 窗口函数
-
相关函数说明
OVER()
:指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化CURRENT ROW
:当前行n PRECEDING
:往前n行数据n FOLLOWING
:往后n行数据UNBOUNDED
:起点UNBOUNDED PRECEDING
: 表示从前面的起点UNBOUNDED FOLLOWING
:表示到后面的终点LAG(col,n)
:往前第n行数据LEAD(col,n)
:往后第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
-
需求
(1)查询在2017年4月份购买过的顾客及总人数
(2)查询顾客的购买明细及月购买总额
(3)上述的场景,要将cost按照日期进行累加
(4)查询顾客上次的购买时间
(5)查询前20%时间的订单信息
-
创建本地business.txt,导入数据
[dwjf321@hadoop102 ~]$ vim /opt/module/datas/business.txt 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
-
创建hive表并导入数据
create table business( name string, orderdate string, cost int ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ','; load data local inpath '/opt/module/datas/business.txt' into table business;
-
按需求查询数据
-
需求一:查询在 2017 年 4 月份购买过的顾客及总人数
select name, count(*) over() from business where substring(orderdate, 0, 7)= '2017-04' group by name;
查询结果:
jack 2 mart 2
购买过的顾客有:jack 和 mart,总人数是:2。
-
需求二:查询顾客的购买明细及月购买总额
select name, orderdate, cost, sum(cost) over(partition by month(orderdate)) from business;
查询结果:
jack 2017-01-01 10 205 tony 2017-01-02 15 205 tony 2017-01-04 29 205 jack 2017-01-05 46 205 tony 2017-01-07 50 205 jack 2017-01-08 55 205 jack 2017-02-03 23 23 mart 2017-04-13 94 341 mart 2017-04-08 62 341 mart 2017-04-09 68 341 mart 2017-04-11 75 341 jack 2017-04-06 42 341 neil 2017-05-10 12 12 neil 2017-06-12 80 80
-
需求三:上述的场景,要将cost按照日期进行累加
select name, orderdate, cost, sum(cost) over() sample1,--所有行相加 sum(cost) over(partition by name) sample2,--按 name 分组,组内数据相加 sum(cost) over(partition by name order by orderdate) sample3,--按 name 分组,组内数据累加 sum(cost) over(partition by name order by orderdate rows between unbounded preceding and current row) sample4,--结果与 sample3一样,由起始行到当前行累加 sum(cost) over(partition by name order by orderdate rows between 1 preceding and current row) sample5,--当前行和前面一行做聚合 sum(cost) over(partition by name order by orderdate rows between 1 preceding and 1 following) sample6,--前一行、当前行、后一行做聚合 sum(cost) over(partition by name order by orderdate rows between 1 preceding and unbounded following) sample7 --前一行到最后一行聚合 from business;
-
需求四:查看顾客上次的购买时间
select name, orderdate, cost, lag(orderdate, 1, '1900-01-01') over(partition by name order by orderdate) time1--求上次购买时间,默认值:1900-01-01 from business;
-
需求五:查询前20%时间的订单信息
select * from ( select name, orderdate, cost, ntile(5) over( order by orderdate) sorted from business ) t where t.sorted = 1;
-
3.6 Rank
-
函数说明
RANK()
: 排序相同时会重复,总数不会变DENSE_RANK()
: 排序相同时会重复,总数会减少ROW_NUMBER()
:会根据顺序计算 -
数据准备
表 数据准备
name | subject | score |
---|---|---|
孙悟空 | 语文 | 87 |
孙悟空 | 数学 | 95 |
孙悟空 | 英语 | 68 |
大海 | 语文 | 94 |
大海 | 数学 | 56 |
大海 | 英语 | 84 |
宋宋 | 语文 | 64 |
宋宋 | 数学 | 86 |
宋宋 | 英语 | 84 |
婷婷 | 语文 | 65 |
婷婷 | 数学 | 85 |
婷婷 | 英语 | 78 |
-
需求
计算每门学科成绩排名。
-
创建本地 score.txt,导入数据
孙悟空 语文 87 孙悟空 数学 95 孙悟空 英语 68 大海 语文 94 大海 数学 56 大海 英语 84 宋宋 语文 64 宋宋 数学 86 宋宋 英语 84 婷婷 语文 65 婷婷 数学 85 婷婷 英语 78
-
创建hive表并导入数据
create table score( name string, subject string, score int) row format delimited fields terminated by "\t"; load data local inpath '/opt/module/datas/score.txt' into table score;
-
根据需求查询数据
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;
4. 自定义函数
-
Hive 自带了一些函数,比如:max/min等,但是数量有限,自己可以通过自定义UDF来方便的扩展。
-
当Hive提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。
-
根据用户自定义函数类别分为以下三种:
-
UDF(User-Defined-Function)
一进一出
-
UDAF(User-Defined Aggregation Function)
聚集函数,多进一出
类似于:
count/max/min
-
UDTF(User-Defined Table-Generating Functions)
一进多出
如
lateral view explore()
-
-
官方文档地址
https://cwiki.apache.org/confluence/display/Hive/HivePlugins
-
编程步骤:
-
继承
org.apache.hadoop.hive.ql.UDF
-
需要实现
evaluate
函数;evaluate
函数支持重载; -
在hive的命令行窗口创建函数
-
添加 jar
add jar linux_jar_path
-
创建 function
create [temporary] function [dbname.]function_name AS class_name;
-
-
在 hive 的命令行窗口删除函数
drop [temporary] function [if exists] [dbname.]function_name;
-
-
注意事项
UDF必须要有返回类型,可以返回null,但是返回类型不能为void;
5. 自定义 UDF 函数
-
创建一个 maven 工程
-
导入依赖
<dependencies> <dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-exec</artifactId> <version>1.2.1</version> </dependency> </dependencies>
-
创建一个类
package com.big.data.hive.udf; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.hive.ql.exec.UDF; import org.json.JSONObject; /** * 自定义 UDF 函数 */ public class BaseFieldUDF extends UDF { public static String evaluate(String line, String jsonKeysString) { // 0 准备一个sb StringBuilder sb = new StringBuilder(); // 1 切割jsonkeys mid uid vc vn l sr os ar md String[] jsonkeys = jsonKeysString.split(","); // 2 处理line 服务器时间 | json String[] logContents = line.split("\\|"); // 3 合法性校验 if (logContents.length != 2 || StringUtils.isBlank(logContents[1])) { return ""; } try { JSONObject jsonObject = new JSONObject(logContents[1]); // 获取cm里面的对象 JSONObject base = jsonObject.getJSONObject("cm"); for (int i = 0; i < jsonkeys.length; i++) { String filedName = jsonkeys[i].trim(); if (base.has(filedName)) { sb.append(base.getString(filedName)).append("\t"); } else { sb.append("\t"); } } sb.append(jsonObject.getString("et")).append("\t"); sb.append(logContents[0]).append("\t"); }catch (Exception e) { e.printStackTrace(); } return sb.toString(); } public static void main(String[] args) throws Exception{ String line = "1541217850324|{\"cm\":{\"mid\":\"m7856\",\"uid\":\"u8739\",\"ln\":\"-74.8\",\"sv\":\"V2.2.2\",\"os\":\"8.1.3\",\"g\":\"[email protected]\",\"nw\":\"3G\",\"l\":\"es\",\"vc\":\"6\",\"hw\":\"640*960\",\"ar\":\"MX\",\"t\":\"1541204134250\",\"la\":\"-31.7\",\"md\":\"huawei-17\",\"vn\":\"1.1.2\",\"sr\":\"O\",\"ba\":\"Huawei\"},\"ap\":\"weather\",\"et\":[{\"ett\":\"1541146624055\",\"en\":\"display\",\"kv\":{\"goodsid\":\"n4195\",\"copyright\":\"ESPN\",\"content_provider\":\"CNN\",\"extend2\":\"5\",\"action\":\"2\",\"extend1\":\"2\",\"place\":\"3\",\"showtype\":\"2\",\"category\":\"72\",\"newstype\":\"5\"}},{\"ett\":\"1541213331817\",\"en\":\"loading\",\"kv\":{\"extend2\":\"\",\"loading_time\":\"15\",\"action\":\"3\",\"extend1\":\"\",\"type1\":\"\",\"type\":\"3\",\"loading_way\":\"1\"}},{\"ett\":\"1541126195645\",\"en\":\"ad\",\"kv\":{\"entry\":\"3\",\"show_style\":\"0\",\"action\":\"2\",\"detail\":\"325\",\"source\":\"4\",\"behavior\":\"2\",\"content\":\"1\",\"newstype\":\"5\"}},{\"ett\":\"1541202678812\",\"en\":\"notification\",\"kv\":{\"ap_time\":\"1541184614380\",\"action\":\"3\",\"type\":\"4\",\"content\":\"\"}},{\"ett\":\"1541194686688\",\"en\":\"active_background\",\"kv\":{\"active_source\":\"3\"}}]}"; String x = BaseFieldUDF.evaluate(line, "mid,uid,vc,vn,l,sr,os,ar,md,ba,sv,g,hw,nw,ln,la,t"); } }
-
打成jar包上传到服务器
/opt/module/jars/hive-udf.jar
-
将jar包添加到hive的
classpath
hive (default)> add jar /opt/module/datas/hive-udf.jar;
-
创建临时函数与 class关联
hive (default)> create temporary function base_analizer as "com.big.data.hive.udf.BaseFieldUDF";
-
即可在
hql
中使用自定义的函数base_analizer
hive (default)> select split(base_analizer(line,'mid,uid,vc,vn,l,sr,os,ar,md,ba,sv,g,hw,t,nw,ln,la'),'\t')[0] as mid_id from ods_event_log;
-
6. 自定义 UDTF 函数
6.1 自定义 UDTF 步骤
- 创建一个类,继承
org.apache.hadoop.hive.ql.udf.generic.GenericUDTF
。 - 重写
initialize
方法,指定输出参数的名称和参数类型。 - 重写
process
,输入一条记录,输出若干个结果。 - 重写
close
方法。
6.2 具体实现
-
创建一个类
package com.big.data.hive.udtf; import org.apache.commons.lang.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.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 org.json.JSONArray; import org.json.JSONException; import java.util.ArrayList; import java.util.List; /** * 自定义 UDTF 函数 */ public class EventJsonUDTF extends GenericUDTF { /** * 初始化 * 指定输出参数的名称和参数类型 * @param argOIs * @return * @throws UDFArgumentException */ @Override public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException { ArrayList<String> fieldNameList = new ArrayList<>(); ArrayList<ObjectInspector> fieldOIList = new ArrayList<>(); fieldNameList.add("event_name"); fieldOIList.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); fieldNameList.add("event_json"); fieldOIList.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNameList,fieldOIList); } /** * 输入一条记录,输出若干结果 * @param objects * @throws HiveException */ @Override public void process(Object[] objects) throws HiveException { if (objects == null || objects.length < 1) { return; } // 获取传入的 et Object object = objects[0]; if (object == null) { return; } String input = object.toString(); if (StringUtils.isEmpty(input)) { return; } JSONArray jsonArray = null; try { jsonArray = new JSONArray(input); } catch (JSONException e) { e.printStackTrace(); } if (jsonArray == null || jsonArray.length() <= 0) { return; } for (int i = 0; i < jsonArray.length(); i++) { try { String[] result = new String[2]; // 取出事件名称 result[0] = jsonArray.getJSONObject(i).getString("en"); // 取出整个事件 result[1] = jsonArray.getString(i); forward(result); }catch (Exception e) { e.printStackTrace(); continue; } } } @Override public void close() throws HiveException { } }
-
打成jar包上传到服务器
/opt/module/jars/hive-udtf.jar
-
将jar包添加到hive的
classpath
hive (default)> add jar /opt/module/datas/hive-udtf.jar;
-
创建临时函数与 class关联
hive (default)> create temporary function flat_analizer as 'com.big.data.hive.udtf.EventJsonUDTF';
-
即可在
hql
中使用自定义的函数flat_analizer
select event_name, event_json from ( select split(base_analizer(line, 'mid,uid,vc,vn,l,sr,os,ar,md,ba,sv,g,hw,t,nw,ln,la'), '\t')[17] as ops from ods_event_log ) t lateral view flat_analizer(t.ops) tem_k as event_name, event_json;
-