内容简介:现在的场景是需要将ElasticSearch中的数据导入到Hive中,但是在导入的时候发现了日期映射的异常,ElasticSearch中日期字段定义的格式为:在Hive中建立外部表如下:建立外部表的时候,不会报错,但是查询的时候会报日期不能够正常映射为Hive中的Timestamp格式。
现在的场景是需要将ElasticSearch中的数据导入到Hive中,但是在导入的时候发现了日期映射的异常,ElasticSearch中日期字段定义的格式为:
"time" : { "type" : "date", "store" : true, "include_in_all" : true, "format" : "yyyy-MM-dd HH:mm:ss" }
在Hive中建立外部表如下:
CREATE EXTERNAL TABLE `test_table_es`( `meta_id` string COMMENT 'from deserializer', ...... `time` TIMESTAMP) ROW FORMAT SERDE 'org.elasticsearch.hadoop.hive.EsSerDe' STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler' WITH SERDEPROPERTIES ( '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 protected Object parseDate(String value, boolean richDate) { return (richDate ? new TimestampWritable(new Timestamp(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的原码:
package com.service.hadoop; import java.sql.Timestamp; import java.text.ParseException; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import javax.xml.bind.DatatypeConverter; import org.apache.hadoop.hive.serde2.io.TimestampWritable; import org.elasticsearch.hadoop.cfg.Settings; import org.elasticsearch.hadoop.hive.HiveValueReader; import com.sun.xml.bind.DatatypeConverterImpl; /** * 类EsValueReader.java的实现描述:用于转换ES中的日期类型,用于匹配Hive中的日期类型 * * @author fenglibin 2018年4月19日 下午3:54:00 */ public class EsValueReader extends HiveValueReader { private String dateFormat; private static final String DEFALUT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; @Override public void setSettings(Settings settings) { super.setSettings(settings); dateFormat = settings.getProperty("es.date.format"); } @Override protected Object parseDate(String value, boolean richDate) { if (value != null && value.trim().length() > 0 && DEFALUT_DATE_FORMAT.equalsIgnoreCase(dateFormat)) { return (richDate ? new TimestampWritable(new Timestamp(parseDate(value, DEFALUT_DATE_FORMAT).getTime())) : parseString(value)); } /**如果没有设置日期格式,通过默认的方式支持,以避免使用新的ValueReader后影响到其它的外部表**/ return super.parseDate(value, richDate); } /** * 解析日期,根据指定的格式进行解析.<br> * 如果解析错误,则返回null * @param stringDate 日期字符串 * @param format 日期格式 * @return 日期类型 */ private static Date parseDate(String stringDate, String format) { if (stringDate == null) { return null; } try { return parseDate(stringDate, new String[] { format }); } catch (ParseException e) { return null; } } public static Date parseDate(String str, String... parsePatterns) throws ParseException { return parseDateWithLeniency(str, parsePatterns, true); } private static Date parseDateWithLeniency( String str, String[] parsePatterns, boolean lenient) throws ParseException { if (str == null || parsePatterns == null) { throw new IllegalArgumentException("Date and Patterns must not be null"); } SimpleDateFormat parser = new SimpleDateFormat(); parser.setLenient(lenient); ParsePosition pos = new ParsePosition(0); for (String parsePattern : parsePatterns) { String pattern = parsePattern; // LANG-530 - need to make sure 'ZZ' output doesn't get passed to SimpleDateFormat if (parsePattern.endsWith("ZZ")) { pattern = pattern.substring(0, pattern.length() - 1); } parser.applyPattern(pattern); pos.setIndex(0); String str2 = str; // LANG-530 - need to make sure 'ZZ' output doesn't hit SimpleDateFormat as it will ParseException if (parsePattern.endsWith("ZZ")) { str2 = str.replaceAll("([-+][0-9][0-9]):([0-9][0-9])$", "$1$2"); } Date date = parser.parse(str2, pos); if (date != null && pos.getIndex() == str2.length()) { return date; } } throw new ParseException("Unable to parse the date: " + str, -1); } }
将这个类导出一个jar包并将其加到Hive的auxlib目录,然后再重启Hive即可。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- MyBatis从入门到精通(十一):MyBatis高级结果映射之一对多映射
- MyBatis从入门到精通(九):MyBatis高级结果映射之一对一映射
- 【mybatis xml】数据层框架应用--Mybatis(三)关系映射之一对一关系映射
- Hibernate 关系映射整理
- SpringMVC——请求映射
- Hibernate 关系映射整理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Data Structures and Algorithm Analysis in Java
Mark A. Weiss / Pearson / 2006-3-3 / USD 143.00
As the speed and power of computers increases, so does the need for effective programming and algorithm analysis. By approaching these skills in tandem, Mark Allen Weiss teaches readers to develop wel......一起来看看 《Data Structures and Algorithm Analysis in Java》 这本书的介绍吧!