2020.9.27(hive参数设置、运行方式、动态分区、分桶)

除了第一节课讲概念理论之外,后面的操作都是比较细的点,因为hive的技术点没办法,到公司使用的时候也是一些非常琐碎的点,各个点之间没有太多的关联性。这10分钟可能讲这个知识点,下10分钟可能另外一个技术点了,一点关联都没有,是没办法的。hive里更多的是基本操作的问题。要有复习总结的过程。

第一个知识点:hive参数操作和运行方式

hive的参数操作:

hive应该如何设置对应的参数?之前搭建集群的时候,在hive-site.xml里面进行过基本的参数修改,但在企业里面可能不全是往hive-site.xml里面修改数据,原因是:
hive可以给开发人员使用,也可以给数据分析师使用,这意味着,每个人在进行分析操作的时候,他可能需要一些不同的参数。如果你把你需要的所有参数都放到了某一个hive-site.xml文件里,意味着这个参数是在当前的所有规划里面都生效的。但是,有些情况下,我不需要这样的操作和参数配置,应该怎么办?
所以要针对每一个更细粒度做一个划分
比如:有一个数据分析师要加一个参数,你可以自己设置参数而不会影响其他成员或用户的基本使用。到公司后也会有很多这样的操作。

hive参数的基本分类:

在这里插入图片描述
上面三个表示参数,最后一个表示变量。
** hiveconf**:表示只适配于hive的配置文件,比如之前配的hive连接MySQL的URL,username,password要配在这里面
system:表示当前服务器操作系统的参数
env:环境变量,比如JAVA_HOME HIVE_HOME
这些参数都是要进行最基本的加载的。在实际过程中,system和env很少关注,最关注的的是hiveconf这个配置项。
hivevar:hive的变量操作,在写sql语句的时候有可能需要引入一些外部的变量。这时候可以使用这样的方式来进行参数设置。

** hiveconf**:直接配置在hive-site.xml里面,除了这种方式还有很多其他配置方式:

select * from psn;

这张表在进行查询的时候和MySQL有什么不一样的地方?
有一个非常不一样的地方,当输入完sql语句之后,只出来一个OK没有表头,我想把这些表头信息显示出来怎么办?应该怎么操作呢,要加参数了。配置在hive-site.xml的方式配置是比较麻烦的,假如只在当前会话里面需要表头,其他会话不需要怎么办?

hive --hiveconf hive.cli.print.header=true

意味着你在进入命令行的时候会带上这个参数,显示表头信息的意思
在这里插入图片描述加上表头信息了,刚才参数起的作用。如果退出当前hive重新进来,又没有表头信息了。意味着刚刚参数的作用域,只在当前会话有效。
如果已经进入到命令行里面了,想设置显示表头信息,不可能每次Ctrl+C退出重新进吧,这种方式比较麻烦,在命令行里也有对应的命令

hive> set;

输出很多东西,表示在当前hive会话里面应该已经运用到的一些参数
在这里插入图片描述在这里插入图片描述
system:表示system环境的一些参数
env:表示环境变量
没加冒号的表示hive本身自己参数的配置
hive是以hdfs作为存储引擎,同时以MapReduce作为计算引擎,所有hive会把hdfs和MapReduce对应的参数都同样加载进来。

这个参数非常多,看起来比较麻烦,有没有简单的方式可以这些参数都搞成一个文件?
而不要每次翻屏幕了,有很多很多参数翻不完的。使用重定向

hive> set hive.cli.print.header;

什么都不加,会把当前参数的默认值显示出来
hive.cli.print.header=false
现在如果想改的话:

hive> set hive.cli.print.header=true;

这种方式也是在当前会话有效。而不是全局有效的变量。

现在有3种设置方式了:

  • 1.在hive-site.xml里面配置,这种是全局有效
  • 2.hive启动命令行的时候加上–hiveconf 当前会话有效
  • 3.在命令行里通过set的方式,在当前会话有效
    还有一种方式,但更多是类似于初始化的配置:
    先把当前会话退出,在虚拟机里可能使用的是root用户,可能是god或普通用户
    在执行下面命令的时候一定要进入到当前用户的家目录下
    如果是root /root 普通用户是在home下面有一个用户目录
ll -a

