hive

99 阅读15分钟

hive 是什么?

hive 是一个SQL解析工具吧,其实就是将SQL转换成为计算引擎的任务。

注意:hive 不支持表格之中数据的更新和删除。用insert overwrite 来实现数据的删除

hive的工作原理

是将sql 转化成为mapreduce作业

hive 客户端

  • hive cli 客户端
  • beeline 客户端
  • Java编程 操作客户端。

语法介绍

with as

 1: with as 必须和其他sql一起使用(可以定义一个`with`但在后续语句中不使用他)
 2: with as 是一次性的

location 关键字

location关键字
(后面必须需要指定文件夹的名字,指定文件会出错)
对于创建数据库的时候,
location 指定的是数据库文件夹的存放位置 要具体到某个xx.db文件夹。

内置表:
location关键字指定的是表文件夹的存放的位置 要具体到以表为命名的文件夹位置。

外部表:
location 也是数据存放的位置。

order by vs distribute by vs sort by vs cluster by

order by
  只会产生一个reduce任务,进行全局排序。
  1:使用order的时候 设置reduce task 数目的方式是不起作用的。
  2:如果hive的执行模式是hive.mapred.mode 是严格的话,使用order by 的时候
  后面是需要加上limit 进行限制的。
  
distribute by
    distribute by 需要写在 sort by 的前面。
    distribute by 控制map 输出到 reduce 的方式。
   
sort by 
  后面跟随字段,每个reduce内部根据写的字段来进行排序。
  
cluster by
   是 distributed by + sort by 相加的总和。
   但是 cluster by 指定的字段 只能是按照正序排列。
   cluster by 在分桶之中会被使用。
   

distinct

distinct 关键字的作用是去重 

注意:
distinct + field
当field的取值为null 有很多 可能会造成数据倾斜。
一般以group by 语法 来代替 distinct关键字的作用

join

hive join 的种类

  • map join
  • common join

common join

reduce阶段完成join

map join

map 阶段完成 join

map join 与 common join

   map join 一般用于大表与小表 join , 小表的大小限制为 由参数`hive.mapjoin.smalltable.filesize` 来决定,默认值为 25M。满足条件的话 Hive 在执行时候会自动转化为 MapJoin,或使用 hint 提示 `/*+ mapjoin(table) */` 执行 MapJoin。
   

map join的相关的参数

hive.auto.convert.join= ture; 设置自动化开启(默认为false)

hive.mapjoin.smalltable.filesize=25000000; 设置小表大小的上限(默认为25M)

join 注意点

1join时 表格的顺序 很重要
   左边的表 一般为小表 右边的表为大表
   一般会将左边表读入缓存之中 右边表是流式读取。
   
2: inner join
  a join b on a.user_id=b.user_id
  where 条件之中 加入过滤 不管是什么字段 都是先过滤 再join
  没有遵循 先joinwhere 的顺序。谓词下推

3: 内连接的连接字段 在连接的时候 会对on 字段进行过滤 过滤掉不是null的字段,然后再join。但是外连接 对于连接字段 不会进行null的过滤
  
4: join 的时候 不能加入 < > !=的比较式子 只是支持 =

5join 的时候 on 两边比较的字段的类型是需要相同的,否则的话,某个字段的值 可能会全部shuffle到一个reduce 之中,这样的话,也是会造成数据倾斜。

6: 大小表之间进行join 思考mapjoin来进行优化实现
 
   

lateral view

   hive之中的侧视图 一般和 udtf函数结合使用

侧视图的原理

  侧视图的原理是将UDTF的结果构建成一个类似于视图的表,然后将原表中的每一行和UDTF函数输出的每一行进行连接(一列输出的多行),生成一张新的虚拟表

数据库相关

创建库:
create database [if not exists] xxx
[with dbproperties(xxx=yyy)]
[location xxxx] 指定数据库数据文件存储的位置 指定位置的时候 是需要指定到具体要创建的db.sl地址的。;

创建的库 会在 配置文件设置的目录下面建立了一个文件夹,后缀是以.db结尾的。

显示数据库:
show databases;

显示数据库的信息:
describe databases [extended] database_name; 
不加extended 不显示扩展信息
加上extended 显示扩展信息。

修改数据库:
alter database database_name set dbproperties(""="")

使用数据库:
 use xxx
 
删除数据库:
  drop database [if exists] xxx (那么在hdfs上面db的目录也是会被删除的)后面有关键字 cascade 加上这个关键字来删除非空的数据库。

表之中写入数据

1: 数据来自文件
load data [local] inpath 'data_path' into table table_name [partition (pfield=pval)]
  
