本篇介绍如何在hive中查询、更新、插入ES数据,以及把数据从hive导入到es中。本方案适用于任何hive可以挂外表的数据库类型。
ELK系列(一)、安装ElasticSearch+Logstash+Kibana+Filebeat-v7.7.0
ELK系列(二)、在Kibana中使用RESTful操作ES库
ELK系列(四)、Logstash读取nginx日志写入ES中
ELK系列(五)、Logstash修改@timestamp时间为日志的产生时间
ELK系列(六)、修改Nginx日志为Json格式并使用Logstash导入至ES
ELK系列(七)、Filebeat+Logstash采集多个日志文件并写入不同的ES索引中
ELK系列(八)、使用Filebeat+Redis+Logstash收集日志数据
ELK系列(十)、ES中文分词器IK插件安装和配置远程词库热加载
ELK系列(十一)、ElasticSearch7.7.0插件es-head安装及使用
ELK系列(十二)、使用SQL查询ElasticSearch7.7.0
-----------------------------------------------在HIVE中操作ES----------------------------------------------
官方文档:https://www.elastic.co/guide/en/elasticsearch/hadoop/current/hive.html
下载:https://www.elastic.co/cn/downloads/past-releases#es-hadoop
参数:https://www.elastic.co/guide/en/elasticsearch/hadoop/current/configuration.html
环境
CDH-6.3.1
hive-2.1.1
ElasticSearch-6.6.2 (ES7.7一样的,因为之前用的ES6没升级,修改配置需要重启HIVE所以我就不用ES7演示了)
依赖
要在hive中查询操作ES需要先将ES的jar包放在hive的依赖环境中,这里有几种方式,首先下载jar包,到上面的链接中下载对应ES版本的elasticsearch-hadoop-hive-6.6.2.jar,然后到hive的lib下【/opt/cloudera/parcels/CDH/jars/commons-httpclient-3.1.jar】找到commons-httpclient-3.1.jar,待会讲为什么需要它。
在hive中添加外部jar包,hive中加载外部jar包的方式有几种:
1. hive shell中add jar
session级别的配置,只在hive命令行生效,不需要重启服务。
#在hive shell中:
#本地jar
add jar /home/tools/wyk/elasticsearch-hadoop-hive-6.6.2.jar;
add jar /home/tools/wyk/commons-httpclient-3.1.jar;
#或hdfs的jar包
add jar hdfs://nameservice1/tmp/hive/elasticsearch-hadoop-hive-6.6.2.jar;
add jar hdfs://nameservice1/tmp/hive/commons-httpclient-3.1.jar;
2. 启动hive shell时添加配置
session级别的配置,只在hive命令行生效,不需要重启服务。
hive -hiveconf hive.aux.jars.path=/home/tools/wyk/elasticsearch-hadoop-hive-6.6.2.jar
3. 在hive-site.xml中添加配置
服务级别的配置,在hive-shell和hiveserver2都可以生效,需要重启Hive。
vim hive-site.xml
<property>
<name>hive.aux.jars.path</name>
<value>/path/elasticsearch-hadoop.jar</value>
<description>A comma separated list (with no spaces) of the jar files</description>
</property>
4. 将jar放置在hive.aux.jars.path下【推荐】
服务级别的配置,在hive-shell和hiveserver2都可以生效,需要重启Hive,
把elasticsearch-hadoop-hive-6.6.2.jar和commons-httpclient-3.1.jar 放在hiveserver2节点的/home/public/java_project/udf/目录,此目录在CM中可配置,参数为hive.aux.jars.path。
为什么要添加httpclient的jar?
如果不加的话很可能会遇到下面的错误信息,将【/opt/cloudera/parcels/CDH/jars/commons-httpclient-3.1.jar】文件也通过上面的方式加到依赖中即可解决此问题:
java.lang.ClassNotFoundException: org.apache.commons.httpclient.protocol.ProtocolSocketFactory
Error: java.lang.RuntimeException: java.lang.NoClassDefFoundError: org/apache/commons/httpclient/protocol/ProtocolSocketFactory
at org.apache.hadoop.hive.ql.exec.mr.ExecMapper.map(ExecMapper.java:157)
at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:54)
at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:465)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:349)
at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:174)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1875)
at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:168)
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/httpclient/protocol/ProtocolSocketFactory
at org.elasticsearch.hadoop.rest.commonshttp.CommonsHttpTransportFactory.create(CommonsHttpTransportFactory.java:40)
at org.elasticsearch.hadoop.rest.NetworkClient.selectNextNode(NetworkClient.java:102)
at org.elasticsearch.hadoop.rest.NetworkClient.<init>(NetworkClient.java:85)
at org.elasticsearch.hadoop.rest.NetworkClient.<init>(NetworkClient.java:61)
at org.elasticsearch.hadoop.rest.RestClient.<init>(RestClient.java:94)
at org.elasticsearch.hadoop.rest.InitializationUtils.discoverNodesIfNeeded(InitializationUtils.java:90)
at org.elasticsearch.hadoop.rest.RestService.createWriter(RestService.java:581)
at org.elasticsearch.hadoop.mr.EsOutputFormat$EsRecordWriter.init(EsOutputFormat.java:173)
at org.elasticsearch.hadoop.hive.EsHiveOutputFormat$EsHiveRecordWriter.write(EsHiveOutputFormat.java:58)
at org.apache.hadoop.hive.ql.exec.FileSinkOperator.process(FileSinkOperator.java:769)
at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:882)
at org.apache.hadoop.hive.ql.exec.SelectOperator.process(SelectOperator.java:95)
at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:882)
at org.apache.hadoop.hive.ql.exec.TableScanOperator.process(TableScanOperator.java:130)
at org.apache.hadoop.hive.ql.exec.MapOperator$MapOpCtx.forward(MapOperator.java:146)
at org.apache.hadoop.hive.ql.exec.MapOperator.process(MapOperator.java:484)
at org.apache.hadoop.hive.ql.exec.mr.ExecMapper.map(ExecMapper.java:148)
... 8 more
Caused by: java.lang.ClassNotFoundException: org.apache.commons.httpclient.protocol.ProtocolSocketFactory
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 25 more
验证
通过上面第四种方式将jar放放置在hs2节点的hive.aux.jar.path路径下并重启Hive之后即可生效,在HUE中也可以直接通过Hive操作ES了。
hive建表属性
建表的TBLPROPERTIES中的属性可以在官网文档中查看:hive建表配置
...
STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES (
'es.index.auto.create'='false',--自动创建索引
'es.index.read.missing.as.empty'='true', --防止查询为空值报错
'es.mapping.names'='id:id,name:name,age:age,pt:pt', --hive字段对应的ES字段,手动指定或自动映射
'es.mapping.id'='id', --指定hive的字段对应es索引的_id值
'es.resource'='wyk_csdn/_doc' --ES中的索引
'es.net.http.auth.pass'='ES密码', --ES密码
'es.net.http.auth.user'='ES登录名', --ES登录名
'es.nodes'='localhost', --ES地址
'es.port'='9200',
'es.nodes.wan.only'='true',
'es.nodes.discovery' = 'false',
'es.read.metadata'='true'
)
类型映射规则
hive中建表的时候可以不指定字段映射,也可以手动指定字段的类型映射,不指定的话会自动映射字段类型,映射规则如下:
Hive type | Elasticsearch type |
---|---|
void | null |
boolean | boolean |
tinyint | byte |
smallint | short |
int | int |
bigint | bigint |
double | double |
float | float |
string | string |
binary | binary |
timestamp | date |
struct | map |
map | map |
array | array |
union | not supported (yet) |
decimal | string |
date | date |
varchar | string |
char | string |
验证交互
在Hive中创建ES外表并在ES中创建索引并插入数据:
-- 在Hive中创建ES外表并在ES中创建索引并插入数据
DROP TABLE IF exists default.es_bigdata_csdn01;
CREATE EXTERNAL TABLE if not exists default.es_bigdata_csdn01 (
name string,
age bigint,
email string
)
STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES('es.resource' = 'wyk_hive_csdn01/_doc',
'es.index.auto.create' = 'true', --自动建index
'es.index.read.missing.as.empty'='true',
'es.nodes' = '10.1.174.10',
'es.port'='9200'
);
-- 此时建完hive表,在es中没有索引
-- 插入一条数据后,在es中才能看到该索引
insert into default.es_bigdata_csdn01 values('王义凯',28,'[email protected]');
建hive外表读ES中已有的索引:
-- 建hive外表读已有的索引
CREATE EXTERNAL TABLE if not exists default.es_bigdata_csdn02(
name string,
age bigint,
email string
)
STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES('es.resource' = 'wyk_hive_csdn01/_doc',
'es.index.auto.create' = 'false', --因为是已有索引,所以无需自动建,其实就算选择了自动建,也可以读到已有的数据
'es.index.read.missing.as.empty'='true',
'es.nodes' = '10.1.174.10',
'es.port'='9200'
);
hive建表的时候指定ES索引的id唯一键映射:
在上面的Kibana截图中可以看到这条通过hive插入的数据的_id 属性的值是自动生成的,那么如果我们想指定该_id列为hive表的name列,这样的话就可以通过hive对ES的数据进行更新了,因为ES中_id相同的内容会自动更新。
-- 在hive中建ES外表并指定主键_id的映射字段
CREATE EXTERNAL TABLE if not exists default.es_bigdata_csdn03 (
name string,
age bigint,
email string
)
STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES('es.resource' = 'wyk_hive_csdn03/_doc',
'es.index.auto.create' = 'true', --若es中没有wyk_hive_csdn03索引则自动创建(需要在hive中对该索引插入数据才会生效)
'es.mapping.id'='name', --指定_id对应hive表的name字段
'es.index.read.missing.as.empty'='true',
'es.nodes' = '10.1.174.10',
'es.port'='9200'
);
insert into default.es_bigdata_csdn03 values('王义凯',28,'[email protected]');
此时我们在Hive中对该记录进行更新,看看在ES中该记录会变成什么样,注意在hive中无法对ES表使用update和delete命令,因此我们仍旧使用insert命令只要主键相同就会自动更新:
insert into default.es_bigdata_csdn03 values('王义凯',29,'[email protected]');
insert into default.es_bigdata_csdn03 values('Rick.Wang',30,'[email protected]');
全量覆盖 insert overwrite
效果等同于append,insert into,如果有相同主键则更新没有则insert。
--insert overwrite的效果等同于insert into
insert overwrite table default.es_bigdata_csdn03 select 'Rick.Wang',33,'[email protected]';
多类型测试
在hive中建一个测试表,类型丰富,测试在ES中自动映射之后的类型:
drop table if exists default.es_bigdata_csdn04;
CREATE TABLE if not exists default.es_bigdata_csdn04(
id bigint,
str_type string,
decimal_type decimal(5,2),
double_type double,
float_type float,
ins_ts timestamp,
arr array<string>
)
STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES('es.resource' = 'wyk_hive_csdn04/_doc',
'es.index.auto.create' = 'true',
'es.mapping.id'='id',
'es.index.read.missing.as.empty'='true',
'es.nodes' = '10.1.174.10',
'es.port'='9200'
);
--插入记录
insert into default.es_bigdata_csdn04 select 1,'str',3.14,4.13333,1.3333444,current_timestamp(),array('str1','str2','str3');
注意这里插入数据的时候不能用insert ... values(), 因为带有集合类型的记录,只能用insert .. select ...的写法,否则会报下面的错误:
FAILED: SemanticException [Error 10293]: Unable to create temp file for insert values Expression of type TOK_FUNCTION not supported in insert/values
从hive将数据导入ES
这个就很简单了,到目前未知应该很多人都能想到了,其实就是按照hive源表结构创建hive外表连接ES,然后在hive中执行下面的命令即可:
insert into hive_es select * from hive_src_tbl;
hive连接ES索引的其他的注意事项
- 不支持update,delete,truncate命令;
- truncate命令对hive外表(不能对no-managed的表进行清空操作);
- truncate命令对hive内表(不支持清空non-native 非原生表);
- 删除hive中的表(无论是External表还是Internal表),都是只会删掉hive表,对ES中的索引无影响;
- insert overwrite 全表覆盖,效果等同于append,insert into,如果有相同主键则更新没有则insert;
希望本文对你有帮助,请点个赞鼓励一下作者吧~ 谢谢!