Hive自定义文件读取
考虑这么个场景:某天你leader过来跟你说,我这现在有大量文本文件,大小不一,大的好几十G,小的几百兆;现在想提取出来共有的几个业务字段做分析,但是每种类型的接口文件的字段解析规则还不一样,比如业务字段A,在file1里面在第10字节到18字节之间,在file2中在第8字节到第16字节之间,问你怎么办?
如果有现成的hdfs集群,其实这事儿用Hive自定义文件读取
这个特性会非常省事儿!
文件如何读取(inputformat
),读取的内容如何解析(serde
)
你会发现,你只需要实现几个简单的类,篇头问题即迎刃而解
Inputformat
- 既然处理文本,当然
org.apache.hadoop.mapred.TextInputFormat
- 只需实现接口,把Split传给
RecordReader
,具体文本切分规则交给RecordReader
RecordReader
- 主要逻辑在
next()
中,通过LineRecordReader
解析Split,然后生成原始row
public boolean next(LongWritable key, Text value) throws IOException { |
Serde
- 负责把每一个原生row根据业务规则解析成多个field,这才产出一条有意义的record
initialize()
初始化,根据表schema定义,确定好有哪些列,每一列都是什么类型- 我们只想读取,所以只需实现
deserialize()
接口 - ObjectInspector很精髓!
Hive Sql 定义
hive -e "CREATE EXTERNAL TABLE IF NOT EXISTS khala_his.dwd_acco_his |
Answer
说到这,还有个关键问题没解决,如何解决同一表schema适配不同文本文件呢?只需两步
RecordReader
把文件名split.getPath().getName()
拼到每一个row末尾,相当于加一个虚拟列,用来索引对应row解析规则SerDe
解析字段规则时,根据虚拟列获取到解析规则,然后解析即可
org.apache.hadoop.io.Text
标准UTF8编码,如果你的文本不是UTF8,生成row时要用getBytes()
,非toString()
;
解析类型时候,DECIMAL要用HiveDecimal.create(BigDecimal decimal),DATE用java.sql.Date()