ElasticSearch中的日期映射爲Hive中的日期格式

現在的場景是需要將ElasticSearch中的數據導入到Hive中,但是在導入的時候發現了日期映射的異常,ElasticSearch中日期字段定義的格式為:

time:{

type:date,

store:true,

include_in_all:true,

format:yyyy-MM-ddHH:mm:ss

}

在Hive中建立外部表如下:

CREATEEXTERNALTABLE`test_table_es`(

`meta_id`stringCOMMENT'fromdeserializer',

......

`time`TIMESTAMP)

ROWFORMATSERDE

'org.elasticsearch.hadoop.hive.EsSerDe'

STOREDBY

'org.elasticsearch.hadoop.hive.EsStorageHandler'

WITHSERDEPROPERTIES(

'serialization.format'='1')

TBLPROPERTIES(

'COLUMN_STATS_ACCURATE'='false',

'es.index.auto.create'='false',

'es.mapping.names'='meta_id:_metadata._id,time:time',

'es.nodes'='127.0.0.1:9200',

'es.read.metadata'='true',

'es.resource'='test_index/test_type');

建立外部表的時候,不會報錯,但是查詢的時候會報日期不能夠正常映射為Hive中的Timestamp格式。

elasticsearch-hadoop中用於將ES中的日期轉換為Hive中的日期格式的類為org.elasticsearch.hadoop.hive.HiveValueReader,通過查看該類的源碼,其實現的用戶日期轉換的方法為:

@Override

protectedObjectparseDate(Stringvalue,booleanrichDate){

return(richDate?newTimestampWritable(newTimestamp(DatatypeConverter.parseDateTime(value).getTimeInMillis())):parseString(value));

}

可以看到它是通過javax.xml.bind.DatatypeConverter.parseDateTime(String)方法將對應的日期字符串轉換為日期的,

該方法不支持的日期字符串格式為“yyyy-MM-dd HH:mm:ss”的字符串,它支持的日期字符串的格式為“yyyy-MM-ddTHH:mm:ss”這樣的。

因而為了支持這種轉換,可以選擇兩種處理方式:

一是修改原始數據,二是在轉換的過程中做數據轉換,考慮到第一種方式要處理非常多的數據,因而採用了第二種方式,實現自己的ValueReader,在實現ValueReader的時候,要考慮兼容其它的日期格式,並且只處理屬性中指定了日期格式為“yyyy-MM-dd HH:mm:ss”的日期轉換,其它日期格式還是採用默認的方式處理,這樣才能夠兼容其它的日期格式,否則會導致其它的日期格式出錯,以下是一個實現的自定義的EsValueReader的原碼:

packagecom.service.hadoop;

importjava.sql.Timestamp;

importjava.text.ParseException;

importjava.text.ParsePosition;

importjava.text.SimpleDateFormat;

importjava.util.Calendar;

importjava.util.Date;

importjavax.xml.bind.DatatypeConverter;

importorg.apache.hadoop.hive.serde2.io.TimestampWritable;

importorg.elasticsearch.hadoop.cfg.Settings;

importorg.elasticsearch.hadoop.hive.HiveValueReader;

importcom.sun.xml.bind.DatatypeConverterImpl;

/**

*類EsValueReader.java的實現描述:用於轉換ES中的日期類型,用於匹配Hive中的日期類型

*

*@authorfenglibin2018年4月19日下午3:54:00

*/

publicclassEsValueReaderextendsHiveValueReader{

privateStringdateFormat;

privatestaticfinalStringDEFALUT_DATE_FORMAT=yyyy-MM-ddHH:mm:ss;

@Override

publicvoidsetSettings(Settingssettings){

super.setSettings(settings);

dateFormat=settings.getProperty(es.date.format);

}

@Override

protectedObjectparseDate(Stringvalue,booleanrichDate){

if(value!=nullvalue.trim().length()0DEFALUT_DATE_FORMAT.equalsIgnoreCase(dateFormat)){

return(richDate?newTimestampWritable(newTimestamp(parseDate(value,

DEFALUT_DATE_FORMAT).getTime())):parseString(value));

}

/**如果沒有設置日期格式,通過默認的方式支持,以避免使用新的ValueReader後影響到其它的外部表**/

returnsuper.parseDate(value,richDate);

}

/**

*解析日期,根據指定的格式進行解析.br

*如果解析錯誤,則返回null

*@paramstringDate日期字符串

*@paramformat日期格式

*@return日期類型

*/

privatestaticDateparseDate(StringstringDate,Stringformat){

if(stringDate==null){

returnnull;

}

try{

returnparseDate(stringDate,newString[]{format});

}catch(ParseExceptione){

returnnull;

}

}

publicstaticDateparseDate(Stringstr,String...parsePatterns)throwsParseException{

returnparseDateWithLeniency(str,parsePatterns,true);

}

privatestaticDateparseDateWithLeniency(

Stringstr,String[]parsePatterns,booleanlenient)throwsParseException{

if(str==null||parsePatterns==null){

thrownewIllegalArgumentException(DateandPatternsmustnotbenull);

}

SimpleDateFormatparser=newSimpleDateFormat();

parser.setLenient(lenient);

ParsePositionpos=newParsePosition(0);

for(StringparsePattern:parsePatterns){

Stringpattern=parsePattern;

//LANG-530-needtomakesure'ZZ'outputdoesn'tgetpassedtoSimpleDateFormat

if(parsePattern.endsWith(ZZ)){

pattern=pattern.substring(0,pattern.length()-1);

}

parser.applyPattern(pattern);

pos.setIndex(0);

Stringstr2=str;

//LANG-530-needtomakesure'ZZ'outputdoesn'thitSimpleDateFormatasitwillParseException

if(parsePattern.endsWith(ZZ)){

str2=str.replaceAll(([-+][0-9][0-9]):([0-9][0-9])$,$1$2);

}

Datedate=parser.parse(str2,pos);

if(date!=nullpos.getIndex()==str2.length()){

returndate;

}

}

thrownewParseException(Unabletoparsethedate:+str,-1);

}

}

將這個類導出一個jar包並將其加到Hive的auxlib目錄,然後再重啟Hive即可。


分享到:


相關文章: