es导出hive遇到的问题汇总

本文介绍如何通过导入elasticsearch-hadoop-hive-5.5.2.jar包实现Elasticsearch与Hive的集成,并详细说明了创建外部表及内部表的过程。此外,还讨论了解决日期类型数据转换问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先直接上干货:

步骤
  1. 导入elasticsearch-hadoop-hive-5.5.2.jar包
  2. 创建hive外部表,数据源设置为es中,添加相应的配置
  3. 创建内部表拉取数据
add jar file:///home/hadoop/liubx/elasticsearch-hadoop-hive-5.5.2.jar;
add jar  file:///home/hadoop/hive-1.2.1/lib/es-hadoop.jar;   #代码见后面

use estest;
drop table if exists ext_es_test;
CREATE EXTERNAL TABLE ext_es_test(
typeid string,
cs_app string,
ipAddress string,
createTime  timestamp
)
row format delimited fields terminated by '\t'  
collection items terminated by ',' 
map keys terminated by ':'
STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES(
'es.nodes' = 'master:9200',
'es.index.auto.create' = 'false',
'es.mapping.date.rich' = 'true',
'es.date.format' = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd", 
'es.ser.reader.value.class' = 'fjjf.es.EsValueReader',
'es.resource' = 'buriedpointinfo_bumsg/',
'es.read.metadata' = 'true',
'es.mapping.names' = 'typeid:_metadata._type, cs_app:cs_app,ipAddress:ipAddress,createTime:createTime');

#注释:
'es.nodes'                  -- es连接node信息
'es.index.auto.create'      -- 是否自动创建索引 
'es.mapping.date.rich'      -- 是否启用date自动转换,json中没有时间类型,es封装了一个Date类型存放特定格式的时间字符串。可以通过mapping指定format
'es.date.format'            -- 自定义dateformat
'es.ser.reader.value.class'  -- 自定义reader,由于本地es中存放时间采用了("yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"),导出时hive只能选择一种类型存取timestamp或者date
'es.resource'            -- es索引        
'es.read.metadata'       -- 是否读取es元数据字段         
'es.mapping.names'         -- es 和hive  字段映射

#分页查询
select * from estest.ext_es_test_bumsg limit 10;

#创建内部表分页查询
drop table if exists itn_es_test;
create table itn_es_testas 
select * from estest.itn_es_test;
遇到的问题:
  1. es中字段较多,不需要导出所有字段。
    解决: 通过'es.mapping.names' 配置筛选所需要的字段。

  2. 在hadoop-2.8版本下导出的时候经常会报Error: java.lang.ClassNotFoundException: org.apache.commons.httpclient.util.xxxx,但是hive/lib目录下确实有该类。手动添加后还是无法解决
    解决: 将版本切到2.7不会出现该问题,但是根本原因还是没有找到,待解决。

20180402更新:
解决方法:


URL:
  http://master:8088/taskdetails.jsp?jobid=job_1517535406767_315524&tipid=task_1517535406767_315524_m_000137
-----
Diagnostic Messages for this Task:
Error: java.lang.ClassNotFoundException: org.apache.commons.httpclient.util.DateParseException
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)
    at java.lang.Class.newInstance(Class.java:412)
    at org.elasticsearch.hadoop.util.ObjectUtils.instantiate(ObjectUtils.java:41)
    at org.elasticsearch.hadoop.util.ObjectUtils.instantiate(ObjectUtils.java:52)
    at org.elasticsearch.hadoop.util.ObjectUtils.instantiate(ObjectUtils.java:48)

尝试在hive命令行手动添加jar失效之后,对比了hadoop2.7和hadoop2.8的jar包内容。发现hadoop-2.8.1/share/hadoop/common/lib目录下少了commons-httpclient-3.1.jar,由于本地hadoop2.8是编译安装的,所以怀疑是编译安装的时候没有将该依赖包打进去,对比官方下载的hadoop2.8二进制包发现也没有该jar包。
通过查看hadoop-2.8。0的change-log(https://issues.apache.org/jira/browse/HADOOP-13382

5903023-6965301acbd84309.png
image.png

接下来,只需将es-hadoop依赖的commons-httpclient jar加入到所有的hadoop节点即可。

  • hadoop classpath | tr ':' '\n'
5903023-fe9c2088ccb2561a.png
image.png
  1. es中导出的Date类型数据既有时间戳也有日期字符串,在存取到hive的时候发现以下问题;

1)时间戳无法正常转换为时间戳
37304150-01-31 14:25:515:51.616
37301390-01-10 14:25:515:51.616
37300635-01-05 14:25:515:51.616
37289863-10-16 14:25:515:51.616
2)时间字符串无法正常转换为时间戳,会报类转换异常 TextWritable unable cast to TimestampWritable

