Hive底层文件存储类型parquet

Hive作为数据仓库常用工具之一,在数据量级越来越大的时候,存储问题会暴露出来。那么在之前大部分为了省事方便都会以TextFile*作为存储类型,此类型比较占存储,并且查询效率并不是很高。为了节省集群的存储空间,研究了各种存储类型,网上各类帖子已经把这几类的优缺点和使用场景说的非常明确。我在这稍微提及一下,主要想分享我在使用sqoop抽取数据时进行文件类型转换(parquet)遇到的坑,共享出来希望遇到此问题的朋友借鉴,减少不必要时间消耗。*

一、概述一下各类文件类型的优缺点

1.TextFile

行存储,直接存储文件,数据量级大,磁盘开销大,
优点:数据操作方便,直接使用put上传数据文件,并且可以直接使用cat 查看HDFS上的文件内容

2.SequenceFile

行存储,含有键值对的二进制文件,数据量级大,对于Hadoop生态系统之外的工具不适用,需要通过text文件转化加载。
优点:可压缩、可分割,优化磁盘利用率和I/O

3.rcfile

行列式存储,先将数据按行分块,同一个record在一个块上,避免读一条记录需要读多个block;然后块数据列式存储
缺点:加载时性能消耗较大,需要通过text文件转化加载;读取全量数据性能低(扫描的数据块多效率低 )
优点:可压缩,高效的列存取;查询效率较高。

4.orcfile

列式存储,优化后的rcfile,存储方式和 rcfile 相同
优点:压缩快,快速列存取 ,效率比rcfile高 ,上层presto查询引擎和orc格式兼容性较好
缺点:查询引擎不支持 impala 只能用hive查询数据

5.parquet

列存储Parquet仅仅是一种存储格式,和语言、平台无关,并且不需要和任何一种数据处理框架绑定,通常使用的查询引擎和计算框架都已适配,并且可以很方便的将其它序列化工具生成的数据转换成Parquet格式。
优点:
1.支持多种(几乎大部分)查询引擎,计算框架,数据模型
2.可以使用更多的压缩算法
3.很好的支持: hive,spark,hadoop streaming,mapreduce,impala
4.查询性能和压缩比虽然没有ORC高但是已经达到相对满意的程度了


       如果使用impala组件,使用parquet 存储格式是最好的搭配。根据实际使用情况得知: 使用parquet格式没有采用压缩就已经有 2.3:1 的压缩比了 ,数据量至少比原来减少一半以上,并且不影响原来的查询和计算。

二、sqoop+hive(parquet)

1.hive建表语句

CREATE TABLE database.table_tmp(
a bigint
b string,
c double
) 
PARTITIONED BY (etl_month string)
ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
WITH SERDEPROPERTIES (   'field.delim'='\t',   'line.delim'='\n',   'serialization.format'='\t') 
STORED AS INPUTFORMAT  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION 'hdfs://nameservice1/user/hive/warehouse/database.db/table_tmp'
TBLPROPERTIES('parquet.compression'='SNAPPY');

2.sqoop抽取数据配置

#启用压缩开关参数  --compress 
#压缩格式定义  --compression-codec org.apache.hadoop.io.compress.SnappyCodec
#采用parquet文件存储格式  --as-parquetfile
 
#数据抽取
sqoop import \
--append \
--connect "jdbc:sqlserver://$ip:$port;database=$source_db;username=$username;password=$password" \
--fields-terminated-by "${separator}"  -m 3 \
--query "${query}" \
--split-by "${split_col}" \
--as-parquetfile \
--target-dir "hdfs://nameservice1/user/hive/warehouse/$target_db.db/$target_tablename/$partition=$DATATIME" \
--hive-drop-import-delims \
--null-string '\\N' --null-non-string '\\N'

3. 遇到的坑

A.使用sqoop 导入hive表中,查表报错,无法查询

原因分析:数据源的数据类型和parquet所支持的数据类型不完全一致,所以导致查询时出现数据类型转换异常

parquet 和 hive 的 字段类型映射关系如下:
BINARY -> STRING
BOOLEAN -> BOOLEAN
DOUBLE -> DOUBLE
FLOAT -> FLOAT
INT32 -> INT
INT64 -> BIGINT
INT96 -> TIMESTAMP
BINARY + OriginalType UTF8 -> STRING
BINARY + OriginalType DECIMAL -> DECIMAL

所以在parquet的数据类型中不支持存储 timestamp 、decimal 类型,在具体任务执行时就会出现下面这几种错误类型

错误 1 Cannot inspect org.apache.hadoop.io.LongWritable

数据源的数据类型和hive表定义的数据类型不匹配,比如数据源数据类型为 bigint,hive表中数据类型为 string。存在两种数据类型不一致时就会报此问题

错误 2 java.lang.ClassCastException:org.apache.hadoop.io.LongWritable cannot be cast to org.apache.hadoop.hive.serde2.io.TimestampWritable

在这里插入图片描述
在parquet中timestamp类型是用int96存储的,如果在执行hive建表时将表字段定义为timestamp类型,那么在查询时会出现转换异常错误,若将hive表字段变为int96时,查询结果回是时间的长整型表示形式:长度为10位,即表示的是秒数,从1970年1月1日开始的。这种长整型格式在使用时还需要进行数据格式转换,才能转换成“yyyyMMdd”类型,所以我们采用的策略是:将timestamp类型从数据源头抽取时就转换为string类型

错误 3 java.lang.ClassCastException:org.apache.hadoop.io.Text cannot be cast to org.apache.hadoop.io.LongWritable

在parquet中没有DECIMAL数据类型,如果将hive表定义为此类型,在查询时也会报如下错误。所以可以采取的策略是:数据抽取时就将数据源头的数据转换为float 和 double。避免查询时报错

>>>在这记录一个Hue的数据显示问题

当表中字段类型定义为double时,Hue查询数据可能会出现数据精度或者转换问题的假象,表象如下:
在这里插入图片描述
但是在hive的cli界面查询时数据是正常的,没有出现精度损失问题。如下图:
在这里插入图片描述
如果广大网友有遇到此类问题并且知道原理务必留言评论告知,非常感谢!

B. sqoop 抽取数据显示“从字符串转换日期和/或时间时,转换失败”

看此问题一度会认为是数据抽取时数据转换出现错误,其实不然。数据是在sqoop抽取数据时数据切分时报错,定义 “ -m 3 ” 后,数据会切分为3块以3个reduce进行输出。上一步咱们已经把时间戳字段转换成了string进行存储,那么在抽取切分时也应该定义为相同类型,保持一致。 比如在数据抽取字段中使用 monitortime 字段,由于需要转换,我们将其转换为 CONVERT(varchar(19),monitortime,120) 字符串 (我们的数据源头是sql server数据库),那么在 sqoop 参数**–split-by** 中使用monitortime 不进行转换时就会出现下图的错误,避免错误就得在该参数中也进行时间格式转换
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章