可以打印出来当前目录对应的文件以及一些隐藏文件
在这里插入图片描述表示的是hive的历史,可以查看当前文件,表述的是在hive命令行里执行的所有命令这时候可以查看历史命令。除此之外,还有一个文件有可能存在有可能不存在。
不存在就自己创建:

vi .hiverc

在里面可以写命令了:

set hive.cli.print.header=true;

然后保存退出
重新敲hive命令行,它的意思是,每次在启动hive窗口的时候,会默认去当前用户的家目录里面读取配置文件信息,读取完成之后

select * from psn;

也带上对应的表头信息了,注意,那个文件在当前用户家目录,类似于创建当前用户的环境信息的操作,表达的是这个意思。换成其他用户不使用这个配置。
在这里插入图片描述

~/.hiverc

参数的配置文件,每次启动的时候会默认加载,需要自己手动创建
在这里插入图片描述
到公司以后要选择一种合适的方式去设置参数。不一定必须在hive-site.xml里面配置。
注意了hive -f并不归属于我们的参数,表示的是执行的一种方式,而不是参数设置的方式。

hive的运行方式

在这里插入图片描述
· 命令行运行方式cli:一直用的方式都是比较简单的,并没有把cli用到极致,之前只是在cli窗口里面输入对应的sql语句,除了写sql语句外,还有很多复杂的功能
1、可以直接查看hdfs里面的目录信息