解决: 通过指定'es.ser.reader.value.class' ,自定义reader处理该异常,将所有时间格式字符串统一格式输出。

通过查看elasticsearch-hadoop的源码,发现es-hadoop在解析Date类型的时候使用的是DatatypeConverter.parseDateTime(value)。(无法应对我们自定义的各种时间格式,甚至包括UTC时区的时间。)

源码地址:
https://github.com/elastic/elasticsearch-hadoop/blob/master/hive/src/main/java/org/elasticsearch/hadoop/hive/HiveValueReader.java

@Override
    protected Object parseDate(Long value, boolean richDate) {
        return (richDate ? new TimestampWritable(new Timestamp(value)) : processLong(value));
    }

    @Override
    protected Object parseDate(String value, boolean richDate) {
        return (richDate ? new TimestampWritable(new Timestamp(DatatypeConverter.parseDateTime(value).getTimeInMillis())) : parseString(value));
    }

源码修改(默认情况下richDate为true,如果为false,则时间戳会当作Long处理,时间字符串当作Text处理)

@Override
    protected Object parseDate(String value, boolean richDate) {
        Date d = null;

        if(StringUtil.isNotEmpty(dateFormat)) {
            try {
                if(value.length() == 13){
                    return new TimestampWritable(new Timestamp(Long.valueOf(value)));
                }else{
                    d = DateUtil.parseDate(value, Arrays.asList(dateFormat.split("\\|\\|")));
                }

            } catch (DateParseException e) {
                e.printStackTrace();
                System.out.println("parse failed please check the dateFormat");
            }
        } else {
            d = DdfatatypeConverter.parseDateTime(value).getTime();
        }
        return new TimestampWritable(new Timestamp(d.getTime()));
    }

    protected Object parseDate(long value, boolean richDate) {
        Date d = new Date(value);
        return new TimestampWritable(new Timestamp(d.getTime()));
    }
  1. 最后遇到一个小问题,idea打包jar的时候太大,上传服务器速度较慢,将一些依赖去除打包后解决。
    解决: 在pom.xml中指定scope为proviede,打包的时候忽略。
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch-hadoop</artifactId>
    <version>5.5.0</version>
    <scope>provided</scope>
</dependency>

总结:
es国内资料比较杂乱,很多都还是2.x的。
建议研读官方文档,es这块配置项比较多,而且很多功能也许在配置项中已经可以找到解决方案了,缺乏的是仔细去研读和加深理解。这个我自己也正在学习的路上,哈哈!
另外,es-hadoop导出性能一般,20m/s左右,3个节点。有待提升,有时间可以对比下es-spark和java api效果。

