hive创建表指定分隔符,不支持多个字符作为分隔符

hadoop fs -cat /tmp/liuxiaowen/1.txt

 

000377201207221125^^APPLE IPHONE 4S^^2
132288201210331629^^THINKING IN JAVA^^1
132288201210331629^^THIN ssss^^1111
132288201210331629^^THdd dd ddJAVA^^10

 

文本文件以两个尖角符作为列分隔符

 

hive中建表:

 

create external table tt(times string,
product_name string,
sale_num string
) row format delimited
fields terminated by '^^'
STORED AS TEXTFILE 
location 'hdfs://nn/tmp/liuxiaowen/';

 

hive> select times from tt;

000377201207221125
132288201210331629
132288201210331629
132288201210331629


hive> select product_name from tt; (结果均为空字符)
OK




Time taken: 13.498 seconds

hive> select sale_num from tt;
APPLE IPHONE 4S
THINKING IN JAVA
THIN ssss
THdd dd ddJAVA
 

本来应该放在product_name中的值,被分到了第三个字段sale_num.

 

原因是,hive中create table时候指定列分隔符,只能用一个字符,上面的建表语句真实采用的分隔符为一个尖角符^,

所以,真正的是将数据000377201207221125^^APPLE IPHONE 4S

以^为分隔符,分到了三个字段中,所以才有上面的select结果。

 

解决办法:

1. 将源文件中的分隔符替换为一个字符,比如\001(Ctrl+A),创建表时候指定\001作为分隔符;

 

2. 自定义 outputformat 和 inputformat。

 

Hive 的 outputformat/inputformat 与 hadoop 的 outputformat/inputformat 相当类似, inputformat 负责把输入数据进行格式化,然后提供给 Hive , outputformat 负责把 Hive 输出的数据重新格式化成目标格式再输出到文件,这种对格式进行定制的方式较为底层,对其进行定制也相对简单,重写 InputFormat 中 RecordReader 类中的 next 方法即可。

示例代码如下:

public boolean next(LongWritable key, BytesWritable value) throws IOException {
        while (reader.next(key,text)) {
	        String strReplace = text .toString().toLowerCase().replace( "^^" , "\001" );
	        Text txtReplace = new Text();
	        txtReplace.set(strReplace );
	        value.set(txtReplace.getBytes(), 0, txtReplace.getLength());
	        return true ;
      	}
      return false ;
}

 重写 Hive IgnoreKeyTextOutputFormat 中 RecordWriter 中的 write 方法,示例代码如下:

public void write (Writable w) throws IOException {
      String strReplace = ((Text)w).toString().replace( "\001" , "^^" );
      Text txtReplace = new Text();
      txtReplace.set(strReplace);
      byte [] output = txtReplace.getBytes();
      bytesWritable .set(output, 0, output. length );
      writer .write( bytesWritable );
}
 

自定义 outputformat/inputformat 后,在建表时需要指定 outputformat/inputformat ,如下示例:

stored as INPUTFORMAT 'com.aspire.search.loganalysis.Hive .SearchLogInputFormat' OUTPUTFORMAT 'com.aspire.search.loganalysis.Hive .SearchLogOutputFormat'

 

3. 通过 SerDe(serialize/deserialize) ,在数据序列化和反序列化时格式化数据。

这种方式稍微复杂一点,对数据的控制能力也要弱一些,它使用正则表达式来匹配和处理数据,性能也会有所影响。但它的优点是可以自定义表属性信息 SERDEPROPERTIES ,在 SerDe 中通过这些属性信息可以有更多的定制行为。

 

add jar /opt/app/hive-0.7.0-rc1/lib/hive-contrib-0.7.0.jar ;

create external table tt(times string,
product_name string,
sale_num string
) ROW FORMAT
SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
WITH SERDEPROPERTIES
( 'input.regex' = '([^^]*)\\^\\^([^^]*)\\^\\^([^^]*)',
'output.format.string' = '%1$s %2$s %3$s')
STORED AS TEXTFILE 
location 'hdfs://nn/tmp/liuxiaowen/';

hive> select product_name from tt;

APPLE IPHONE 4S
THINKING IN JAVA
THIN ssss
THdd dd ddJAVA

hive> select times,sale_num from tt;

000377201207221125      2
132288201210331629      1
132288201210331629      1111
132288201210331629      10
 

 

你可能感兴趣的:(hive,分隔符)