一、上次课回顾二、Hive SQL执行流程
三、Hive UDF函数
Permanent Function(持久化的函数)
一、上次课回顾
二、Hive执行流程分析
Spark SQL、Impla、Hive的执行流程大体相似.
Hive SQL执行流程分析:
1)SQL执行流程分析
2)面试用
常用的SQL语句:
select yyy, 聚合函数 from XXX group by yyyy;
select a., b. from a join b on a.id = b.id;
抽象语法树:
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Explain
ABSTRACT SYNTAX TREE(抽象语法树):
(TOK_QUERY (TOK_FROM (TOK_TABREF src))
(TOK_INSERT (TOK_DESTINATION (TOK_TAB dest_g1))
(TOK_SELECT (TOK_SELEXPR (TOK_COLREF src key))
(TOK_SELEXPR (TOK_FUNCTION sum (TOK_FUNCTION substr
(TOK_COLREF src value) 4))))
(TOK_GROUPBY (TOK_COLREF src key))))
面试题1:Predicate Push Down和Mapjoin分别执行在哪两个上???
PK哥在面试过程中join使用SQL来描述,问题:给你一个join的功能,使用mapjoin和reduce join来实现。
SQL要熟练到怎样的一个程度???
看到一个SQL要知道它的底层是怎么样的;使用MapReduce的思想来理解出来
给定SQL语句:
从抖音的访问日志表,带大奔的有哪些???
select * from access a where a.day=‘20190414’ and a.catalog=‘大奔’;
表最终是落地在hdfs上的,必然是要去hdfs上读取数据的;
还涉及一个概念:输入分片(inputSplit)
这个SQL语句没有shuffle,仅仅只是过滤而已.
2.1:无Shuffle
SQL语句修改,找出哪个城市ID,城市名字
==>select a.id,a.city from access
解释:SQL语句进来有两个分片,MapTask底层是两个map;两个分片的数据存放在hdfs上,分成两个MapTask,底层是以进程的方式运行;两个InputSplit对应两个Map;
2)我们看SQL中的where条件,a.day=‘20190414’,分区就是hdfs上的目录,第一步就不用执行了;
3)Map中的逻辑:拆分:split("\t")、
splits(2):if collect(…)
此时就已经找到了分片1中的大奔,分片2中的大奔
==> 类似于ETL,
4)SQL输出:如下图
2.2:有Shuffle
group by
select city ,count(1) from access
where day=‘20190414’ and cate=‘大奔’
group by city
mr count:
- map:split ==> (word,1)
- shuffle:(Word,1) partitioner ==> reduce
- reduce:(word,可迭代的(1,1,1,1,1,1,1))
==> (word, sum(可迭代的))
转换到业务需求上来是不是一样的呢了,是的
map:split ==> (city,1)
combiner:local reduce (局部聚合)
本节面试题:combiner的使用场景
Spark中reduceByKey和GroupByKey的区别
reduceByKey:全量数据聚合经过shuffle.
GroupByKey:先做一个局部聚合,本地有combiner操作.
Shuffle(洗牌)操作:可以参考我之前的博客查看:
split去读取数据,map,经过combiner计算每个task结果,根据partition的定义分到reduce上,最终结果落地HDFS,这就是group by的过程
感觉有点像mapreduce的wordcount.
SQL中的JOIN操作见后续:
穿插:WordCount需要Combiner
三、UDF函数
工作流程:
1)开发代码
2)本地测试
3) 打包代码
在工作中,Hive中的函数满足不了业务上的需求,所以需要我们自己去开发UDF函数,Hive是使用Java开发的。
分为三类:
UDF(User-Defined Function):one-to-one row mapping upper substr 一行对一行的映射
UDAF:Aggregation(聚合) Many-to-one row mapping sum/min
UDTF:Table-generating one-to-many lateral view explode()
使用IDEA打开mapreduce ETL的项目:
1、在pom.xml中添加如下:
<properties>
<hive.version>1.1.0-cdh5.7.0</hive.version>
</properties>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>${hive.version}</version>
<scope>test</scope>
</dependency>
2、编写简单的HelloUDF.java
package com.ruozedata.hadoop.udf;
import org.apache.hadoop.hive.ql.exec.UDF;
public class HellloUDF extends UDF {
/*
*需求:输入:若泽
* 输出:hello:若泽
*/
public String evaluate(String input){
return "hello" + input;
}
public static void main(String[] args) {
HellloUDF udf = new HellloUDF();
String output = udf.evaluate("若泽");
System.out.println(output);
}
}
3、打包本地提交jar包到阿里云服务器:
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateFunction 在Hive中执行:
1、create temporary function sayHello AS 'com.ruozedata.hadoop.udf.HellloUDF';
hive (g6_hadoop)> create temporary function sayHello AS 'com.ruozedata.hadoop.udf.HellloUDF';
FAILED: Class com.ruozedata.hadoop.udf.HellloUDF not found
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.FunctionTask
2、执行这个命令前需要先添加jar包:
hive (g6_hadoop)> ADD JAR /home/hadoop/lib/g6-hadoop-1.0.jar;
Added [/home/hadoop/lib/g6-hadoop-1.0.jar] to class path
Added resources: [/home/hadoop/lib/g6-hadoop-1.0.jar]
3、再次执行命令:
create temporary function sayHello AS 'com.ruozedata.hadoop.udf.HellloUDF';
还报了一个错:java.lang.UnsupportedClassVersionError: com/ruozedata/hadoop/udf/HellloUDF : Unsupported major.minor version 52.0
FAILED: Execution Error, return code -101 from org.apache.hadoop.hive.ql.exec.FunctionTask. com/ruozedata/hadoop/udf/HellloUDF : Unsupported major.minor version 52.0
因为我们本地运行程序是jdk1.8;这套环境jdk1.7;切换下版本即可;更换版本后还是这个问题,换了台机器没问题,不知道重启下集群,重启hive有没有用。
4、show functions;
已经显示有sayhello了,它会自动把大写转换为小写。
5、测试:
hive (ruozeg6)> create table dual(x string);
OK
Time taken: 1.696 seconds
hive (ruozeg6)> insert into table dual values('');
hive (ruozeg6)> select sayhello("ruozedata") from dual;
OK
hello:ruozedata
注意:创建的是临时function,所以只对当前session生效,重新开一个session是不生效的。
解决:…
Permanent Function(持久化的函数)
hive的元数据库mysql中有一张表专门用来存放函数的,此时表信息如下:
mysql> use ruoze_g6;
Database changed
mysql> select * from funcs;
Empty set (0.00 sec)
创建永久函数:
1、CREATE FUNCTION sayhello2 AS 'com.ruozedata.hadoop.udf.HellloUDF' USING JAR 'hdfs://hadoop004:9000/lib/g6-hadoop-1.0.jar';
hive (ruozeg6)> CREATE FUNCTION sayhello2 AS 'com.ruozedata.hadoop.udf.HellloUDF' USING JAR 'hdfs://hadoop004:9000/lib/g6-hadoop-1.0.jar';
converting to local hdfs://hadoop004:9000/lib/g6-hadoop-1.0.jar
Added [/tmp/23c0c2e6-8329-4d87-a025-966920086afd_resources/g6-hadoop-1.0.jar] to class path
Added resources: [hdfs://hadoop004:9000/lib/g6-hadoop-1.0.jar]
OK
Time taken: 1.046 seconds
如下图:我们可以看到自定义的永久函数在mysql数据库中的ruoze_g6元数据库下的funcs表中显示:
当前session启动测试:select sayhello2(“ruozedata”) from dual;
新开一个session来启动Hive,如下图所示
对于UDF所需要的掌握程度:
开发代码
继承:extends UDF
重写 evaluate
本地测试
main方法
打包
上传服务器测试
Hive中自带的函数IDEA的体现:
FunctionRegistry.java