hive> dfs -cat /user/hive_remote/warehouse/psn/*

在hive命令行里可以直接操作hdfs命令了,只不过命令前面不需要加hdfs,直接从dfs开头就可以了。而且这种方式运行起来速度更快。在Linux系统中输入hdfs dfs为什么慢,因为要先建立连接,然后才能查询到对应的结果。而这里已经建立好hdfs连接了,此时运行起来比较快的。以后在操作hdfs的时候,不需要在外面操作了,直接在hive命令行里就可以了
2、! ls /;
显示出来的目录是当前操作系统的根目录,可以执行Linux系统里的命令,但是注意了,在最开始要加一个!。当我们有了hivecli之后,可以操作hdfs也可以操作Linux,所以他的功能非常强大,不止看到的东西,不只能执行sql语句。熟练在cli里面运行命令。

命令行的方式在公司里用的不是特别多,每天写不同的sql语句,不可能都在命令行里进行运行吧,而且会遇到一个问题,比如说公司是做电商日志数据分析的,这个时候,每天数据必须要到凌晨0点之后才跑完,是不是要把昨天数据进行分析了,那么在进行分析的时候是不是意味着已经凌晨里,不可能每天凌晨都在公司加班吧,也不可能每天凌晨2、3点的时候跑到公司把sql语句执行一下,然后再回家。

要启动定时任务了,但是要给定时任务一个命令,要识别到hive命令之后才能进行运行。大家所了解的定时任务有几种设置方式?
crontab这种方式用的非常多,操作也非常简单。
除此之外,Azkaban、Oozie都属于任务调度的,都是用的比较多,必须要学的。在公司里面使用任务调度的时候,比较麻烦,比如同一时刻比如过来100个任务, 谁先执行,谁后执行,突然有个任务比较着急,必须现在得到结果。还要让他优先级更高一点进行执行。Oozie比较重,使用起来必Azkaban复杂很多,所以在中小型项目或一般的大数据公司里面,用的都是Azkaban,如果用Oozie也是可以的,后面会讲CDH这样的东西,里面自动集成了Oozie用起来也是比较方便的。
任务调度系统非常关键也非常重要。

现在要通过定时任务去执行了,执行的时候一定是要有一个hive的脚本的。hive脚本怎么运行?

脚本运行方式(实际生产环境中最多)

需要写哪些命令?
在这里插入图片描述
如果自学的话,应该怎么学习?

hive --service cli --help

启动metastore时候的命令是hive --service metastore如果不写--service的话默认启动的是客户端,等同于hive --service cli

在这里插入图片描述
-d 如何定义一个参数
-e 从命令行读取sql语句
-f 从文件里读取sql语句来进行执行
-i 初始化的sql文件
-s 静默模式

-d 如何定义一个参数

hive -d abc=1

把1的值给了abc这个变量,然后回车进入命令行里,意味着,我需要使用1的时候可以不写1了直接使用abc就完事了

select * from psn where id=1;
select * from psn where id=${abc};

两个结果是一样的。意味着已经把1的值给了abc了,可以直接进行运行了。

-e 从命令行读取sql语句

在Linux命令行里直接敲

hive -e "select * from psn"

会帮我们把结果检索出来,并且打印到对应的控制台。之后写脚本的时候,基本使用的都是这样的一种方式!
执行完之后直接退出命令行了,并没有在里面接着进行操作。除此之外,里面可以加多条命令。

hive -e "select * from psn;show tables"

N条命令都可以进行执行,每次不需要都等着进入到命令行里,所有到公司选择合适的方式,一般写脚本的话都是hive -e

第三种方式,我的结果不要显示在控制台,能不能放到某一个文件里面进行存储?使用重定向。

hive -e "select * from psn" >>aa.txt

控制台有OK有time token但是没有数据,但是在当前目录下,cat aa.txt也把对应结果展示出来了。可以执行重定向。

想想set的命令,想把所有参数都拿出来怎么操作?

hive -e "set" >>set.txt

查看文件:

more set.txt

敲一次空格大概1%到2%,这里面配置信息非常非常多。
在执行hive -e命令的时候有一个非常不好的地方,总会出现一个OK还有Time Token的字段,不想让这个字段出现该怎么办,这时候需要使用hive的静默模式。

hive -S -e "select * from psn"

静默模式用的也比较多,在公司写脚本运行命令的时候,经常会有一些无意义的输出,比如输入一个passwd会输出一个Changing password for user root.
这时候怎么办?不想让这句话显示怎么办?黑洞
把这句话重定向到/dev/null表示Linux下的一个数据黑洞。属于Linux里的基本命令,也属于我们的基本模式,写脚本的时候用的非常多。

-f 从文件里读取sql语句来进行执行

从某个文件读取sql命令,

vi sql
写上:select * from psn;
hive -f sql

他会把文件里的命令都读取出来进行执行。执行完之后把结果打印到控制台。

-i 初始化的sql文件

vi sql
写上:select * from psn;
hive -i sql

也是从文件里读取命令,但是注意了,-i叫做初始化,刚刚-f的时候得到结果退出当前会话了,但此时,执行完之后不会退出hive命令行,只是为当前窗口执行一些初始化命令。也就是说,如果有一些参数的话可以写到这个文件里面,然后每次执行时候引用一个文件,会执行相关的命令。所以叫初始化操作,而不叫从文件里读取的操作。

除此之外,想在hive里面执行外部的sql语句可以执行么?
是可以的。叫source

source sql;

也执行了外部文件里的命令。

还有一个非常关键的点:

hive -S -e "select * from psn"

现在运行起来一点问题都没有,但是,这两个参数的顺序能反过来么?
这种方式是不可以的。如果命令后面要求跟一个具体的参数值,顺序是不能换的,否则会有问题。hbase也有对应的基本操作,顺序是不能反的。

提问:上节课讲了hiveserve2和beeline什么时候用?
在公司里面大部分操作,如果你是开发人员,肯定用命令行了,非常简单。如果是数据分析师,更多的是希望看到黑窗口么?不是的,更多的是希望看到web浏览器的方式。这个时候就可以启动hiveserver2的服务,单独给他启动一个webUI的页面,在里面提交sql语句进行参数的提交了。

第三种设置数据的方式:JDBC方式

第四种:web GUI 接口(hwi、hue)

hive里面自带了webUI页面,但是是非常丑的,用户体验度极度不好的。官网里有一句话。
在这里插入图片描述
Setting Up Hive Web Interface
Version

HWI is only available in Hive releases prior to 2.2.0. It was removed by HIVE-15622.
HWI在2.2的版本之后,已经把这个东西摒弃掉了。这个是hive里面自带的,非常丑。除了这个还有一个东西叫做hue。在hadoop官网里有这样的技术Ambari。
在这里插入图片描述A web-based tool for provisioning, managing, and monitoring Apache Hadoop clusters which includes support for Hadoop HDFS, Hadoop MapReduce, Hive, HCatalog, HBase, ZooKeeper, Oozie, Pig and Sqoop. Ambari also provides a dashboard for viewing cluster health such as heatmaps and ability to view MapReduce, Pig and Hive applications visually along with features to diagnose their performance characteristics in a user-friendly manner.
一个基于web的工具,提供管理监控hadoop集群,包含了很多技术,hdfs,MapReduce,hive,HBASE。。很多这样的工具,在浏览器里可以直接进行对应查看了。是这样的技术。基于BS架构的技术一定是未来的趋势。

HUE也是浏览器的基本工具。可以集成对应的sql语句。在里面可以提交sql语句,会有对应的执行结果。会看到很多可视化的工具,非常正常。不需要我们开发。

对于实时的业务,还是推荐使用流式计算框架,比如sparksql,flink这样的东西,用hive不太合适,hive是离线跑批的引擎,不是跑实时的。

Hive的动态分区和分桶

静态分区特点:在定义表的时候,必须把它指定为一张分区表。在添加数据的时候,必须要自己手动给出分区列的值。意味着,同一份数据,所有数据都放到某一个分区里面了。这种方式不太好。更多是希望看到我的分区是随着数据的由来,一层一层根据字段值往里面添加的,而不是手动赋值。在这样的前提下,产生了动态分区的概念。

Dynamic Partitions

在这里插入图片描述
在执行hive操作的时候,什么操作会执行MR,什么操作不会执行MR?
理论上来说,所有的hive的sql操作,都是要转化成MR来进行执行的,但是我们看到效果是,当我们在执行select * 或者执行select * 加一些where条件的时候,并没有执行MR语句,原因是hive里面已经帮我们做了优化了。对这些操作,它直接就会读取数据,而不会触发MR,之后讲优化的时候,会把这些点讲的非常清楚,也会演示对应的效果。

官网要求使用insert插入,insert有两种方式:
from insert select 和 insert into values(这种方式几乎不用)
因此,一般是从一张表里查询数据插入另外一张表里面。

create table psn21
(
id int,
name string,
age int,
gender string,
likes array<string>,
address map<string,string>
)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':';

这只是一张普通的表,导入数据文件:

load data local inpath '/root/data/data4' into table psn21;
select * from psn21;

有对应的结果显示。
想要动态分区,意味着要创建对应的动态分区表。
怎么做?

create table psn22
(
id int,
name string,
likes array<string>,
address map<string,string>
)
partitioned by (age int,gender string)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':';

要按照age和gender进行分区,意味着不能写在普通属性里面了,要写在partition里面了,把对应的分区表先创建好。
现在需要按照数据里面的字段,往对应的表里插入数据了。
现在只是刚把表创建好没有数据,要用什么语句?官网里说了,使用insert语句

在这里插入图片描述hive的动态的扩展方式,不能写*,因为字段顺序必须和最终的结果表是一致的,要加partition,表示要往哪个分区里插入数据了。

insert into table psn22 partition(age,gender) select id,name,likes,address from psn21

在这里插入图片描述想使用hive的动态分区,必须要设置参数
在这里插入图片描述注意:hive.exec.dynamic.partition=true默认是true的,但是在公司里面可能拿的是别人的集群,别人可能已经改成false了,这个值必须要确保为等于true才可以。
动态分区模式,nostrict 非严格模式,strict严格模式,默认值是严格模式的。

set hive.exec.dynamic.partition.mode=nostrict;

这时候再执行刚才的语句,注意,这时候age和gender字段也要用,在select的时候也要查询出来。

insert into table psn22 partition(age,gender) select id,name,likes,address,age,gender from psn21

在这里插入图片描述

这个时候没有问题了,开始触发MR任务了。在严格模式里要求必须要运用静态分区,原因是,在严格模式里面,用户必须指定至少一个静态分区列,以防用户把所有的分区列覆盖掉。在插入数据的时候可以选择into,也可以选择overwrite,一个是插入一个是覆盖。如果是覆盖的话,不仅是静态分区,还可能把前面所有分区列给覆盖掉。如果分区列是以秒为单位的,一天要建非常多的目录,这么多目录是非常麻烦的,建一个分区在最外层可以做最基本的区分,防止分区的意外情况。

还有一些相关参数:
– set hive.exec.max.dynamic.partitions.pernode;
▪ 每一个执行mr节点上,允许创建的动态分区的最大数量(100)
– set hive.exec.max.dynamic.partitions;
▪ 所有执行mr节点上,允许创建的所有动态分区的最大数量(1000)
– set hive.exec.max.created.files;
▪ 所有的mr job允许创建的文件的最大数量(100000)
这个数量是和Linux系统的内核挂钩的,1G内存最多打开10w个文件

cd /proc/sys/fs
cat file-max

385915个,因为虚拟机是4G的内存

ulimit -a

里面有个open files 值是1024表示每个进程最多打开文件的数量
这个10w个不是白设置的,每次打开文件都需要占用一定的系统资源,内存,这时候不能超过这个数量,超过系统就崩了。《深入理解计算机系统》

都是为了限制动态分区目录数,动态分区的数量是根据值来指定的,值有多少个是无法预估的,是根据数据来决定的,所有如果目录非常非常多的话,会导致查询效率降低,并不是分区越多就越好,要选择合适的粒度

hive分桶

注意:hive的分区和分桶完全不是一回事!!
分区在hdfs里面看到的展现形式是多级目录,每个目录里面放着固定特征的数据文件,当我需要去检索某一部分文件的时候,直接去目录里面找就可以了,而不需要去全量遍历数据。但这时候依然会有一个问题。
我公司,一天的数据量是10T,假如按天进行分区,这意味着,一个分区目录里放着10T的文件,依然很大,我不可能把10T的数据都放在一个数据文件里吧。
比如看小说,一个10M的小说用阅读器打开来非常慢,这时候应该考虑把文件隔离开来,用N多个文件来存,这叫做文件的分桶操作。
为了把数据做一个更细粒度的切分。之前分区在切分数据的时候,相当于是一个横向切分,现在分桶的时候相当于纵向切分,把某一部分数据可以放在一起。这是分桶存在的意义。
在这里插入图片描述
之前做过分区了,依然可以继续做分桶,这是不矛盾的。有两个应用场景,一个叫数据抽样,一个叫MapsideJoin,是官网里面明确的指示。
LanguageManual DDL BucketedTables
在这里插入图片描述

bucket这个词见过,在讲hive里面的delete和update的时候,事务操作的时候有一个限制,这张表必须要被进行过分桶。原因在这里。
分桶是按照某一个列值的哈希值取模之后进行分桶。
为什么适合做抽样的操作?
比如要统计北京市多少人戴口罩,一个学生去水泥厂,发现全部带口罩,一个学生去空气好的地方,发现没有人带口罩。这时候怎么知道北京市戴口罩的比例?可以把数据进行一个散列,把每一部分的数据随机取一点,做一个抽样查询,这个时候需要用到我们的分桶。原来是把所有数据放在一个文件里,现在按照某些规则把一个文件切分成了N多份,我再接着从N多份文件里取数据就完事了。

在这里插入图片描述
怎么进行操作?
开启支持分桶
– set hive.enforce.bucketing=true;
▪ 默认:false;设置为true之后,mr运行时会根据bucket的个数自动分配reduce task个数。(用户也可以通过mapred.reduce.tasks自己设置reduce任务个数,但分桶时不推荐使用)
▪ 注意:一次作业产生的桶(文件数量)和reduce task个数一致。
在这里插入图片描述这个参数在2.x的时候找不到了,默认支持分桶操作,但是关键在于,在定义hive表的时候要把它定义成一张分桶表。hive在默认情况下帮我们做了很多点的优化了,比如说MapTask的个数,reduceTask的个数,(比如会把两个小文件放在同一个mapTask里面),reduceTask在不设置的时候默认是1个的,但是会优化成和bucket的个数是一致的。

▪ 往分桶表中加载数据
– insert into table bucket_table select columns from tbl;
– insert overwrite table bucket_table select columns from tbl;

建一个普通表:

CREATE TABLE psn31( id INT, name STRING, age INT)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
load data local inpath '/root/data/bucket' into table psn31;

现在要建分桶表了,需要指定分桶字段了:

CREATE TABLE psnbucket( id INT, name STRING, age INT)
CLUSTERED BY (age) INTO 4 BUCKETS
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

现在有了原始数据表,又有了结果表,又可以insert into了

insert into table psnbucket select * from psn31;

在这里插入图片描述
把数据都已经散列开了,接下来可以抽样查询了。
在hive里面有抽样的语法规则:
在这里插入图片描述
强调:x表示从第几个bucket开始抽取数据,并不包含0,如果有4个桶就是1,2,3,4而不是0,1,2,3

bucket 2 out of 4;
x=2
y=4
表示:从第 2 个桶取数据,取 (桶的个数/y)= 1 份数据
select * from psnbucket tablesample(bucket 2 out of 4);

从 2 号桶开始,取 1 份数据,000001_0里放的是 3 和 7
意味着是从第二桶里面取数据的,并且取出来了一整桶的数据。

bucket 3 out of 8;
x=3
y=8
表示:从第 3 个桶取数据,取 (桶的个数/y)= 1/2 份数据
select * from psnbucket tablesample(bucket 3 out of 8);

表示从第3个桶里取数据,取出来了一条数据,1/2桶的数据

bucket 3 out of 16;
x=3
y=16
表示:从第 3 个桶取数据,取 (桶的个数/y)= 1/4 份数据

这个里面总共有2条数据,取1/4条数据是什么效果?
在这里插入图片描述按道理说,半行数据应该不显示,因为数据没有半行的说法,但是有两个分区取出来数据了,有两个分区没取出来数据。同样的把16改成32:
在这里插入图片描述
这个地方困扰了很久?
要不然每个分区都取出来数据,要不然都取不出来数据,但现在的情况是部分能取出来,部分取不出来数据。这可能是hive的bug
所有在这里设置y的时候,建议就设置成桶的因子,不要设置成桶的倍数了。
设置成因子的时候,每次取的是整个桶的数据,设置成因子就很难划分了。

bucket 3 out of 2;
x=3
y=2
表示:从第 3 个桶取数据,取 (桶的个数/y)= 2 份数据

先去3号桶的数据,然后应该取5号桶的数据,但是我们没有5号桶,数据根本取不到会报错
从1号桶开始取,然后取3号桶的数据,每次都跨y这个值,所有3号桶能取出来

在往分通表里存数据的时候,已经根据列的值进行过一次散列了,并且后面又取了模,根据模的值来决定每个数据放在哪个分桶里面。

为什么会跳桶取数据?
现在有4个桶,每个桶里都是符合某一个哈希规则的数据聚合在一起的。如果是按照连续的方式取数据,那有不是一个随机方式了,现在按照跳桶的方式取数据,跳的值正好是y的值,这样意味着取1号桶,不取2号桶,取3号桶。。取2号桶,不取3号桶,取4号桶。。取3号桶,应该取5号桶,没有5号桶它不会往回返。
每次都会加上y的值去下一个桶取数据

如果是y的值是桶的倍数是不是也是跳桶取数据的?

假设有32个桶
bucket 3 out of 256;
x=3
y=256
表示:从第 3 个桶取数据,取 (桶的个数/y)= 1/8 份数据

我连一份数据都没取完,会涉及到跳桶的问题么?就没有跳桶的这一个说法了。

分桶操作只适用于抽样查询。

提问:看DML语句,之前在讲update的时候,在进行事务管理的时候,为什么要求我们必须要进行分桶?能不能想明白?
在执行update或delete的时候,必须要配置事务,但进行事务配置的时候,有很多限制,其中一个限制是必须要进行分桶,这是由hive的一个特征决定的。hive的数据是放在hdfs的,而hdfs里面放的数据要求只能append,不能进行修改和删除操作,这意味着,如果一个文件变得非常非常大的话,要修改需要把整个表的数据读出来,读完之后把其中某个值修改了,修改之后要重新生成新的文件,分桶之后可以定向的去某一个文件里把数据拿出来。原来是100M,假如分了4个桶,只要生成一个25M的新文件就可以了,之前的75M不需要重新生成了。不需要进行全量数据的重新生成了。

Hive Lateral View

在这里插入图片描述
上节课的时候讲了函数,分类:UDF UDAF UDTF
hive lateral view是和UDTF组合起来使用的
比如上节课讲了这个案例,把输入的集合的数据拆分开,变成N多个值,输入一个值,返回多个值

select explode(likes) from psn;

现在加一个字段

select explode(likes),id from psn;
select explode(likes),explode(address) from psn;

在这里插入图片描述都不报同样的错误,意思是只有一个简单的表达式支持在UDTF里面
当你在一个SQL语句里面,如果你用了UDTF函数,那么不好意思,当前SQL语句里面只允许出现这一个字段,其他字段都不能够组合使用了。这种很难受。
比如现在有这样的需求:

select * from psn;

分析一下这张表里一共有多少种爱好和多少种地址,这个怎么做
能看出来是3种爱好,2个地址
问题是用SQL语句怎么查出来?
爱好,首先要把array里面的值拆分出来,同时要把地址里面的值拆分出来。刚刚演示过了,使用UDTF函数的时候,不能跟其他列,以及不能跟其他UDTF函数组合使用,这个地方就成了问题。

怎么解决问题?
就需要用到hive lateral view的语法了。

hive Lateral View
– Lateral View用于和UDTF函数(explode、split)结合来使用。
– 首先通过UDTF函数拆分成多行,再将多行结果组合成一个支持别名的虚拟表。
– 主要解决在select使用UDTF做查询过程中,查询只能包含单个UDTF,不能包含
其他字段、以及多个UDTF的问题
– 语法:
– LATERAL VIEW udtf(expression) tableAlias AS columnAlias (’,’ columnAlias)

在这里插入图片描述

select count(distinct(myCol1)), count(distinct(myCol2)) from psn2
LATERAL VIEW explode(likes) myTable1 AS myCol1
LATERAL VIEW explode(address) myTable2 AS myCol2, myCol3;

因为address是个map结构,所以key变成一个列,value变成一个列
这样用法有什么好处?上面用的时候,就可以直接用别名使用了。
算是视图的一种,但它不是视图。意思和视图一样,把这个查询出来的值变成一个虚拟表,给一个表的别名,给一个列的别名。之后,在上面使用的时候,直接把表和列的别名用起来就可以了。
类似于是一张临时表的概念,但是写的时候,必须要加两个关键字LATERAL VIEW才能进行组合使用。同时注意了:myTable1 myTable2 myCol1 myCol2 myCol3名字是可以随便指定的。

提问:把myTable1 myTable2 都改成psn可以执行么?

select count(distinct(myCol1)), count(distinct(myCol2)) from psn 
LATERAL VIEW explode(likes) psn AS myCol1
LATERAL VIEW explode(address) psn AS myCol2, myCol3;

可以执行的。语法结构里明确表示说这只是一个表的别名。相当于说,别名爱起什么起什么,无所谓。只要列名能取到就完事了,但也不要给自己找事情,这样的操作就是为了和其他的UDTF函数/其他字段组合使用,不是为了难为自己,明明可以设置成不一样的,非要把它设置成一样的。。。

select id,myCol1 from psn
lateral view explode(likes) psn as myCol1;

这样也组合起来了。

这个执行顺序是什么?
设计到SQL的解析过程,它每次一定是把所以的SQL语句拿出来,拿出来之后根据关键字来进行取值,比如说在MySQL的时候,根据关键字取值出来,划分from,where,select,group by,having,order by这几个关键字执行顺序是什么样子的。它是有默认的顺序,lateral view也有默认的顺序,按照这个顺序解析就完事了。
第一次取的时候肯定是先把表拿过来,告诉我要从哪儿读数据的
第二件事有lateral view关键字,先执行这两行,然后再执行上面操作
它里面一定包含了某种默认顺序。。叫做执行计划,讲优化的时候再说

explain extended select id,myCol1 from psn lateral view explode(likes) psn as myCol1;

这就是SQL语句的执行计划,涉及到怎样的执行过程,每一步是怎么解析的。这里面有一个东西叫做抽象语法树。从SQL语句到整个MR任务执行,涉及到关键几个步骤,第一步骤叫抽象语法树,第二步叫查询块,第三步叫逻辑查询计划,第四步叫物理查询计划,第五步叫优化执行
这五步一般都是不讲的,因为SQL语句的解析是通过第三方组件来实现的,也不需要开发出一套SQL解析的引擎,没必要学习,稍微了解一下,也不会问到hive源码层面的东西,几乎没什么用。
hive源码应该怎么看,从哪看怎么进行一个执行操作。。下节课再说

猜你喜欢

转载自blog.csdn.net/m0_48758256/article/details/108826609