Hive体系结构

Hive是一种建立在Hadoop文件系统上的数据仓库架构,并对存储在HDFS中的数据进行分析和管理。

一.如何来分析和管理数据:

Hive定义了一种类似SQL的查询语言,被称为HQL,对于熟悉SQL的用户可以直接利用Hive来查询数据。同时,这个语言也允许熟悉 MapReduce 开发者们开发自定义的mappers和reducers来处理内建的mappers和reducers无法完成的复杂的分析工作。Hive可以允许用户编写自己定义的函数UDF,来在查询中使用。Hive中有3种UDF:User Defined Functions(UDF)、User Defined Aggregation Functions(UDAF)、User Defined Table Generating Functions(UDTF)。

二.常见的应用场景:

(1)日志分析:大部分互联网公司使用hive进行日志分析,包括百度、淘宝等。
①统计网站一个时间段内的pv、uv
②多维度数据分析
(2)海量结构化数据离线分析

这里写图片描述

三.Hive架构与基本组成

1.组件:
这里写图片描述

① Metastore-元存储:存储“系统目录以及关于表、列、分区等的元数据”的组件,可以通过thrift接口查询得到,由于需要快速的提供到编译器中,所以使用RDBMS(关系数据库管理系统)。
②Driver-驱动: 控制 HiveQL 生命周期的组件,当 HiveQL 查询穿过 Hive时。该驱动管理着会话句柄以及任何会话的统计。
③Hiveserver-Hive服务器:一个提供“健壮的接口(thrift interface )、JDBC/ODBC 服务器以及提供一种整合 Hive 和其它应用的”组件。
④Query Compiler-查询编译器:是一个组件,将HiveQL编译成有向无环图(directed acyclic graph, DAG)形式的map/reduce任务。
⑤Execution Engine-执行引擎:依相依性顺序(dependency order)执行由编译器产生的任务。
⑥客户端组件 -类似命令行接口CLI(Command Line Interface), web UI 以及JDBC/ODBC驱动。包含了正反序列化(SerDe)以及对象观察器(ObjectInspector)接口的可扩展接口,类似于前述用户定义函数 UDF (User Defined Function)以及用户定义聚合函数UDAF(User Defined AggregateFunction)接口,允许用户定义自己的列函数。

四.执行的过程:

HiveQL通过CLI/web UI或者thrift 、 odbc 或 jdbc接口的外部接口提交,经过complier编译器,运用Metastore中的云数据进行类型检测和语法分析,生成一个逻辑方案(logical plan),然后通过简单的优化处理,产生一个以有向无环图DAG数据结构形式展现的map-reduce任务。

五.执行原理

Hive编译器将一个Hive QL转换操作符。

①操作符Operator

Hive最小的处理单元,每个操作符代表HDFS的一个操作或者一道MapReduce作业。
所有的操作构成了Operator图,hive基于这些图关系来处理诸如limit, group by, join等操作。
这里写图片描述

操作符:
这里写图片描述

②Hive编译器
这里写图片描述

流程
这里写图片描述
这里写图片描述
parse   sa    lpg       lo        ppg       po
hql——->AST——>QB—–>OP TREE——->OP TREE——->task tree——->task tree
1).解析(parse)-anlr解析其生成语法树AST(hibernate也是这个):将HQL转化为抽象语法树AST
2).类型检查和语法分析(type checking and semantic analysis):将抽象语法树转换此查询块(query block tree),并将查询块转换成逻辑查询计划(logic plan Generator);
3).优化(optimization):重写查询计划(logical optimizer)–>将逻辑查询计划转成物理计划(physical plan generator)–>选择最佳的join策略(physical optimizer)

六.三种模式连接到数据库

①单用户模式,连接到一个In-memory 的数据库Derby,一般用于Unit Test。
这里写图片描述

②多用户模式。通过网络连接到一个数据库中,是最经常使用到的模式。
这里写图片描述

③远程服务器模式。用于非Java客户端访问元数据库,在服务器端启动MetaStoreServer,客户端利用Thrift协议通过MetaStoreServer访问元数据库。
这里写图片描述

六.数据模型

①Hive数据库
类似传统数据库的DataBase,在第三方数据库里实际是一张表。简单示例命令行 hive > create database test_database;

②内部表
Hive的内部表与数据库中的Table在概念上是类似。每一个Table在Hive中都有一个相应的目录存储数据。例如一个表pvs,它在HDFS中的路径为/wh/pvs,其中wh是在hive-site.xml中由${hive.metastore.warehouse.dir} 指定的数据仓库的目录,所有的Table数据(不包括External Table)都保存在这个目录中。删除表时,元数据与数据都会被删除。
内部表简单示例:
创建数据文件:test_inner_table.txt
创建表:create table test_inner_table (key string)
加载数据:LOAD DATA LOCAL INPATH ‘filepath’ INTO TABLE test_inner_table
查看数据:select * from test_inner_table; select count(*) from test_inner_table
删除表:drop table test_inner_table

