Hive
Hive简介
Facebook为了解决海量日志数据的分析而开发了Hive,后来开源给了Apache软件基金会。
官网定义:
The Apache Hive ™ data warehouse software facilitates reading, writing, and managing large datasets residing in distributed storage using SQL.
Hive是一种用类SQL语句来协助读写、管理那些存储在分布式存储系统上大数据集的数据仓库软件。
Hive的几个特点
- Hive最大的特点是通过类SQL来分析大数据,而避免了写MapReduce程序来分析数据,这样使得分析数据更容易。
- 数据是存储在HDFS上的,Hive本身并不提供数据的存储功能
- Hive是将数据映射成数据库和一张张的表,库和表的元数据信息一般存在关系型数据库上(比如MySQL)。
- 数据存储方面:它能够存储很大的数据集,并且对数据完整性、格式要求并不严格。
- 数据处理方面:因为Hive语句最终会生成MapReduce任务去计算,所以不适用于实时计算的场景,它适用于离线分析。
Hive架构
image.png
Hive的底层存储
Hive的数据是存储在HDFS上的。Hive中的库和表可以看作是对HDFS上数据做的一个映射。所以Hive必须是运行在一个Hadoop集群上的。
Hive语句的执行过程
Hive中的执行器,是将最终要执行的MapReduce程序放到YARN上以一系列Job的方式去执行。
Hive的元数据存储
Hive的元数据是一般是存储在MySQL这种关系型数据库上的,Hive和MySQL之间通过MetaStore服务交互。
Hive重要概念
外部表和内部表
内部表(managed table)
- 默认创建的是内部表(managed table),存储位置在
hive.metastore.warehouse.dir
设置,默认位置是/user/hive/warehouse
。 - 导入数据的时候是将文件剪切(移动)到指定位置,即原有路径下文件不再存在
- 删除表的时候,数据和元数据都将被删除
- 默认创建的就是内部表
create table xxx (xx xxx)
外部表(external table)
- 外部表文件可以在外部系统上,只要有访问权限就可以
- 外部表导入文件时不移动文件,仅仅是添加一个metadata
- 删除外部表时原数据不会被删除
- 分辨外部表内部表可以使用
DESCRIBE FORMATTED table_name
命令查看 - 创建外部表命令添加一个external即可,即
create external table xxx (xxx)
- 外部表指向的数据发生变化的时候会自动更新,不用特殊处理
分区表和桶表
分区(partioned)
- 有些时候数据是有组织的,比方按日期/类型等分类,而查询数据的时候也经常只关心部分数据,比方说我只想查2017年8月8号,此时可以创建分区,查询具体某一天的数据时,不需要扫描全部目录,所以会明显优化性能
- 一个Hive表在HDFS上是有一个对应的目录来存储数据,普通表的数据直接存储在这个目录下,而分区表数据存储时,是再划分子目录来存储的
- 使用
partioned by (xxx)
来创建表的分区
分桶(clustered)
- 分桶是相对分区进行更细粒度的划分。分桶将整个数据内容安装某列属性值得hash值进行区分,按照取模结果对数据分桶。如取模结果相同的数据记录存放到一个文件。
- 桶表也是一种用于优化查询而设计的表类型。创建通表时,指定桶的个数、分桶的依据字段,hive就可以自动将数据分桶存储。查询时只需要遍历一个桶里的数据,或者遍历部分桶,这样就提高了查询效率。
具体说明分桶
- clustered by (user_id) sorted by(leads_id) into 10 buckets
- clustered by是指根据user_id的值进行哈希后模除分桶个数,根据得到的结果,确定这行数据分入哪个桶中,这样的分法,可以确保相同user_id的数据放入同一个桶中。
- sorted by 是指定桶中的数据以哪个字段进行排序,排序的好处是,在join操作时能获得很高的效率。
- into 10 buckets是指定一共分10个桶。
- 在HDFS上存储时,一个桶存入一个文件中,这样根据user_id进行查询时,可以快速确定数据存在于哪个桶中,而只遍历一个桶可以提供查询效率。
Hive文件格式
hive文件存储格式包括以下几类:
- TEXTFILE
- SEQUENCEFILE
- RCFILE
- ORCFILE(0.11以后出现)
其中TEXTFILE为默认格式,建表时不指定默认为这个格式,导入数据时会直接把数据文件拷贝到hdfs上不进行处理;SEQUENCEFILE,RCFILE,ORCFILE格式的表不能直接从本地文件导入数据,数据要先导入到textfile格式的表中, 然后再从表中用insert导入SequenceFile,RCFile,ORCFile表中。
列式存储和行式存储
首先我们看一下一张表的存储格式
image.png
行式存储
image.png
列式存储
image.png
列式存储和行式存储的比较
行式存储
优点:
- 相关的数据是保存在一起,比较符合面向对象的思维,因为一行数据就是一条记录
- 这种存储格式比较方便进行INSERT/UPDATE操作
缺点:
- 如果查询只涉及某几个列,它会把整行数据都读取出来,不能跳过不必要的列读取。当然数据比较少,一般没啥问题,如果数据量比较大就比较影响性能
- 由于每一行中,列的数据类型不一致,导致不容易获得一个极高的压缩比,也就是空间利用率不高
- 不是所有的列都适合作为索引
列式存储
优点:
- 查询时,只有涉及到的列才会被查询,不会把所有列都查询出来,即可以跳过不必要的列查询
- 高效的压缩率,不仅节省储存空间也节省计算内存和CPU
- 任何列都可以作为索引
缺点:
- INSERT/UPDATE很麻烦或者不方便
- 不适合扫描小量的数据
TEXTFILE
默认格式,数据不做压缩,磁盘开销大,数据解析开销大。
可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
SEQUENCEFILE
SequenceFile是Hadoop API提供的一种二进制文件支持,其具有使用方便、可分割、可压缩的特点。
SequenceFile支持三种压缩选择:NONE,RECORD,BLOCK。Record压缩率低,一般建议使用BLOCK压缩。
RCFILE
RCFILE是一种行列存储相结合的存储方式。首先,其将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。其次,块数据列式存储,有利于数据压缩和快速的列存取。
- RCFile保证同一的数据位于同一节点,因此元组重构代价较低(需要将分散的数据重新组织,比如一列数据散落在不同集群,查询的时候,需要将各个节点的数据重新组织;但是如果数据都在一个机器上,那就没有必要重新组织)
- RCFile通过列进行数据压缩,因为同一列都是相同的数据类型,所以压缩比比较好
- RCFile可以跳过不必要的列读取
从以上几点也可以看出它是兼顾了行式和列式存储的部分优点。
ORC File
ORCFile存储格式,就是Optimized RC File的缩写。意指优化的RCFile存储格式。
ORC File 和 RC File比较
- 每一个任务只输出单个文件,这样可以减少NameNode的负载
- 支持各种复杂的数据类型,比如datetime,decimal,以及复杂的struct,List,map等
- 在文件中存储了轻量级的索引数据
- 基于数据类型的块模式压缩:比如Integer类型使用RLE(RunLength Encoding)算法,而字符串使用字典编码(DictionaryEncoding)
- 使用单独的RecordReader并行读相同的文件
- 无需扫描标记就能分割文件
- 绑定读写所需要的内存
- 元数据存储使用PB,允许添加和删除字段
Hive ROW FORMAT
Serde是 Serializer/Deserializer的简写。hive使用Serde进行行对象的序列与反序列化。
你可以创建表时使用用户自定义的Serde或者native Serde,如果 ROW FORMAT没有指定或者指定了 ROW FORMAT DELIMITED就会使用native Serde。
hive已经实现了许多自定义的Serde,之前我们在介绍stored时也涉及到:
- Avro (Hive 0.9.1 and later)
- ORC (Hive 0.11 and later)
- RegEx
- Thrift
- Parquet (Hive 0.13 and later)
- CSV (Hive 0.14 and later)
- JsonSerDe (Hive 0.12 and later)
Hive写入数据的方式
和我们熟悉的关系型数据库不一样,Hive现在还不支持在insert语句里面直接给出一组记录的文字形式,也就是说,Hive并不支持INSERT INTO …. VALUES形式的语句(目前新版本早已支持,但是并不十分建议使用,性能和可用性方面难以满足要求)。
从本地文件系统中导入数据到Hive表
load data local inpath 'xxx.txt' into table xxx;
从HDFS上导入数据到Hive表
load data inpath '/home/xxx/add.txt' into table xxx
alter table db.access_log add partition (dt='18-09-18') location 'hdfs://ns/hive/warehouse/access_log/dt=18-09-18';
从别的表中查询出相应的数据并导入到Hive表中
insert overwrite table db.log_v2 partition(dt='18-09-26') select uid,model,key,value,time from db.log where dt='18-09-26';
在创建表的时候通过从别的表中查询出相应的记录并插入到所创建的表中