Hive介绍

Hive是什么?

简单来说,hive就是在Hadoop的基础之上,加了一层Sql的接口,内部可以将hive的类SQL语句翻译成MapReduce程序去Hadoop集群上运行,所以HIve的底层就是MapReduce这也是区别与关系型SQL语句的地方,这样带来的好处就是使得数据开发人员和分析人员,很方便的使用SQL来完成海量数据的统计和分析,而不是用一些高级语言去开发mapreduce程序,(说白了就是为了方便更多人群使用,相比之下SQL更符合人类的思维)
可以把hive当成一个数据库,他也具备传统数据库的数据单元,数据库表但实际上就是hadoop的一个工具,hive是基于Mapreduce的一个上层数据分析框架。
专业解释:hive是基于hadoop的数据仓库工具,可以将结构化的数据文件映射成一张数据表,并提供简单的SQL查询功能。优点就是学习成本低。

Hive的应用场景?

由于hive的底层是mapreduce,其特点是具有较高的延迟,并且在作业提交和调度的时候需要大量的开销,因此hive并不支持低延迟的查询与应用,Hive的最佳使用场合是大量数据聚集的批处理作业,例如网络离线日志分析等。

设计特征?

Hive的数据库其实就是hadoop dfs上的一个文件目录。Hive在加载数据的过程中不会对数据进行任何的修改,只是将数据移动到HDFS中hive设定的目录下,因此,hive不支持数据的改写和添加,所有的数据都是在加载的时候确定的,Hive的设计特点如下:
1.支持索引,加快数据查询
2.不同的存储类型,例如纯文本和Hbase中的文件。
3.将元数据保存在关系型数据库中,大大减少了查询过程中执行语义检查的时间。
4.可以直接使用存储在Hadoop文件系统中的数据
5.内置大量的函数,如果内置函数不能完成用户需求,支持用户自定义UDF函数来完成具体的实现

Hive的架构?

  1. 用户接口

    用户接口主要有三个:CLI,Client和WebUI。最常用的是Cli,Cli启动的时候.会同时启动一个Hive副本。Client是Hive的客户端,用户连接自hiveServer .在启动的时候需要指出HiveServer所在节点的,并且在该节点启动hiveServer 。

  2. 元数据存储

    Hive将元数据存储在数据库中,如Mysql,derby.hive中的元数据包括表名,表的列和分区及其属性,表的属性(是否为外部表),表的数据所在的目录(通常把元数据保存在Mysql中,derby是hive默认的元数据存储的数据库,其特点就是:基于内存 而且非常小,所以通常将元数据保存在mysql中)
    解释器、编译器、优化器、执行器
    解释器:检查HQL 是否有语法语义错误
    编译器:将sql语句翻译成mapreduce程序
    优化器:优化mapreduce 找出最优的job
    执行器:调用hadoop执行job任务

  3. Hadoop

    Hive的数据存储在HDFS上。

Hive的基本操作?

  • 创建外部表 external
Create external table if not exists test(
Name string,
Age int)
Row format delimited fields terminated by \t 
Stored by textfile;
  • 创建内部表 managed_table
Create table if not exists test(
Name string,
Age int)
Row format delimited fields terminated by \t 
Stored by textfile;
  • 将结果集保存到新建的表中
Created table test as select * from info;
  • 复制一个已有的表结构
