Hive load外部文件時(shí)如何區(qū)別分隔符與文本內(nèi)容

在測(cè)試hive的load性能時(shí),我們?cè)诮ū頃r(shí)指定使用|作為分隔符。這樣就需要考慮一個(gè)問(wèn)題:如果外部文本中|作為文本內(nèi)容出現(xiàn)時(shí),如何區(qū)分到底是分隔符還是文本內(nèi)容。

首先測(cè)試hive是否能智能區(qū)分分隔符與文本內(nèi)容,結(jié)果表明:當(dāng)分隔符與文本內(nèi)容相同時(shí),會(huì)產(chǎn)生數(shù)據(jù)混淆問(wèn)題。


SQL如何解決這一問(wèn)題

參考鏈接:如何在sqlldr中導(dǎo)入多字符分隔符文件

SQL中對(duì)此的解決辦法是采用多字符分隔符,以降低產(chǎn)生數(shù)據(jù)混淆的概率。


Hive中對(duì)這一問(wèn)題的解決思路與SQL相同

然而hive中默認(rèn)只支持單字符分割符,如果指定多字符分隔符將會(huì)報(bào)錯(cuò)。

參考鏈接:hive如何處理多分隔符數(shù)據(jù)
hive處理日志,自定義inputformat
hive創(chuàng)建表指定分隔符,不支持多個(gè)字符作為分隔符

解決辦法:

  • 利用hive自帶的序列化/反序列化的方式RegexSe
  • 重寫(xiě)相應(yīng)的InputFormat和OutputFormat方法

1. 利用hive自帶的序列化/反序列化的方式RegexSe
這種方式稍微復(fù)雜一點(diǎn),對(duì)數(shù)據(jù)的控制能力也要弱一些,它使用正則表達(dá)式來(lái)匹配和處理數(shù)據(jù),性能也會(huì)有所影響。但它的優(yōu)點(diǎn)是可以自定義表屬性信息 SERDEPROPERTIES ,在 SerDe 中通過(guò)這些屬性信息可以有更多的定制行為。

/*樣例數(shù)據(jù)*/
110|#警察
120|#醫(yī)院
/*建表*/ 
add jar /home/cup/software/……/hive-contrib-0.10.0-cdh4.4.0.jar;
create table test
(
id string,
name string
)partitioned by (c_day string)
row format serde 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
with serdeproperties
( 'input.regex' = '([^\\|#]*)\\|#([^\\|#]*)' , 'output.format.string' = '%1$s%2$s')
stored as textfile;
 /*load*/
load data local inpath '/……/test.txt'  overwrite into table test partition(c_day = '20141027');
/*查詢(xún)結(jié)果*/
select * from test;
110 警察 20141027
120 醫(yī)院 20141027

2. 自定義 outputformat 和 inputformat
Hive 的 outputformat/inputformat 與 hadoop 的 outputformat/inputformat 相當(dāng)類(lèi)似, inputformat 負(fù)責(zé)把輸入數(shù)據(jù)進(jìn)行格式化,然后提供給 Hive,outputformat 負(fù)責(zé)把 Hive 輸出的數(shù)據(jù)重新格式化成目標(biāo)格式再輸出到文件,這種對(duì)格式進(jìn)行定制的方式較為底層,對(duì)其進(jìn)行定制也相對(duì)簡(jiǎn)單,重寫(xiě) InputFormat 中 RecordReader 類(lèi)中的 next 方法即可。

/*樣例數(shù)據(jù)*/
2010-05-31 10:50:17|||61.132.4.82|||http://www.360buy.com/product/201185.html 
/*分隔符是“ ||| ”,這是為了盡可能防止日志正文出現(xiàn)與分隔符相同的字符而導(dǎo)致數(shù)據(jù)混淆。 hive 的內(nèi)部分隔符是“ \001 ”,所以我們需要做一下轉(zhuǎn)換 */
/*編寫(xiě)自定義InputFormat */
package com.jd.cloud.clickstore;    
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;    
/** 
 * 自定義hadoop的 org.apache.hadoop.mapred.InputFormat 
 *  
 * @author winston 
 *  
 */  
public class ClickstreamInputFormat extends TextInputFormat implements  
        JobConfigurable {    
    public RecordReader<LongWritable, Text> getRecordReader(  
            InputSplit genericSplit, JobConf job, Reporter reporter)  
            throws IOException {    
        reporter.setStatus(genericSplit.toString());  
        return new ClickstreamRecordReader(job, (FileSplit) genericSplit);  
    }  
}  
/*自定義ClickstreamRecordReader實(shí)現(xiàn)RecordReader接口,并重寫(xiě)next方法 */
/** Read a line. */  
  public synchronized boolean next(LongWritable key, Text value)  
    throws IOException {    
    while (pos < end) {  
      key.set(pos);    
      int newSize = in.readLine(value, maxLineLength,  
                                Math.max((int)Math.min(Integer.MAX_VALUE, end-pos),  
                                         maxLineLength));          
      //start  
      String strReplace = value.toString().toLowerCase().replaceAll("\\|\\|\\|" , "\001" );  
      Text txtReplace = new Text();  
      txtReplace.set(strReplace );  
      value.set(txtReplace.getBytes(), 0, txtReplace.getLength());  
      //end
      if (newSize == 0) {  
        return false;  
      }  
      pos += newSize;  
      if (newSize < maxLineLength) {  
        return true;  
      }    
      // line too long. try again  
      LOG.info("Skipped line of size " + newSize + " at pos " + (pos - newSize));  
    }    
    return false;  
  }  
/*我們可以直接使用LineRecordReader,修改next方法 */
/*啟動(dòng)hive,添加我們自己剛剛添加的類(lèi) */
/*創(chuàng)建數(shù)據(jù)庫(kù)*/
/*自定義 outputformat/inputformat 后,在建表時(shí)需要指定 outputformat/inputformat */
create table clickstream_table(time string, ip string, url string) stored as INPUTFORMAT 'com.jd.cloud.clickstore.ClickstreamInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION '/data/clickstream_20110216.txt';  
/*LOAD數(shù)據(jù) */
LOAD DATA LOCAL INPATH '/data/clickstream_20110216.txt' OVERWRITE INTO TABLE clickstream_table; 
/*查詢(xún)剛剛LOAD的數(shù)據(jù)*/
select * from clickstream_table; 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容