Hive支持多分隔符与GBK字符集

近期在做将数据从SFTP拷贝的Hive,SFTP中的文件存储的是从关系型数据库抽出来的数据,字段之间用0x7C0x1C两个字符分割,采用GBK字符集,这些都是公司规定的,不可能改动,字符集问题可以通过指定序列化编码方式适配,但是也有问题,下文会介绍,但是分隔符的问题无法通过指定建表参数解决,因为Hive默认只支持一个分隔符,既然不能通过HIVE命令解决多分隔符问题,那只能通过代码解决,从头开始过一遍HIVE的读写流程。

1、Hive的读写流程

Hive底层使用HDFS存储数据,Hive的查询就是从HDFS读取数据并且将数据转换为行对象,对Hive表的增删改会转换成mapreduce作业,计算完之后再写入HDFS,引用官方的文档,读写流程如下:
HDFS files –> InputFileFormat –> <key, value> –> Deserializer –> Row object
Row object –> Serializer –> <key, value> –> OutputFileFormat –> HDFS files

总结一下,Hive面对一个HDFS文档,查询的时候会做如下操作:

  • 调用InputFileFormat(默认是TextInputFormat)将文档中的每一行都转换为Key-Value形式的键值对;
  • 忽略key(key是偏移量,value才是文本内容),使用反序列化接口将value并结合设置的字段分隔符将文本内容切分成各个字段

写入操作和独处操作类似,Hive默认使用的OutputFileFormat 是HiveIgnoreKeyTextOutputFormat,为了让Hive支持多分隔符和GBK编码,需要重新实现某些类。

2、需求

将GBK编码的文件导入到hive,字段之间的分隔符为0x7C0x1C两个ASCII码,要求文件能正确导入,查询不出现乱码,每个字段均能正确显示,能支持删除部分数据(即支持mapreduce运算)

3、大概思路

想要支持多分隔符,有两种方式,一种是自定义序列化和反序列化类,另一种是自定义InputFileFormat和OutputFileFormat,相比第一种方案,第二种方案会简单一些,第二种的主要思想是:
文件从hdfs读出时,在调用InputFileFormat 中的相应方法时将两个分隔符替换成单个分隔符(具体的分隔符在建表的时候指定,最好是控制字符,我选的是0x1c);
文件写入hdfs时,在调用OutputFileFormat 相应方法时将单个分隔符重新转换成两个分隔符。
GBK字符集也需要在建表的时候一并指定,否则,默认按照utf-8的格式存储,建表语句如下:

create table tablename( columns)  
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe' WITH SERDEPROPERTIES("field.delim"='\034',"serialization.encoding"='GBK')
stored as INPUTFORMAT '自定义的InputForamta类'  
OUTPUTFORMAT'自定义的OutputFormat类';

具体的实现见下文

4、自定义inputFileformat

Hive并没有自己实现InputFilFormat,而是默认使用了hadoop下的mapred对应的TextInputFormat类,自定义InputFileFormat主要包括两个类,入口类需要继承TextInputFormat并实现JobConfigurable接口,数据读取类需要实现RecordReader接口

  • 入口类的代码实现
import java.io.IOException;  
import org.apache.hadoop.io.LongWritable;  
import org.apache.hadoop.io.Text;  
import org.apache.hadoop.mapred.FileSplit;  
import org.apache.hadoop.mapred.InputSplit;  
import org.apache.hadoop.mapred.JobConf;  
import org.apache.hadoop.mapred.JobConfigurable;  
import org.apache.hadoop.mapred.RecordReader;  
import org.apache.hadoop.mapred.Reporter;  
import org.apache.hadoop.mapred.TextInputFormat;

public class WareHouseInputFormat extends TextInputFormat implements  JobConfigurable {  

    public RecordReader<LongWritable, Text> getRecordReader(  
        InputSplit genericSplit, JobConf job, Reporter reporter)  
        throws IOExc
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值