2: 数据来自表
insert into table_name_A
select * from table_name_B

表拷贝

数据表结构拷贝

create table new_table_name like copyed_table_name;

数据表结构 和 其中的数据一同拷贝

create table new_table_name as
select * from copyed_table_name;

分区 开窗(over( partition by ))

开窗函数的语法


分析函数 over(partition by 列名 order by 列名 rows between 开始位置 and 结束位置)

开始位置就是表示 向前取多少行 结束位置,就是表示往后取多少行。
默认的取值范围 为 到 当前行

外部表 与 内部表

1:内部表的数据由hive自己管理  
2:外部表的数据由hdfs管理

删除内部表 元数据和真实数据会一起删除。  
删除外部表 只会删除元数据。

表的相关操作

建表语句:
create [tempoary| external] table table_name // 创建的是否使外部表 使需要注意的
(field1 field_type,.......)
[location]
[comment]
[partitioned by (pfield ptype,.....)] // 是否分区
[clustered by (buck_field) sort by(bucked_field) into num buckets]
[serde]
[row format delimited
fields terminated by ''
lines terminated by '']
[stored as fileType]

注意点:
创建表的时候 注意表的读取格式 stored as 指定上传文件的类型
默认的文件类型使textFile
serde 和row format delimited 的作用几乎使相同的,
指定如何将列转化成为字段。
如果想要将文本格式存储数据的表 转换成为以 特殊文本形式存储的表的话,
要建立一个中间表 然后使用insert 语句 将数据插入到表格之中。


拷贝表
create table tableA like tableB;

查看表结构
desc tableName
desc formatted tableName

删除表
drop table tableName

修改表名
alter table xxx rename to yyy;

修改表字段
alter table xxx change column oldColumn newColumn 字段类型 comment 'xxx' after 字段名。

增加表字段
alter table xxx add column 字段类型

分区

对于分区的理解

分区的目的:
  将表数据,分散到多个子目录中,在执行查询时,可以只选择查询某些子目录中的数据,加快查询效率;

分区的实质:
  分区其实就是一个目录
  分区对应的目录名为 区列列名=分区列列值


动态分区 与 静态分区

静态分区:
  若分区的值是确定的,那么称为静态分区。新增分区或者是加载分区数据时,已经指定分区名。

动态分区:
  分区的值是非确定的,由输入数据来决定。

分区表

分区表的查询模式
分区表的查询模式由严格模式和非严格模式两种。默认的模式是非严格。
设置查询模式为严格模式的方法:
set hive.mapred.mode=strict 

查看分区表下有哪些分区

show partitions table_name [partition("pname"="pvalue")]

partition关键字 表示查看具体的分区下面有哪些分区。

增加分区

alter table table_name add partition ("pname"=”xxx“) [location 放置到指定的路径下]

分桶

什么是分桶

  一个分桶就是一个目录,使用分桶的时候,需要指定分桶的数目,
  对分桶列进行hash去值,然后对分桶数进行取模,决定数据被存储在哪个分桶之中

分区和分桶之间的区别

  分区的数目不固定,分桶的数目都是固定的。
  分区和分桶的实质都是目录。

hive 元数据

1: hive 元数据可以存储在内嵌的 Derby数据库。
2: hive 元数据可以存储在 mysql数据库之中

hive 读写流程


hdfs -> inputformat ->serde->row object->serde->outputformat->hdfsfile

serde的作用是将文本行 与 表的字段解释相对应。

map / reduce 任务数 的计算方式

压缩方式比较

  主要从压缩方式是否支持切分这个角度来观察。

压缩算法   是否支持切割    native   压缩率     解压速度   是否hadoop自带   换成压缩格式后原本程序是否需要修改
gzip      否            是        很高      比较快                    和文本处理一样,不需要修改   
lzo       是            是        比较高     很快                     需要建立索引 
snappy    否            是        比较高     很快                     和文本处理一样,不需要修改
bzip2     是            否        最高       慢                      和文本处理一样,不需要修改

文件格式

  在hive 之中,对于 文件格式的主要关注点,也在于,文件格式是否支持切割,以及是 行式存储 还会 列式存储容量
 Text File: 行式存储,支持切割
 SequenceFile:行式存储,支持分割
 ORC Files: 先按行切分成块,块内按列存储,支持切分  

hive.input.format

 查看 hive 当前所使用的 inputformat类型
 set hive.input.format

map任务数

map任务数 与三个因素相关:
1: 文件的压缩格式
2: 文件的存储格式 
3: hive.input.format