Created table user1 like user;
  • 数据的四种加载方式
  1. 本地到Hive表:

    load data local inpath "/home/tom/demo1.txt" into table info;
    
  2. Hdfs到hive表:当不写本地的时候就是hdfs目录

    load data inpath "/home/tom/demo1.txt" into table info;
    
  3. 结果集:

    Insert into table info select * from info 字段数要相同
    
  4. 创建表时指定一个hdfs目录:

    Location ‘hdfs://...’
    
  • 数据导出的四种方式
  1. 导出到本地文件系统:

    Insert overwrite local directory ‘home/a’select * from a;
    
  2. 导出到hdfs目录:

    Insert overwrite directory ‘/a’select * from user1;
    
  3. 指定分隔符:

    Insert overwrite local directory ‘/home/a’select * from info row 	format delimited fields terminated by ‘\t’
    
  4. 从本地和HDFS上加载数据有什么不同?
    加载数据到表中的将HDFS中的数据文件指向hive时,是将HDFS数据文件移动到hive表的路径目录下。
    加载本地文件时,是将本地文件拷贝到HDFS上的hive库的指定表的目录下,而不是移动。

  • 分区表
    事实上,分区表就是在表的目录下创建了子目录

    create table if not exists user2 (
    qqno string,
    sex string,
    height float,
    heavy float)
    partitioned by (age int )
    row format delimited fields 
    terminated by ' '
    stored as textfile;
    

注意:表中没有真是的分区字段,分区字段在表中是伪列,而mysql分区是将表中的字段拿来直接作为分区字段。
同样往指定分区加载数据也有四种方式:要指明那个分区

load data local inpath'/home/a' into table 表名 partition(sex="man");

常见的操作:
添加分区 alter table user1 add partition(sex=”ss”);
删除分区 alter table user1 drop partition(sex=”ss”);
重命名分区 alter table user1 partition(sex=”ss”) rename to partition(sex=”x”);

其实这种添加数据是就指定哪个分区的方式就是静态分区,那么hive里面还有另一种分区就是 动态分区:
Hive默认的是静态分区 设置动态分区的时候需要以下设置:
set hive.exec.dynamic.partition=true; 表示开启动态分区功能
set hive.exec.dynamic.partition.mode=nonstrict;
表示所有分区都是动态的没有限制
set hive.exec.max.dynamic.partitions.pernode=100;
最大动态分区个数
需要注意的问题:当分区为静态分区的时候,分区字段在表中是伪列,在使用就结果集的进行插入分区数据的时候,需要指定分区,但分区字段不能出现在子查询里面。动态分区时,表中的数据是真是存在的并不是伪列,在使用结果集进行插入的时候,子查询中必须有该字段
分区的目的,快速查询,适用于增量表,可以用来存放每天的数据
当分区数 和分区字段不确定时,使用动态分区

  • 创建分区的目的?

    创建分区是为了实现快速查询,在hive中的单个表的数据量越来越大时,在hive的select查询机制一般是会扫描整个表内容,会消耗很多时间,做没必要的工作,而表在创建分区之后查询时直接指向hive的某个分区目录所以查询快。

  • 分桶表

比分区更加细粒化,可以用来抽样查询

create table bucketed_users(id int ,name string) clustered by (id) sorted by (name) into 4 buckets;

其原理就是:将分区字端id对应的值然后对桶的个数求余决定该条记录存放到那个桶中。
查看分桶的数据
分桶的数据加载方式:只能是insert into select 的方式动态的加载数据。
语法:TABLESAMPLE(BUCKET x OUT OF y)
y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。例如,table总共分了64份,当y=32时,抽取(64/32=)2个bucket的数据,当y=128时,抽取(64/128=)1/2个bucket的数据。x表示从哪个bucket开始抽取。例如,table总bucket数为32,tablesample(bucket 3 out of 16),表示总共抽取(32/16=)2个bucket的数据,分别为第3个bucket和第(3+16=)19个bucket的数据。

  • 分桶在hive中的作用?

(1)获得更高的查询处理效率。桶为表加上了额外的结构,hive在处理有些查询时能利用这个结构。比如连接两个相同列上划分了桶的表,可以使用map端连接(map-sido-join)高效的实现。比如join操作对于join操作两个表有一个相同的列,如果对这两个表都进行了桶操作,那么将保存相同列值的桶进行join操作就可以,大大减少join的数据量。
(2)对数据取样更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。
分桶和分区异同?
(1)分区的字段是表中没有的字段,只是强加一个标记(分区目录名),而分桶的字段必须是表中的字段。
(2)分区表查询出来的包括伪列(分区目录名),而分桶表查询出来的数据都是真实数据
(3)分区是在表的基础上根据数据的特征进行归列统一,将有共同特点的数据存放在一个分区中(目录中),分桶是用将分区字段id的hash值和分桶数据的取模数作为依据进行数据的保存的。
Hive的数据类型

  • 基本类型:

