首先直接上干貨:
步驟
- 導入elasticsearch-hadoop-hive-5.5.2.jar包
- 創(chuàng)建hive外部表逝撬,數(shù)據(jù)源設置為es中,添加相應的配置
- 創(chuàng)建內(nèi)部表拉取數(shù)據(jù)
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' -- 是否自動創(chuàng)建索引
'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元數(shù)據(jù)字段
'es.mapping.names' -- es 和hive 字段映射
#分頁查詢
select * from estest.ext_es_test_bumsg limit 10;
#創(chuàng)建內(nèi)部表分頁查詢
drop table if exists itn_es_test;
create table itn_es_testas
select * from estest.itn_es_test;
遇到的問題:
es中字段較多,不需要導出所有字段拦键。
解決: 通過'es.mapping.names' 配置篩選所需要的字段谣光。在hadoop-2.8版本下導出的時候經(jīng)常會報Error: java.lang.ClassNotFoundException: org.apache.commons.httpclient.util.xxxx,但是hive/lib目錄下確實有該類芬为。手動添加后還是無法解決
解決: 將版本切到2.7不會出現(xiàn)該問題萄金,但是根本原因還是沒有找到,待解決媚朦。
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包內(nèi)容。發(fā)現(xiàn)hadoop-2.8.1/share/hadoop/common/lib目錄下少了commons-httpclient-3.1.jar询张,由于本地hadoop2.8是編譯安裝的,所以懷疑是編譯安裝的時候沒有將該依賴包打進去孙乖,對比官方下載的hadoop2.8二進制包發(fā)現(xiàn)也沒有該jar包。
通過查看hadoop-2.8。0的change-log(https://issues.apache.org/jira/browse/HADOOP-13382)
接下來唯袄,只需將es-hadoop依賴的commons-httpclient jar加入到所有的hadoop節(jié)點即可弯屈。
- hadoop classpath | tr ':' '\n'
- es中導出的Date類型數(shù)據(jù)既有時間戳也有日期字符串,在存取到hive的時候發(fā)現(xiàn)以下問題恋拷;
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處理該異常蔬顾,將所有時間格式字符串統(tǒng)一格式輸出宴偿。
通過查看elasticsearch-hadoop的源碼,發(fā)現(xiàn)es-hadoop在解析Date類型的時候使用的是DatatypeConverter.parseDateTime(value)诀豁。(無法應對我們自定義的各種時間格式酪我,甚至包括UTC時區(qū)的時間。)
@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()));
}
- 最后遇到一個小問題逞带,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國內(nèi)資料比較雜亂遇汞,很多都還是2.x的未妹。
建議研讀官方文檔,es這塊配置項比較多空入,而且很多功能也許在配置項中已經(jīng)可以找到解決方案了络它,缺乏的是仔細去研讀和加深理解。這個我自己也正在學習的路上歪赢,哈哈化戳!
另外,es-hadoop導出性能一般埋凯,20m/s左右点楼,3個節(jié)點。有待提升白对,有時間可以對比下es-spark和java api效果掠廓。