情况1:
  前提:文件压缩存储,且压缩算法不支持切分。
   hive.input.format 的值为 CombineFileInputFormat
   
   map数由 四个参数影响
    mapred.split.max.size // 每个map处理的文件的最大数据量
    mapred.split.min.size // 每个map处理的最小的数据量
    mapred.split.min.size.per.node
    mapred.split.min.size.per.rack
 
  四个参数生效的优先级 最下面的最高,就以参数设置而言,
  mapred.split.max.size >= mapred.split.min.size >= 
   mapred.split.min.size.per.node >= mapred.split.min.size.per.rack
   
   注意:在输入文件的压缩格式是不能被切分的情况下,设置以上的参数,只能调低map的任务数,而不能调大map的任务数。通过调大
mapred.split.max.size 参数的值,来降低map的任务数。

情况2:
   前提:
     文件被压缩,支持切分,
      hive.input.format 的值为CombineFileInputFormat
      
   map数由 四个参数影响
    mapred.split.max.size // 每个map处理的文件的最大数据量
    mapred.split.min.size // 每个map处理的最小的数据量
    mapred.split.min.size.per.node
    mapred.split.min.size.per.rack
 
  四个参数生效的优先级 最下面的最高,就以参数设置而言,
  mapred.split.max.size >= mapred.split.min.size >= 
   mapred.split.min.size.per.node >= mapred.split.min.size.per.rack
   
   注意:
     可以通过调下  mapred.split.min.size.per.rack ,mapred.split.min.size.per.node ,mapred.split.min.size 这三个参数来增加map的任务数。
     可以通过调大 mapred.split.max.size 参数值,来增加map的任务数。

reduce 任务数


hive 自己决定reduce数目的规则,
 reduce

// 设置reduce的数目
mapred.reduce.tasks = N;

// 每个reduce所接收的数据量的大小
hive.exec.reducers.bytes.per.reducer

//每个任务最大的reduce数,默认为999
hive.exec.reducers.max  

reduce的任务数 = min(hive.exec.reducers.max ,总输入数据量/参数1))

注意:
  使用 order by,全局只会生成一个reduce任务

压缩格式

  查看hive 当前支持的压缩算法
  set io.compression.codecs;
  
  查看 hive的输出是否开启压缩
  set hive.exec.compress.output;
  
  查看当前hive 使用的压缩算法
  set mapreduce.output.fileoutputformat.compress.codec

数据倾斜

什么是数据倾斜

大数据是分布式计算,数据倾斜就是大量的数据都分布到了一个任务上计算,导致出现长尾问题。

导致数据倾斜的部分情况 以及 处理方式

  1: join的字段之中null值非常多
      处理方式:
         1: 过滤null2: 对null值赋予随机值
  2: join的字段 类型不一样
      处理方式:
        在join的时候,使用cast 进行强制数据类型转换
  3: 文件过大,使用不可切割的压缩文件导致的
      处理方式:
         选择可切割的压缩文件算法
  4: 使用group by 引发的数据倾斜
     处理方式:
        开启参数 开启参数 hive.groupby.skewindata

数据倾斜的处理方式

 1: 可以尝试这样设置参数 set hive.groupby.skewindata=true

 备注:其实对于数据倾斜问题 主要是找到哪里的数据倾斜了,然后具体问题具体处理。
   如果是两个表进行join,join的字段之中有太多的null,那么可以将null值多的字段的null值进行补全,然后打散。
 

参数 hive.groupby.skewindata 背后的实现原理

  开启该配置会将作业拆解成两个作业,第一个作业会尽可能将Map的数据平均分配到Reduce阶段,并在这个阶段实现数据的预聚合,以减少第二个作业处理的数据量;第二个作业在第一个作业处理的数据基础上进行结果的聚合。
  
  注意:对于需要全局计算的统计,这个参数无法解决数据倾斜的问题。

小文件

小文件来源

1: 本身表格之中存储的数据文件很小
2: reduce 任务输出的是小文件

小文件处理

  对于reduce任务输出小文件的问题,
  开启reduce输出合并
   参数 hive.merge.mapredfiles 设置为true 
   hive.merge.smallfiles.avgsize // 默认为16MB,如果不是partitioned table的话,输出table文件的平均大小小于这个值,启动merge job,如果是partitioned table,则分别计算每个partition下文件平均大小,只merge平均大小小于这个值的partition。这个值只有当hive.merge.mapfiles或hive.merge.mapredfiles设定为true时,才有效。
   
  对于表格之中本身存储的数据文件很小的问题 
    可以使用 insert overwrite + distribute by的语法,将数据覆盖一遍。
    
   
  hive的 的 concatenate 命令 可以自动合并小文件
  注意:
    1、concatenate 命令只支持 RCFILE 和 ORC 文件类型。  
    2、使用 concatenate 命令合并小文件时不能指定合并后的文件数量,但可以多次执行该命令。

