六、函数
1、系统自带函数
<1>、查看系统自带的函数
hive> show functions;
<2>、显示自带的函数的用法
hive> desc function upper;
<3>、详细显示自带的函数的用法
hive> desc function extended upper;
2、自定义函数描述
1)Hive 自带了一些函数,比如:max/min等,但是数量有限,自己可以通过自定义UDF来方便的扩展。
2)自定义函数有三种
UDF一进一出
UDAF聚集函数,多进一出
UDTF一进多出
3、自定义函数开发案例
<1>、环境搭建
创建一个工程,hive/lib的jar拷入工程的环境,也可以使用Maven
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>3.1.0</version>
</dependency>
<2>、编写代码,定义一个传入的参数
import org.apache.hadoop.hive.ql.exec.UDF;
public class Lower extends UDF {
public String convert(final String s) {
if (s == null) {
return null;
}
return s.toString().toLowerCase();
}
}
<3>、打包带入到测试环境
hive> add jar /opt/modules/apache-hive-1.2.2-bin/iotmp/jar/Hadoop_Test-0.0.1-SNAPSHOT.jar;
Added [/opt/modules/apache-hive-1.2.2-bin/iotmp/jar/Hadoop_Test-0.0.1-SNAPSHOT.jar] to class path
Added resources: [/opt/modules/apache-hive-1.2.2-bin/iotmp/jar/Hadoop_Test-0.0.1-SNAPSHOT.jar]
<4>、创建临时函数与开发好的java class关联
hive (default)> create temporary function my_lower as "com.example.hive.Lower";
<5>、使用函数
hive (default)> select ename, my_lower(ename) lowername from emp;
七、企业级调优
1、Fetch抓取
Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算。例如:SELECT * FROM employees;在这种情况下,Hive可以简单地读取employee对应的存储目录下的文件,然后输出查询结果到控制台。
在hive-default.xml.template文件中hive.fetch.task.conversion默认是more,老版本hive默认是minimal,该属性修改为more以后,在全局查找、字段查找、limit查找等都不走mapreduce。
<property>
<name>hive.fetch.task.conversion</name>
<value>more</value>
<description>
Expects one of [none, minimal, more].
Some select queries can be converted to single FETCH task minimizing latency.
Currently the query should be single sourced not having any subquery and should not have
any aggregations or distincts (which incurs RS), lateral views and joins.
0. none : disable hive.fetch.task.conversion
1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
2. more : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
</description>
</property>
2、本地模式
大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过,有时Hive的输入数据量是非常小的。在这种情况下,为查询触发执行任务时消耗可能会比实际job的执行时间要多的多。对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。
用户可以通过设置hive.exec.mode.local.auto的值为true,来让Hive在适当的时候自动启动这个优化。
而hive.exec.mode.local.auto.inputbytes.max可以设定最大数据输入量,当小于value的时候就采用local mr,大于就是分布式 hive.exec.mode.local.auto.input.files.max可以设置最大输入文件量,小于value的时候采用local mr,大于的时候就是用分布式mr。
<property>
<name>hive.exec.mode.local.auto</name>
<value>true</value>
<description>Let Hive determine whether to run in local mode automatically</description>
</property>
<property>
<name>hive.exec.mode.local.auto.inputbytes.max</name>
<value>134217728</value>
<description>When hive.exec.mode.local.auto is true, input bytes should less than this for local mode.</description>
</property>
<property>
<name>hive.exec.mode.local.auto.input.files.max</name>
<value>4</value>
<description>When hive.exec.mode.local.auto is true, the number of tasks should less than this for local mode.</description>
</property>
3、表的优化
<1>、大表、小表join
将key相对分散,并且数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率;再进一步,可以使用Group让小的维度表(1000条以下的记录条数)先进内存。在map端完成reduce。
实际测试发现:新版的hive已经对小表JOIN大表和大表JOIN小表进行了优化。小表放在左边和右边已经没有明显区别。
需求:测试大表JOIN小表和小表JOIN大表的效率
(1)建大表、小表和join表
create table bigtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
create table smalltable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
create table jointable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
(2)、分表向大表和小表中导入数据
hive (default)> load data local inpath '/opt/module/datas/bigtable' into table bigtable;
hive (default)>load data local inpath '/opt/module/datas/smalltable' into table smalltable;
(3)、关闭mapjoin功能(默认是打开的)
set hive.auto.convert.join = false;
(4)、执行小表join大表语句
insert overwrite table jointable
select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from smalltable s
left join bigtable b
on b.id = s.id;
Time taken: 35.921 seconds
(5)、执行大表join小表语句
insert overwrite table jointable
select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable b
left join smalltable s
on s.id = b.id;
Time taken: 34.196 seconds
<2>、MapJoin
MapJoin一般用于解决数据倾斜的问题,就比如说在做数据分析的时候,表中有10000条数据,其中5000条的key都是一样的,剩下的都是散乱均匀分布,那么就会造成很大的数据倾斜,我们为了避免这种数据倾斜的发生,这时候我们就要用上MapJoin,MapJoin会把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配,由于在map是进行了join操作,省去了reduce运行的效率也会高很多。
另外,MapJoin还有一个适用环境,它不仅仅适用于判断中相等的条件,像3<1>中的s. id=b. id,,也适用于比如s. id>b. id,因为我们如果不适用MapJoin的话,在这里运行mapReduce会进行笛卡尔积,运行效率特别低,如果使用了MapJoin,就会大大提升速度。
总结:MapJoin适用于
1.关联操作中有一张表非常小,产生了由于key相同的数据倾斜
2.不等值的链接操作
(2)、参数设置
设置自动选择Mapjoin
set hive.auto.convert.join = true; 默认为true
大表小表的阀值设置(默认25M一下认为是小表)
set hive.mapjoin.smalltable.filesize=25000000
(3)、工作机制
首先是Task A,它是一个Local Task(在客户端本地执行的Task),负责扫描小表b的数据,将其转换成一个HashTable的数据结构,并写入本地的文件中,之后将该文件加载到DistributeCache中。
接下来是Task B,该任务是一个没有Reduce的MR,启动MapTasks扫描大表a,在Map阶段,根据a的每一条记录去和DistributeCache中b表对应的HashTable关联,并直接输出结果。
由于MapJoin没有Reduce,所以由Map直接输出结果文件,有多少个Map Task,就有多少个结果文件。
(4)、 重新对刚才的Join操作测试
insert overwrite table jointable
select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from smalltable s
join bigtable b
on s.id = b.id;
Time taken: 24.594 seconds
insert overwrite table jointable
select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable b
join smalltable s
on s.id = b.id;
Time taken: 24.315 seconds
<3>、Group By
默认情况下,Map阶段同一Key数据分发给一个reduce,当一个key数据过大时就倾斜了。
并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端进行部分聚合,最后在Reduce端得出最终结果。
<4>、Count(Distinct去重统计)
数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替换
(1)、创建一张表
hive (default)> create table bigtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
(2)、加载数据
hive (default)> load data local inpath '/opt/module/datas/bigtable' into table bigtable;
(3)、设置reduce个数
set mapreduce.job.reduces = 5;
(4)、执行去重id查询
hive (default)> select count(distinct id) from bigtable;
Stage-Stage-1: Map: 1 Reduce: 1 Cumulative CPU: 7.12 sec HDFS Read: 120741990 HDFS Write: 7 SUCCESS
Total MapReduce CPU Time Spent: 7 seconds 120 msec
OK
c0
100001
Time taken: 23.607 seconds, Fetched: 1 row(s)
Time taken: 34.941 seconds, Fetched: 1 row(s)
(5)、采用Group By去重id
hive (default)> select count(id) from (select id from bigtable group by id) a;
Stage-Stage-1: Map: 1 Reduce: 5 Cumulative CPU: 17.53 sec HDFS Read: 120752703 HDFS Write: 580 SUCCESS
Stage-Stage-2: Map: 3 Reduce: 1 Cumulative CPU: 4.29 sec HDFS Read: 9409 HDFS Write: 7 SUCCESS
Total MapReduce CPU Time Spent: 21 seconds 820 msec
OK
_c0
100001
Time taken: 50.795 seconds, Fetched: 1 row(s)
显然会多用一个job来完成,但是在数据量大的情况下,这个绝对是值得的。