③外部表
外部表指向已经在HDFS中存在的数据,可以创建Partition。它和内部表在元数据的组织上是相同的,而实际数据的存储则有较大的差异。内部表的创建过程和数据加载过程这两个过程可以分别独立完成,也可以在同一个语句中完成,在加载数据的过程中,实际数据会被移动到数据仓库目录中;之后对数据对访问将会直接在数据仓库目录中完成。删除表时,表中的数据和元数据将会被同时删除。而外部表只有一个过程,加载数据和创建表同时完成(CREATE EXTERNAL TABLE ……LOCATION),实际数据是存储在LOCATION后面指定的 HDFS 路径中,并不会移动到数据仓库目录中。当删除一个External Table时,仅删除该链接。
外部表简单示例:
创建数据文件:test_external_table.txt
创建表:create external table test_external_table (key string)
加载数据:LOAD DATA INPATH ‘filepath’ INTO TABLE test_inner_table
查看数据:select * from test_external_table; •select count(*) from test_external_table
删除表:drop table test_external_table

④分区
Partition对应于数据库中的Partition列的密集索引,但是Hive中Partition的组织方式和数据库中的很不相同。在Hive中,表中的一个Partition对应于表下的一个目录,所有的Partition的数据都存储在对应的目录中。例如pvs表中包含ds和city两个Partition,则对应于ds = 20090801, ctry = US 的HDFS子目录为/wh/pvs/ds=20090801/ctry=US;对应于 ds = 20090801, ctry = CA 的HDFS子目录为/wh/pvs/ds=20090801/ctry=CA。
分区表简单示例:
创建数据文件:test_partition_table.txt
创建表:create table test_partition_table (key string) partitioned by (dt string)
加载数据:LOAD DATA INPATH ‘filepath’ INTO TABLE test_partition_table partition (dt=‘2006’)
查看数据:select * from test_partition_table; select count(*) from test_partition_table
删除表:drop table test_partition_table

⑤桶
Buckets是将表的列通过Hash算法进一步分解成不同的文件存储。它对指定列计算hash,根据hash值切分数据,目的是为了并行,每一个Bucket对应一个文件。例如将user列分散至32个bucket,首先对user列的值计算hash,对应hash值为0的HDFS目录为/wh/pvs/ds=20090801/ctry=US/part-00000;hash值为20的HDFS目录为/wh/pvs/ds=20090801/ctry=US/part-00020。如果想应用很多的Map任务这样是不错的选择。
桶的简单示例:
创建数据文件:test_bucket_table.txt
创建表:create table test_bucket_table (key string) clustered by (key) into 20 buckets
加载数据:LOAD DATA INPATH ‘filepath’ INTO TABLE test_bucket_table
查看数据:select * from test_bucket_table; set hive.enforce.bucketing = true;

⑥Hive的视图
视图与传统数据库的视图类似。视图是只读的,它基于的基本表,如果改变,数据增加不会影响视图的呈现;如果删除,会出现问题。•如果不指定视图的列,会根据select语句后的生成。
示例:create view test_view as select * from test

七.Hive和数据库的异同
这里写图片描述

(1)查询语言。由于 SQL 被广泛的应用在数据仓库中,因此专门针对Hive的特性设计了类SQL的查询语言HQL。

(2)数据存储位置。
Hive是建立在Hadoop之上的,所以Hive的数据都是存储在HDFS中的。而数据库则可以将数据保存在块设备或者本地文件系统中。

(3)数据格式。
Hive中没有定义专门的数据格式,数据格式可以由用户指定,用户定义数据格式需要指定三个属性:列分隔符(通常为空格、”\t”、”\x001″)、行分隔符(”\n”)以及读取文件数据的方法(Hive中默认有三个文件格式TextFile,SequenceFile以及RCFile)。由于在加载数据的过程中,不需要从用户数据格式到Hive定义的数据格式的转换,因此,
Hive在加载的过程中不会对数据本身进行任何修改,而只是将数据内容复制或者移动到相应的HDFS目录中。
而在数据库中,不同的数据库有不同的存储引擎,定义了自己的数据格式。所有数据都会按照一定的组织存储,因此,数据库加载数据的过程会比较耗时。