Smallint Int bigint boolean
Float double String timestamp
不支持:char byte long short

  • 复杂类型:

1.array:
array类型是由一系列相同类型的元素组成,这些元素可以和java语言的数组一样通过下表访问,
建表:
create table if not exists arrayT(
id int ,
province string,
city array)
row format delimited fields
terminated by ‘\t’
collection items terminated by ‘,’ stored as textfile;
源数据:
1 beijing daxing,haidian,fengtai,chaoyang
2 hebei shijiazhuang,langfang,cangzhou,zhangjiakou
3 shanxi taiyuan,linfen,datong,xinzhou,lvliang
加载数据:
load data local inpath’/home/array’into table arrayt;
结果:
1 beijing [“daxing”,“haidian”,“fengtai”,“chaoyang”]
2 hebei [“shijiazhuang”,“langfang”,“cangzhou”,“zhangjiakou”]
3 shanxi [“taiyuan”,“linfen”,“datong”,“xinzhou”,“lvliang”]

按下标访问:
select city[0] from arrayt;
结果:
daxing
shijiazhuang
taiyuan
<>当hive中出现数组越界的时候,不报错,当没有数据时 用null代替
<
>row format delimited fields terminated by ‘\t’ 和
collection items terminated by ‘,’ 不能调换位置
2.Map集合: map包含key,value 键值对,可以通过key来访问值

建表:
create table if not exists mapt(
name string,
grade map<string,int>
)
row format delimited fields terminated by ‘\t’
collection items terminated by ‘,’
map keys terminated by ‘:’
stored as textfile;
数据:
xiaohong chinses:65,math:80,english:70
xiaohei chinses:90,math:90,english:80
xiaohei chinses:98,math:30,english:20
加载:
load data local inpath’/home/mapt’ into table mapt;
结果:
xiaohong {“chinses”:65,“math”:80,“english”:70}
xiaohei {“chinses”:90,“math”:90,“english”:80}
xiaohei {“chinses”:98,“math”:30,“english”:20}
通过key访问value:
select grade[‘math’] from mapt where name=‘xiaohong’;
结果:
803.struct
结构体:这些元素可以通过"点语法"的方式来得到所需要的元素
重点是可以包含不同类型的元素
建表:
create table if not exists structt (
id string,
info struct<name:string,age:int ,sex:string>)
row format delimited fields
terminated by ‘\t’
collection items terminated by ‘,’ ;
源数据:
1 tom,10,men
2 jack,20,men
3 marry,30,women

加载数据:
load data local inpath’/home/struct’ into table structt;
结果:
1 {“name”:“tom”,“age”:10,“sex”:“men”}
2 {“name”:“jack”,“age”:20,“sex”:“men”}
3 {“name”:“marry”,“age”:30,“sex”:“women”}
三者不能组合使用

  • Hive中 默认的分隔符:

    ^A \001 默认的列分隔符
    ^B \002 相当于:’,’
    ^C \003 相当于:’:’
    分隔符应该从大到小 先分割行,然后分割字段 再分割key.value

  • Hive的索引

概念:
索引是标准的数据库技术,hive-0.7版本之后开始支持索引 没有传统数据库的好
优缺点:
优点:优化查询和检索性能提升,有索引将不会对全表进行暴力扫描
缺点:存储数据会耗时和内存
我用过的:

create index index_tb2 on table tb2(qqno) as 'compact' with deferred rebuild;create index bm_tb on table tb2(qqno) as 'Bitmap' with deferred rebuild;