<think>我们正在处理用户的问题:"我想将Hive中的数据直接写入Elasticsearch的方法" 根据引用[3]中提到,我们可以使用es-hadoop工具来实现将Hive数据导入Elasticsearch。es-hadoop是一个jar包,其版本需要与Elasticsearch版本对应(例如,如果使用ES 7.10,则需要es-hadoop 7.10版本)。es-hadoop支持与Hadoop组件(包括Hive)以及Spark交互。 具体步骤: 1. 下载对应版本的es-hadoop jar包,并将其放入Hive的auxlib目录(如果没有则创建)或添加到Hive的类路径中。 2. 在Hive中创建外部表,该表指向Elasticsearch的索引,然后通过INSERT语句将Hive表的数据写入这个外部表,从而将数据写入Elasticsearch。 详细步骤: 步骤1:准备es-hadoop jar包 从官方下载:https://www.elastic.co/downloads/hadoop 例如,下载elasticsearch-hadoop-7.10.2.jar,将其放入Hive服务器的auxlib目录(例如/opt/module/hive/auxlib/)或通过ADD JAR命令在Hive会话中添加。 步骤2:在Hive中创建指向Elasticsearch的外部表 假设我们有一个Hive表`hive_table`,其结构如下: CREATE TABLE hive_table (id INT, name STRING, age INT); 现在,我们要将数据写入Elasticsearch,首先在Hive中创建一个指向Elasticsearch索引的外部表: CREATE EXTERNAL TABLE es_table ( id INT, name STRING, age INT ) STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler' TBLPROPERTIES( 'es.resource' = 'index_name/type_name', # 在ES 7.x及以上,类型名通常用_doc,或者可以省略类型名,使用索引名即可 'es.nodes' = 'elasticsearch_host:port', # 例如 'es.nodes' = 'localhost:9200' 'es.index.auto.create' = 'true', # 如果索引不存在,自动创建 'es.mapping.id' = 'id' # 可选,指定文档ID的字段 ); 注意:在Elasticsearch 7.x中,类型(type)已经被逐渐弃用,所以通常我们可以使用固定的类型名,如`_doc`,或者在es.resource中只写索引名(如'index_name'),则类型默认为`_doc`。 步骤3:将Hive表的数据插入到Elasticsearch外部表 INSERT INTO TABLE es_table SELECT * FROM hive_table; 这样,Hive表的数据就会写入Elasticsearch。 另外,也可以使用Hive导出功能(EXPORT)或者直接将数据写入,但上述方法是最常用的。 注意事项: - 确保Hive服务能够访问Elasticsearch集群。 - 根据数据量调整es-hadoop的配置,例如批量写入的大小('es.batch.size.bytes'和'es.batch.size.entries')等。 引用[3]中提到,es-hadoop既可以和Hadoop相关组件交互,也可以和Spark交互。如果数据量非常大,也可以考虑通过Spark来中,但使用Hive直接写入也是一种常见方式。 因此,总结方法:通过es-hadoop提供的Hive集成,创建外部表并插入数据。 生成相关问题: 1. 如何调整es-hadoop写入Elasticsearch的性能? 2. 在写入过程中出现错误如何排查? 3. 除了Hive,还有哪些方式可以将数据写入Elasticsearch? 4. 如何确保Hive和Elasticsearch之间的数据类型映射正确? 5. 如果Elasticsearch集群有认证,如何配置?</think>### 将Hive数据直接写入ElasticSearch的方法 通过 **Elasticsearch-Hadoop 连接器**(es-hadoop)可实现 Hive 到 Elasticsearch 的直接数据写入,以下是详细步骤: #### 步骤 1:安装配置 es-hadoop 1. **下载匹配版本** 选择与 Elasticsearch 版本对应的 es-hadoop jar 包(如 ES 7.x 需用 es-hadoop-7.x.x.jar)[^3] ```bash wget https://artifacts.elastic.co/downloads/elasticsearch-hadoop/elasticsearch-hadoop-7.17.3.jar ``` 2. **部署到 Hive** 将 jar 包放入 Hive 的 `auxlib` 目录或通过 `ADD JAR` 加载: ```sql ADD JAR /path/to/elasticsearch-hadoop-7.17.3.jar; ``` #### 步骤 2:创建 Hive 外部表映射 ES ```sql CREATE EXTERNAL TABLE hive_es_mapping ( id STRING, name STRING, age INT ) STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler' TBLPROPERTIES( 'es.resource' = 'hive_data_index/_doc', -- ES 索引/类型 'es.nodes' = 'es-host:9200', -- ES 节点地址 'es.mapping.id' = 'id', -- 指定文档ID字段 'es.write.operation' = 'upsert' -- 写入模式(upsert/delete) ); ``` #### 步骤 3:写入数据到 ES ```sql -- 从现有 Hive 表导入 INSERT INTO TABLE hive_es_mapping SELECT id, name, age FROM source_hive_table; -- 直接插入数据 INSERT INTO TABLE hive_es_mapping VALUES ('001', '张三', 28), ('002', '李四', 32); ``` #### 关键配置参数 | 参数 | 说明 | 示例值 | |------|------|--------| | `es.resource` | ES 索引/类型 | `my_index/_doc` | | `es.nodes` | ES 集群节点 | `es1:9200,es2:9200` | | `es.mapping.id` | 文档 ID 字段 | `id` | | `es.batch.size.bytes` | 批量写入大小 | `10mb` | | `es.batch.write.retry.count` | 失败重试次数 | `3` | #### 验证数据 ```bash curl -XGET 'http://es-host:9200/hive_data_index/_search?q=name:张三' ``` #### 注意事项 1. **版本兼容性** HiveESes-hadoop 的版本必须严格匹配[^3] 2. **数据类型映射** Hive 的 `STRING` 默认映射为 ES 的 `text` + `keyword`,其他类型需手动调整映射 3. **性能优化** - 增加批量大小:`set es.batch.size.bytes=50mb;` - 启用压缩:`set es.http.compression=true;` - 关闭副本写入:`set es.index.auto.create=false;`(需预创建索引) 4. **安全认证** 若 ES 启用安全认证,需添加配置: ```sql SET es.net.http.auth.user=elastic; SET es.net.http.auth.pass=your_password; ``` --- ###
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值