(4)数据更新。由于Hive是针对数据仓库应用设计的,而数据仓库的内容是读多写少的。因此,Hive中不支持对数据的改写和添加,所有的数据都是在加载的时候中确定好的。而数据库中的数据通常是需要经常进行修改的,因此可以使用INSERT INTO … VALUES添加数据,使用UPDATE … SET修改数据。

(5)索引。
Hive在加载数据的过程中不会对数据进行任何处理,甚至不会对数据进行扫描,因此也没有对数据中的某些Key建立索引。Hive要访问数据中满足条件的特定值时,需要暴力扫描整个数据,因此访问延迟较高。由于MapReduce的引入, Hive可以并行访问数据,因此即使没有索引,对于大数据量的访问,Hive仍然可以体现出优势。数据库中,通常会针对一个或者几个列建立索引,因此对于少量的特定条件的数据的访问,数据库可以有很高的效率,较低的延迟。由于数据的访问延迟较高,决定了Hive不适合在线数据查询。

(6)执行。
Hive中大多数查询的执行是通过Hadoop提供的MapReduce来实现的(类似select * from tbl的查询不需要MapReduce)。而数据库通常有自己的执行引擎。

(7)执行延迟。
Hive在查询数据的时候,由于没有索引,需要扫描整个表,因此延迟较高。另外一个导致Hive执行延迟高的因素是MapReduce框架。由于MapReduce本身具有较高的延迟,因此在利用MapReduce执行Hive查询时,也会有较高的延迟。相对的,数据库的执行延迟较低。当然,这个低是有条件的,即数据规模较小,当数据规模大到超过数据库的处理能力的时候,Hive的并行计算显然能体现出优势。

(8)可扩展性。
由于Hive是建立在Hadoop之上的,因此Hive的可扩展性是和Hadoop的可扩展性是一致的(世界上最大的Hadoop集群在Yahoo!,2009年的规模在4000台节点左右)。而数据库由于ACID语义的严格限制,扩展行非常有限。目前最先进的并行数据库Oracle在理论上的扩展能力也只有100台左右。

(9)数据规模。由于Hive建立在集群上并可以利用MapReduce进行并行计算,因此可以支持很大规模的数据;对应的,数据库可以支持的数据规模较小。

八.使用HIVE注意点

(1)字符集
Hadoop和Hive都是用UTF-8编码的,所以, 所有中文必须是UTF-8编码, 才能正常使用。
备注:中文数据load到表里面,,如果字符集不同,很有可能全是乱码需要做转码的,但是hive本身没有函数来做这个。
(2)压缩
hive.exec.compress.output 这个参数,默认是false,但是很多时候貌似要单独显式设置一遍,否则会对结果做压缩的,如果你的这个文件后面还要在hadoop下直接操作,那么就不能压缩了。
(3)count(distinct)
当前的Hive不支持在一条查询语句中有多Distinct。如果要在Hive查询语句中实现多Distinct,需要使用至少n+1条查询语句(n为distinct的数目),前n条查询分别对n个列去重,最后一条查询语句对n个去重之后的列做Join操作,得到最终结果。
(4)JOIN
只支持等值连接
(5)DML操作
只支持INSERT/LOAD操作,无UPDATE和DELTE
(6)HAVING
不支持HAVING操作。如果需要这个功能要嵌套一个子查询用where限制
(7)子查询
Hive不支持where子句中的子查询
(8)Join中处理null值的语义区别
SQL标准中,任何对null的操作(数值比较,字符串操作等)结果都为null。Hive对null值处理的逻辑和标准基本一致,除了Join时的特殊逻辑。这里的特殊逻辑指的是,Hive的Join中,作为Join key的字段比较,null=null是有意义的,且返回值为true。
(9)分号字符
分号是SQL语句结束标记,在HiveQL中也是,但是在HiveQL中,对分号的识别没有那么智慧,例如:
select concat(cookie_id,concat(‘;’,’zoo’)) from c02_clickstat_fatdt1 limit 2;
FAILED: Parse Error: line 0:-1 cannot recognize input ‘’ in function specification
可以推断,Hive解析语句的时候,只要遇到分号就认为语句结束,而无论是否用引号包含起来。
解决的办法是,使用分号的八进制的ASCII码进行转义,那么上述语句应写成:
select concat(cookie_id,concat(‘\073’,’zoo’)) from c02_clickstat_fatdt1 limit 2;
为什么是八进制ASCII码?我尝试用十六进制的ASCII码,但Hive会将其视为字符串处理并未转义,好像仅支持八进制,原因不详。这个规则也适用于其他非SELECT语句,如CREATE TABLE中需要定义分隔符,那么对不可见字符做分隔符就需要用八进制的ASCII码来转义。
(10)Insert
根据语法Insert必须加“OVERWRITE”关键字,也就是说每一次插入都是一次重写。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值