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 不進行轉換時就會出現下圖的錯誤,避免錯誤就得在該參數中也進行時間格式轉換