参考官网
Apache Hive integration | Elasticsearch for Apache Hadoop [7.17] | Elastic
官网的介绍很简单,我看了很多博客,写的也很简单,但是我搞了半天才勉强成功,分享下,免得各位多走弯路。
环境准备
官网也很贴心的给了几种方式。
1.$ bin/hive --auxpath=/path/elasticsearch-hadoop.jar
2.$ bin/hive -hiveconf hive.aux.jars.path=/path/elasticsearch-hadoop.jar
3.修改hive-site.xml
看似方法很多 其实有问题,首先我们现在都是beeline模式登录,bin/hive已经被废弃了。那么beeline能用吗?貌似可以用 第1和第2基本上是一样的
网上还有一种办法 直接把jar上传到这个目录/opt/cloudera/parcels/CDH/lib/hive/auxlib/ auxlib很明显就是上面的变量
beeline -u "jdbc:hive2://cdp-node02:2181,cdp-node03:2181,cdp-node04:2181/;serviceDiscoveryMode=zooKeeper;zooKeeperNamespace=hiveserver2" -hiveconf hive.aux.jars.path=/path/elasticsearch-hadoop.jar
发现还是没有读取到jar 算了吧
第3种貌似是最好的,但是要动集群配置很麻烦,
于是只有用最简单的方式add jar,注意这个只是当前会话有效;
下载jar包
这个时候有小伙伴会问了 这个jar怎么来的,我看官网好像也没给例子呀。
通过maven,新建一个工程,记住这个工程还有用的
网上看到还有可以直接在服务器wget的。。
<dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch-hadoop</artifactId> <version>7.14.2</version> </dependency>对了低版本的es可能没有个http-client的jar
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
通过maven把这个jar下下来 ,然后再上传到服务,记住改下es.version
添加到hdfs
进入beeline add jar
add jar hdfs:///user/hive/elasticsearch-hadoop-7.5.1.jar;
add jar hdfs:///user/hive/commons-httpclient-3.1.jar;
或者
add jar hdfs:///user/hive/elasticsearch-hadoop-7.14.2.jar;
list jar 可以看是否添加成功
至此 我们的hive已经有了这个jar。
开始建表
官网很多demo,肯定找最简单的来。
参考配置
但是此时我又有问题了。这个demo 明显不对,es的地址都没有啊。
Configuration | Elasticsearch for Apache Hadoop [7.17] | Elastic
这里提到了essential 和required看来都是必须的,还有写defalut的就不说了。
用户认证
因为我的es还有认证所以需要输入用户密码继续在配置里找参数
create external table esdata.cc_test2
(id string ,name string ,des string )
STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES(
'es.net.http.auth.user'='xxxxx',
'es.net.http.auth.pass'='xxxxxx' ,
'es.nodes'='9.134.161.140', --连接地址
'es.resource' = 'i_dw_cc_test' ) --es7的时候没有type了,这里不需要写type
至此参考了了很多人的文章,感觉也差不多了。结果还是有问题。
报错1
先说一个问题。建好表后,insert into的时候报错了
我已经认证了,为什么这里还是报权限错误呢?我这个用户在es是可以查和插入这个index的数据的 确定以及肯定。
分析报错原因,查看源码,这里就提到刚刚那个工程了。
搜索RestClient.getHttpNodes
这个熟不熟悉。这个不就是kibana的get请求么,我在es试了确实没权限,要组长帮忙开通这个权限后,这个错就解决了。
报错2
接着建表。然后又出错了!!!!!!
先给大家看下代码 注意这个node =9.134.161.140
连接 正常。我hive建表的es.node也是这个地址
但是当我执行select count(1) from cc_test;时报错了。
Error: Error while compiling statement: FAILED: Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.tez.TezTask. Vertex failed, vertexName=Map 1, vertexId=vertex_1690006488152_0865_1_00, diagnostics=[Vertex vertex_1690006488152_0865_1_00 [Map 1] killed/failed due to:ROOT_INPUT_INIT_FAILURE, Vertex Input: cc_test initializer failed, vertex=vertex_1690006488152_0865_1_00 [Map 1], org.elasticsearch.hadoop.rest.EsHadoopInvalidRequest: [GET] on [_nodes/http] failed; server[9.10.132.27:9200] returned [403|Forbidden:]
--注意这里9.10.132.27 怎么这是个啥ip。
at org.elasticsearch.hadoop.rest.RestClient.checkResponse(RestClient.java:486)
at org.elasticsearch.hadoop.rest.RestClient.execute(RestClient.java:443)
at org.elasticsearch.hadoop.rest.RestClient.execute(RestClient.java:437)
at org.elasticsearch.hadoop.rest.RestClient.execute(RestClient.java:397)
at org.elasticsearch.hadoop.rest.RestClient.execute(RestClient.java:401)
at org.elasticsearch.hadoop.rest.RestClient.get(RestClient.java:177)
at org.elasticsearch.hadoop.rest.RestClient.getHttpNodes(RestClient.java:134)
at org.elasticsearch.hadoop.rest.RestClient.getHttpDataNodes(RestClient.java:151)
at org.elasticsearch.hadoop.rest.InitializationUtils.filterNonDataNodesIfNeeded(InitializationUtils.java:157)
因为es不是我搭建的,所以我也很难搞。但是没关系,我刚刚不是java客户端连接上了吗? 我根据客户端查下, 其实上面的那张图片也说明了这个问题,就是怎么连接到DATANODE了呢?
添加参数
无奈,继续查找参数。
es.nodes.ingest.only
(default false) -- 这个感觉也有用懒得试了。
es.nodes.wan.only
(default false) --反正是加了这个参数就好了。其中过程复杂就不说了。
简单的理解,我们最开始写的地址没有错,但是es这个家伙会发现其他节点的ip,然后用其他ip去连,你这个为true了就只能用我写的那个了。后面看了下这个和腾讯云 阿里云部署有关。
成功案例
最后的建表语句
create external table esdata.cc_test3
(id string ,name string ,des string )
STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES(
'es.net.http.auth.user'='xxxx',
'es.net.http.auth.pass'='xxxx' ,
'es.nodes'='9.134.161.140',
'es.nodes.wan.only'='true',
'es.resource' = 'i_dw_cc_test',
'es.index.auto.create' = 'false');
count
group by
insert
遗留问题
以为到这里就大功告成了吗? 我遇到了一个最大的问题。。。。一直没说
就是我不能select * 。 上面的那个查询是可以select id,name from t group by id,name
但是tm的就是不能直接select *!!!!!!!!!!!!!!
关键是这个报错我连错误日志都看不懂,感觉就是连接hive出错了。但是select 其他都是正常呀。。 等待研究。。。。 这个报错我仔细看了下源码,好像是读取我的输入内容 也就是select *
读取之后解析的时候出问题了(我select 普通表是ok的)
又没有好心人遇到过同样的问题,留个言。
-----------2023-08-02---------------------------
最近又试了下发现这个问题神奇的自己好了。目前怀疑是和我当初在es建的index有关,但是又没有证据。
目前select insert各种正常。
但是注意
hive可以insert 和select 但是是无法truncate es的数据的!!
delete因为没有建事务表暂时不知道
进一步探索
以为到这就完了吗?还有!!
比如我上面创建外表的时候tblproperties里会有user和pass,当其他人show create table的时候就可以看到账号密码,不安全。或者其他同事也想创建es外表,但是呢es的账户又不好直接告诉别人,那怎么办?
这玩意让我想到了以前用jdbc外表的时候,也有类似的操作
jdbc外表加密
JDBC Storage Handler - Apache Hive - Apache Software Foundation
CREATE
EXTERNAL
TABLE
student_jdbc
(
name
string,
age
int
,
gpa
double
)
STORED
BY
'org.apache.hive.storage.jdbc.JdbcStorageHandler'
TBLPROPERTIES (
"hive.sql.database.type"
=
"MYSQL"
,
"hive.sql.jdbc.driver"
=
"com.mysql.jdbc.Driver"
,
"hive.sql.jdbc.url"
=
"jdbc:mysql://localhost/sample"
,
"hive.sql.dbcp.username"
=
"hive"
,
"hive.sql.dbcp.password"
=
"hive"
,
"hive.sql.table"
=
"STUDENT"
,
"hive.sql.dbcp.maxActive"
=
"1"
);
转化后
那么推断es肯定也有类似的加密措施
es外表加密
Configuration | Elasticsearch for Apache Hadoop [7.17] | Elastic
这里提到了es.keystore.location 好像是把密码放到一个文件里,然后通过文件去读取密码
点击secure settings
Security | Elasticsearch for Apache Hadoop [7.17] | Elastic
Authentication
The authentication support in elasticsearch-hadoop is of two types:
Username/Password
Set these through es.net.http.auth.user
and es.net.http.auth.pass
properties.
PKI/X.509
Use X.509 certificates to authenticate elasticsearch-hadoop to elasticsearch-hadoop. For this, one would need to setup the keystore
containing the private key and certificate to the appropriate user (configured in Elasticsearch) and the truststore
with the CA certificate used to sign the SSL/TLS certificates in the Elasticsearch cluster. That is one setup the key to authenticate elasticsearch-hadoop and also to verify that is the right one. To do so, one should setup the es.net.ssl.keystore.location
and es.net.ssl.truststore.location
properties to indicate the keystore
and truststore
to use. It is recommended to have these secured through a password in which case es.net.ssl.keystore.pass
and es.net.ssl.truststore.pass
properties are required.
--就是这里了 可以存密码
官方案例
##基础操作 $> java -classpath path/to/eshadoop.jar org.elasticsearch.hadoop.cli.Keytool <command> <args> ##创建一个文件保存密码 $> java -classpath path/to/eshadoop.jar org.elasticsearch.hadoop.cli.Keytool create $> ls esh.keystore ##查看文件里有哪些属性 $> java -classpath path/to/eshadoop.jar org.elasticsearch.hadoop.cli.Keytool list ##添加属性 交互模式 $> java -classpath path/to/eshadoop.jar org.elasticsearch.hadoop.cli.Keytool add the.setting.name.to.set ##添加属性 非交互模式 $> cat /file/containing/setting/value | java -classpath path/to/eshadoop.jar org.elasticsearch.hadoop.cli.Keytool add --stdin the.setting.name.to.set ##移除属性 $> java -classpath path/to/eshadoop.jar org.elasticsearch.hadoop.cli.Keytool remove the.setting.name.to.set
自己操作
[root@cdp-node12 /home/cclovezbf]# pwd
/home/cclovezbf
[root@cdp-node12 /home/cclovezbf]#
[root@cdp-node12 /home/cclovezbf]# ls
elasticsearch-hadoop-7.14.2.jar
[root@cdp-node12 /home/cclovezbf]# java -cp elasticsearch-hadoop-7.14.2.jar org.elasticsearch.hadoop.cli.Keytool create
[root@cdp-node12 /home/cclovezbf]# ls
elasticsearch-hadoop-7.14.2.jar esh.keystore
[root@cdp-node12 /home/cclovezbf]# java -cp elasticsearch-hadoop-7.14.2.jar org.elasticsearch.hadoop.cli.Keytool add es.net.http.auth.user
Enter value for es.net.http.auth.user: xxxx
[root@cdp-node12 /home/cclovezbf]# java -cp elasticsearch-hadoop-7.14.2.jar org.elasticsearch.hadoop.cli.Keytool list
es.net.http.auth.user
然后我久兴高采烈的
create external table if not exists dwintdata_es.dw_f_da_websites2
(
`eid` string COMMENT '新企业编码EID',
`source_eid` string COMMENT '数据源企业编码EID',
`web_type` string COMMENT '网址类型',
`web_name` string COMMENT '网址名称',
`web_url` string COMMENT '网址',
`date` string COMMENT '获取日期',
`local_row_update_time` string COMMENT '合合备库数据更新时间',
`etl_create_time` string COMMENT 'Kudu数据更新时间',
`etl_update_time` string COMMENT 'DW数据更新时间',
data_source string
)
STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES (
'es.net.http.auth.pass' = 's2@enterprise',
'es.keystore.location' = '/home/cclovezbf/esh.keystore',
'es.nodes' = '9.134.161.140',
'es.nodes.wan.only' = 'true',
'es.index.auto.create' = 'false',
'es.resource' = 'i_dm_f_da_websites'
);
神奇的是昨天晚上这样建表后就ok了。也能select, 我今天感觉不对,想把文件放到hdfs上就把昨天的表删除了,结果今天建的也不能查了,昨天的表也删除了,找不到语句了,真是他妈的服了。
Error: java.io.IOException: org.elasticsearch.hadoop.EsHadoopIllegalArgumentException: Expected to find keystore file at [hdfs://s2cluster/user/hive/esh.keystore] but was unable to. Make sure that it is available on the classpath, or if not, that you have specified a valid file URI. (state=,code=0)
无奈之下继续看官网
Once your settings are all specified, you must make sure that the keystore is available on every node. This can be done by placing it on each node’s local file system, or by adding the keystore to the job’s classpath. Once the keystore has been added, its location must be specified with the
es.keystore.location
. To reference a local file, use a fully qualified file URL (exfile:///path/to/file
). If the secure store is propagated using the command line, just use the file’s name.
这里说了两种办法
1.是每个节点的文件系统都放keystore
2.是add keystore 我理解为 add jar/add file一样
难搞啊