文档详情

Hive多字节分隔符解决方案

ji****81
实名认证
店铺
DOCX
1.11MB
约26页
文档ID:265417138
Hive多字节分隔符解决方案_第1页
1/26

       Hive多字节分隔符解决方案                      目录1 应用场景1.1 Hive中的分隔符1.2 特殊数据2 问题与需求2.1问题2.2 情况二:数据中包含了分隔符3 解决方案3.1 解决方案一:替换分隔符3.2 解决方案二:RegexSerDe正则加载3.3 解决方案三:自定义InputFormat4 总结1 应用场景1.1 Hive中的分隔符Hive中默认使用单字节分隔符来加载文本数据,例如逗号、制表符、空格等等,默认的分隔符为\001根据不同文件的不同分隔符,我们可以通过在创建表时使用 row format delimited fields terminated by ‘单字节分隔符’ 来指定文件中的分割符,确保正确将表中的每一列与文件中的每一列实现一一对应的关系1.2 特殊数据在实际工作中,我们遇到的数据往往不是非常规范化的数据,例如我们会遇到以下的两种情况· 情况一:每一行数据的分隔符是多字节分隔符,例如:”||”、“--”等上图中每列的分隔符为||,为多字节分隔符· 情况二:数据的字段中包含了分隔符上图中每列的分隔符为空格,但是数据中包含了分割符,时间字段中也有空格192.168.88.134 [08/Nov/2020:10:44:32 +0800] "GET / HTTP/1.1" 404 9512 问题与需求2.1问题基于上述的两种特殊数据,我们如果使用正常的加载数据的方式将数据加载到表中,就会出以下两种错误:· 情况一:加载数据的分隔符为多字节分隔符创建表--如果表已存在就删除表 drop table if exists singer; --创建表 create table singer( id string,--歌手id name string,--歌手名称 country string,--国家 province string,--省份 gender string,--性别 works string--作品 ) --指定列的分隔符为|| row format delimited fields terminated by '||';  加载数据load data local inpath '/export/data/test01.txt' into table singer; 查看结果select * from singer;问题数据发生了错位,没有正确的加载每一列的数据原因Hive中默认只支持单字节分隔符,无法识别多字节分隔符2.2 情况二:数据中包含了分隔符创建表--如果表存在,就删除表 drop table if exists apachelog; --创建表 create table apachelog( ip string, --IP地址 stime string, --时间 mothed string, --请求方式 url string, --请求地址 policy string, --请求协议 stat string, --请求状态 body string --字节大小 ) --指定列的分隔符为空格 row format delimited fields terminated by ' ';加载数据load data local inpath '/export/data/apache_web_access.log' into table apachelog查看结果select * from apachelog;问题时间字段被切分成了两个字段,后面所有的字段出现了错位原因时间数据中包含了分隔符,导致Hive认为这是两个字段,但实际业务需求中,为一个字段需求基于上面两种情况的测试发现,当数据中出现了多字节分隔符或者数据中的某个字段包含了分隔符,就会导致数据加载错位的问题。

基于出现的问题,我们需要通过特殊的方法来解决该问题,即使当数据中出现多字节分隔符等情况时,Hive也能正确的加载数据,实现列与数据的一一对应3 解决方案3.1 解决方案一:替换分隔符方案概述面对情况一,如果数据中的分隔符是多字节分隔符,可以使用程序提前将数据中的多字节分隔符替换为单字节分隔符,然后使用Hive加载,就可以实现正确加载对应的数据例如:原始数据中的分隔符为“||” 程序开发可以在ETL阶段通过一个MapReduce程序,将“||”替换为单字节的分隔符“|”,示例程序如下:import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.input.TextInputFormat; import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; import java.io.IOException; /** * @ClassName ChangeSplitCharMR * @Description TODO MapReduce实现将多字节分隔符转换为单字节符 * @Create By itcast */ public class ChangeSplitCharMR extends Configured implements Tool { public int run(String[] arg) throws Exception { /** * 构建Job */ Job job = Job.getInstance(this.getConf(),"changeSplit"); job.setJarByClass(ChangeSplitCharMR.class); /** * 配置Job */ //input:读取需要转换的文件 job.setInputFormatClass(TextInputFormat.class); Path inputPath = new Path("datas/split/test01.txt"); FileInputFormat.setInputPaths(job,inputPath); //map:调用Mapper job.setMapperClass(ChangeSplitMapper.class); job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(NullWritable.class); //reduce:不需要Reduce过程 job.setNumReduceTasks(0); //output job.setOutputFormatClass(TextOutputFormat.class); Path outputPath = new Path("datas/output/changeSplit"); TextOutputFormat.setOutputPath(job,outputPath); /** * 提交Job */ return job.waitForCompletion(true) ? 0 : -1; } //程序入口 public static void main(String[] args) throws Exception { //调用run Configuration conf = new Configuration(); int status = ToolRunner.run(conf, new ChangeSplitCharMR(), args); System.exit(status); } public static class ChangeSplitMapper extends Mapper{ //定义输出的Key private Text outputKey = new Text(); //定义输出的Value private NullWritable outputValue = NullWritable.get(); @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { //获取每条数据 String line = value.toString(); //将里面的||转换为| String newLine = line.replaceAll("\\|\\|", "|"); //替换后的内容作为Key this.outputKey.set(newLine); //输出结果 context.write(this.outputKey,this.outputValue); } } }程序执行结果如下: 重新建表加载数据1. 重新创建Hive表--如果表已存在就删除表drop table if exists singer;--创建表create table singer( id string,--歌手id name string,--歌手名称 country string,--国家 province string,--省份 gender string,--性别 works string--作品)--指定列的分隔符为||row format delimited fields terminated by '|';在Hive中重新加载数据load data local inpath '/export/data/part-m-00000' into table singer;查看结果 总结在ETL阶段可以直接对数据进行分隔符的替换,通过替换分隔符将多字节分隔符更改为单字节分隔符,就可以解决数据加载的问题,但是这种方式有对应的优缺点,并不是所有的场景适用于该方法。

优点:实现方式较为简单,基于字符串替换即可缺点:无法满足情况2的需求 3.2 解决方案二:RegexSerDe正则加载· 1 方案概述面对情况一和情况二的问题,Hive中提供了一种特殊的方式来解决,Hive提供了一种特殊的Serde来加载特殊数据的问题,使用正则匹配来加载数据,匹配每一列的数据官网地址:https://cwiki.apache.org/conflu。

下载提示
相似文档
正为您匹配相似的精品文档