紧凑索引存储每个值的HDFS块号,而不是存储文件内偏移量,因此存储不会占用过多的磁盘空间,而且对于值被聚簇(clustered)存储于相近行的情况,索引任然有效。
位图索引使用压缩的位集合(bitset)来高效存储具有某个特殊值的行。这种索引一般适合于具有较少取值可能(low-cardinality)的列。

Hive的UDF

需要自定义类,然后继承UDF 然后在方法envluate()方法里面实现具体的业务逻辑,打包上传到linux(以免出错打包成RunningJar)

  • 创建临时函数:

    1.add jar /udf/xxx.jar
    2.Create temporary function mytest as ‘包名.类名’
    3.显示UDF函数 show functions like mytest
    4.删除临时函数 drop temporaray function mytest;

  • 创建永久函数:

    1.把jar包上传至hdfs目录 path
    2.Create function mytest as ‘包名.类名’using jar path/xxx.jar

  • Hive的文件存储格式

    Textfile 行存储
    存储空间消耗比较大,并且压缩的text 无法分割和合并 查询的效率最低,可以直接存储,加载数据的速度最高
    Sequencefile 行存储
    存储空间消耗最大,压缩的文件可以分割和合并 查询效率高,需要通过text文件转化来加载
    不能load加载数据
    rcfile 列存储
    存储空间最小,查询的效率最高 ,需要通过text文件转化来加载,加载的速度最低
    不能load加载数据,使用插入形式添加数据
    orcfile 列存储
    是rcfile的升级版,运用ORC File可以提高Hive的读、写以及处理数据的性能。

Hive的执行流程

1.ExecutoryQuery:hive界面通过命令行或webUI将查询发送到Driver端来执行
2.GetPlan:Driver通过调用编译器解析query语句。验证query是否有语法语义错误,根据query语句形成查询计划,或者查询条件
3.GetMetaStore编译器将元数据请求发送给Metastore
4.SendMetaStore:Metastore将元数据作为响应发送给编译器
5.SendPlan:编译器向Driver发送计划,到这里查询解释和编译已经完成了
6.Exetutorplan:Driver将执行计划发送到执行引擎。
7.Executor job :Hadoop内部执行的是mapreduce程序,任务执行引擎发送一个任务到ResourceManager 资源管理器分配任务到任务节点上,任务节点上开始执行mapreduce程序
8.metaDataOps:在执行引擎发送任务的同时,对hive的元数据进行操作
9.FetchResult:执行引擎接收任务节点的数据
10.Send result:执行引擎发送这些合成值到Driver
11.Send result :Driver将最终结果返回到客户端

  • Hive的执行流程!!!
    在这里插入图片描述
    用户提交查询等任务给driver。此时driver的解释器会判断HQL语句的语法格式的错误。如果HQL语句在语法格式上没有错误,complier编译器就会通过getplan的方式将driver中的plan任务获取到,该plan任务就是HQL语句,同时complier会根据用户任务去metastore获取需要的hive元数据信息。Complier获取到metastore元数据信息,对plan进行编译。首先将HQL语句转成语法树,然后再将语法树转成查询块,再将查询快转成逻辑的查询计划,重写逻辑计划,将逻辑计划转成物理计划(mapreduce)。
    Complier(编译器)将mapreduce交给optimizer进行最后的最佳策略的选择。然后optimizer将最终的mapreduce物理计划返还给driver,driver再将mapreduce计划转交给Executor去执行,再次熊metastore获取元数据信息之后,提交给jobTracker或者resourceManager去执行任务。任务直接会读取HDFS的文件进行相应的操作。
    最后获取MapReduce执行的结果,并返还给hive的driver客户端。

常见问题:

