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

栏目: 服务器 · 发布时间: 5年前

内容简介:现在的场景是需要将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即可。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JavaScript精粹

JavaScript精粹

爱德华兹 / 高铁军 / 人民邮电出版社 / 2007-6 / 49.00元

《JavaScript 精粹》主要介绍JavaScript应用中一些常见的问题及其解决方法,从最基础的数字、字符串、数组到进阶的DOM、表单验证、cookie,再到较为高级的Ajax,书中均有涉及。《JavaScript 精粹》覆盖现在非常流行和通用的技术,提出很多出现频率较高的Web开发常见问题,并提供了大量的技巧和解决方案,具有很强的实用性和通用性,书中的代码也具有很强的兼容性。《JavaSc......一起来看看 《JavaScript精粹》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

html转js在线工具
html转js在线工具

html转js在线工具