hive 函数

hive函数类型 UDF UDTF UDAF

UDF: 输入一行,返回一行
UDTF: 输入多行,返回一行
UDTAF: 输入一行,返回多行

部分hive内置函数介绍

UDF

开窗函数

备注:row_number,rank,dese_rank, 三个函数的关注点在于,值相同的记录,返回的顺序是否会重复,以及排序的顺序是否会跳跃

row_numer()

值相同,返回的记录顺序不会重复,顺序不会跳跃

rank()

值相同,返回的记录顺序会重复,顺序会跳跃

dense_rank

值相同,返回的记录顺序会重复,顺序不会跳跃

first_value() // 求出开窗分区的第一个值
last_value() // 求出开窗分区的最后的值
聚合函数应用于开窗
sum() 求和
avg() 求平均值
max() 求最大值
min() 求最小值
count() 求数目
lag() 取出分区的前n行数据
lead() 取出分区的后n行数据

split

split // 字符串切割函数

coalesce

coalesce(T v1, T v2, …) 返回参数中的第一个非空值;如果所有值都为 NULL,那么返回NULL。

json相关

get_json_object
使用例子:
  get_json_object 函数第一个参数填写`json`对象变量,第二个参数使用`$`表示json变量标识,然后用 . 或 [] 读取对象或数组

时间相关

image.png

字符串日期时间转 日期 to_date
例子:to_date('2015-04-02 13:34:12')
日期类型 转 时间字符串 date_format
获取当前的时间戳 unix_timestamp
  unix_timestamp
转化unix时间戳 到 当前时区的时间 from_unixtime
 from_unixtime

UDTF:

collect_list // 不会去重

UDAF

explode

explode的入参是一个数组,和测试图结合使用

posexplode

针对 多列 进行explode的场景而产生的函数。 

业务分析思考

求连续

 连续的话 是一个等差数列,所以一个等差数列 减去 另一个等差数列,最后得到的结果是一致的。
 所以使用开窗函数 row_numer()增加一列等差数列,然后用另一列去剪去这一列,得到计算的结果,如果每一行的此列的取值结果都是相同的,那么就是连续的。

会话分组 (以用户的操作时间小于60秒作为一个会话窗口)

假设数据记录的格式为 
  id  时间戳 
  
实现的思路就是
   首先使用 lag 进行开窗,对每行增加一列,列是之前的记录的时间,对查询的结果 使用 sum 进行开窗,类似 sum(if(diff > 60,1, 0)),新增一列 分组的标志。

间隔连续 (求出每个用户的最大的连续登录的天数)

间隔连续,就是 连续的过程之中 允许间隔,只要在间隔范围内,也算是连续的。

解决的思路:
  使用 lag + 开窗函数,增加一列,是前一天的时间,
  对查询的结果 使用 sum + 开窗函数 设置会话分组的标志,
  然后对会话分组进行聚合,求出连续的天数。

hive 优化思路

 1: 分表 
   合理利用中间结果集,重视查过就丢的资源浪费。
 2: join表的时候 首先进行 where过滤 更好(谓词下推)。
 3: 合理控制map的数目  reduce 的任务数。

hive 部分参数介绍

控制map任务数的方式:
    控制map数目的方式 可以是通过合并小文件,来减少map的数目。

相关的配置参数:

并行计算:
  hive.exec.parallel = true 

fetch抓取:
hive.fetch.task.conversion //该属性修改为more以后,在全局查找、字段查找、limit查找等都不走mapreduce


map相关:
  hive.merge.mapfiles=true //设置在map 阶段进行文件合并
  hive.map.aggr // map端进行聚合,默认的取值为true


reduce相关:
  mapreduce.reduce.memory.mb // reduce的内存大小
hive.merge.mapredfiles=true // 设置在mapred结束的时候 合并小文件 默认是false;

hive.merge.smallfiles.avgsize // 默认为16MB,如果不是partitioned table的话,输出table文件的平均大小小于这个值,启动merge job,如果是partitioned table,则分别计算每个partition下文件平均大小,只merge平均大小小于这个值的partition。这个值只有当hive.merge.mapfiles或hive.merge.mapredfiles设定为true时,才有效。

hive.merge.size.per.task // hive小文件合并之后 文件的最大的大小。