1.hive与sql语句的区别?
相同点:都有类似的语法
不同点:hive的底层是由mapreduce执行,而Sql底层是由自带的Executor执行
有些语法不同 hive支持from()select 结构的sql语句,这样做的好处是只做一次全表扫描,性能高,如果放在后面的话,就是没查询一次就得扫描一次
2.Hive数据库与mysql语句的区别?
1.模式:Hive是读时模式,mysql是写时模式 具体体现:mysql等关系型数据库在添加数据的时候就检查数据格式,如果格式不匹配,会出现异常; Hive在读的时候才进行检查数据格式,不匹配则返回null,在写数据的时候不进行数据检测
2.数据存储:hive的数据存储在hadoop dfs 分布式文件系统上,关系型数据库将数据存储在本地系统
3.索引:hive0.7之后支持索引 之前没有
数据库中通常会对一个或者几个列创建索引,可以提高效率
4.延迟:hive的延迟较高 因为是mapreduce; mysql延迟较低
5.吞吐量,hive的吞吐量非常大,数据库这一点是劣势
6.HQL暂时不支持使用in,不支持where子句中的子查询,可以使用left semi join 来实现in。可以使用left outer join来实现not in。

3.外部表和内部表的区别?
A)在创建内部表的时候,会将数据移动到数据仓库指向的路径。若创建外部表,只是记录数据的地址,不对数据进行任何的改变
B)在删除内部表的时候,其元数据和源数据都会被删除,而外部表,只是删除元数据,并不会删除数据。
4.SQL的执行流程
·SQL在执行过程:先将sql语句转换为解析前的逻辑计划,在进一步解析成更详细的逻辑计划,由于解析后的逻辑计划,会生成多个计划,这需要通过优化器来选择最优的逻辑计划进行优化,生成优化后的逻辑计划,最后生成物理计划,更加具体的物理计划,最后由Executor执行进行拉去数据
· Hive:将SQL转换成抽象语法树(Parser)->将抽象语法树转换成查询块(Semantic Analyzer)-> 将查询块转换成逻辑查询计划(Logic Plan Generator)-> 重写逻辑查询计划(LogicalOptimizer)-> 将逻辑计划转成物理计划M/R jobs ( Physical Plan Generator)-> 选择最佳的Join策略(PhysicalOptimizer)。

Hive配置优化
参数层面优化
通常我们通过设置某些参数来控制mappers reducers个数
例如设置mapred.min.split.size的大小从而控制mappers数数据的最小分割单元大小
使用合并小文件方法
set Hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
Map端的聚合,减少Reduce处理负担:
sethive.map.aggr=true;
推测执行:
set mapred.map.tasks.speculative.execution=true;
推测执行:
Set hive.mapred.reduce.tasks.speculative.execution =true;
通常我们通过设置某些参数来合并小文件

查询优化:
1.Hive 在读数据的时候,可以只读取查询中所需要用到的列,而忽略其它列
2.可以在查询的过程中减少不必要的分区。
3.在编写带有 join 操作的代码语句时,应该将条目少的表/子查询放在 Join 操作符的左边。 因为在 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,载入条目较少的表 可以有效减少 OOM(out of memory)即内存溢出。
4.join查找操作中如果存在多个join,且所有参与join的表中其参与join的key都相同,则会将所有的join合并到一个mapred程序
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1) 在一个mapre程序中执行join
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2) 在两个mapred程序中执行join
5.MapJoin 的关键在于join操作中的某个表的数据量很小
SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a join b on a.key = b.key
6.用sum() groupby的方式来替换count(distinct)
7.排序优化
Order by实现全局排序,一个reduce实现,效率低
SortBy 实现部分有序,单个reduce输出的结果是有序的,效率高,通常和
Distribute by 关键字一起使用(distribute by 关键字 可以指定map到reduce端的分发key)
Cluster by col1 等价于distributed by col1 sort by col1
select year, temperature
distribute by year
sort by year;
8.笛卡尔基默认使用一个reduce来完成,建议使用mapJOin如果数据符合的话
9.使用from在语句首位的方式。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值