Hive
Impala
Elasticsearch
Hadoop
SQL
javascript
摘要:css
使用Elasticsearch-SQL能夠對存儲在Elasticsearch中的數據執行簡單的SQL查詢操做,然而並不支持多表join等聯接查詢。
Hive是基於Hadoop的一個數據倉庫工具,能夠將結構化的數據文件映射爲一張數據庫表,並提供簡單的SQL查詢功能,能夠將SQL語句轉換爲MapReduce任務進行運行。
所以若是Hive能夠從Elasticsearch中取數據,並結合Hive的SQL查詢功能,便能作到較爲複雜的SQL查詢操做。html
咱們的目標是:html5
- 支持Elasticsearch多表聯接查詢;
- 結合Elasticsearch搜索引擎提升SQL查詢效率。
CentOS-6.5
hive:hive-0.13.1+cdh5.3.6+397
impala:impala-2.1.5+cdh5.3.6+0
spark:spark-1.2.0+cdh5.3.6+379
elasticsearch:elasticsearch-1.7.1
elasticsearch-hadoop-hive:elasticsearch-hadoop-hive-2.1.1java
Elasticsearch是一個基於Apache Lucene(TM)的開源搜索引擎。它基於RESTful web接口,提供實時、穩定、可靠的分佈式服務。node
ES使用JSON做爲數據交互格式,因此簡單來講,JSON支持的數據類型,ES都支持。 linux
String: string Whole number: byte, short, integer, long Floating point: float, double Boolean: boolean Date: date
除了以上Core Types(核心數據類型),還有:Array Type、Object Type、Root Object Type、Nested Type、IP Type、Geo-point Type、Geo Shap Type、Attachment Type等。android
相應的Solr的數據類型有:css3
BCDIntField | BCDLongField | BCDStrField | BinaryField | BoolField |
---|---|---|---|---|
二進制整形字段 | 二進制長整形字段 | 二進制字符型字段 | 二進制數據 | 包含true或者false,值的第一個字符若是是一、t、T均表示true,其餘爲false |
ByteField | DateField | DoubleField | ExternalFileField | FloatField |
一個字節數據 | 一個精確到毫秒的時間值 | |||
IntField | Location | LongField | Point | RandomSortField |
方位搜索用到,存經緯度值 | N維點搜索,在藍圖或者CAD圖中使用 | 不包含值,當查詢時按這種類型的字段排序時會產生隨機排序。使用該特性時須要是一個動態字段 | ||
ShortField | StrField | TextField | UUIDField | |
UTF-8編碼的字符串或Unicode | 文本類型,通常包含多個單詞或漢字 | 惟一識別碼,單傳入的值是「NEW」時,Solr將爲其建立1個UUID值 |
要打通Elasticsearch與Hive,須要Elasticsearch for Apache Hadoop下的elasticsearch-hadoop-hive。
Elasticsearch for Apache Hadoop提供了三類解決方案:Elasticsearch on YARN、repository-hdfs、elasticsearch-hadoop proper。
詳情查看:Elasticsearch for Apache Hadoop。git
在Elasticsearch中並沒有表,甚至並沒有Elasticsearch服務時,能夠經過執行如下語句在Hive中建立一個新的外部表。
#在Hive中建立一個新的外部表 hive> CREATE EXTERNAL TABLE hive_es_angel( id BIGINT, name STRING) STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler' TBLPROPERTIES('es.nodes'='192.168.181.190','es.resource' = 'indexname/typename');
這裏指定了ES的地址與索引名和類型名(index-type)。經過執行此語句,即可以在Hive查看到結構正確的表。
注意:
elasticsearch-hadoop will always convert Hive column names to lower-case,就是說創建起的Hive表中全部字段均變爲小寫。
在執行此語句後,並不會在ElasticSearch中創建指定的索引與類型,只有當後續在Hive中執行SQL插入語句時,纔會在ElasticSearch中創建指定的索引與類型,並插入相關數據。
執行此語句並不會拋出錯誤,這與HBase和Hive創建關聯時的狀況不同,建立HBase外部表時須要查看HBase中信息。 更多細節能夠查看《使用Hive或Impala執行SQL語句,對存儲在HBase中的數據操做》一文。
在ElasticSearch中已有索引和類型,甚至在其中存儲有數據時,咱們能夠在Hive中直接對ElasticSearch中數據進行操做。
便是在Hive中執行以上建立ES外部表的命令,便可以在Hue中看到ElasticSearch中的數據。
如下是幾種典型的建立Hive外部表命令:
CREATE EXTERNAL TABLE hive_es_decimal( price DECIMAL(12,2) ) STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler' TBLPROPERTIES('es.nodes'='192.168.181.160','es.resource' = 'indexname/typename');
默認狀況下,是以列名稱與ES映射的,注意:elasticsearch-hadoop will always convert Hive column names to lower-case,此時ES列名也必須小寫,不然映射不上。
經驗證,以上語句有問題。如Hive定義爲Decimal,而ES只能Double,會出現org.apache.hadoop.hive.serde2.io.DoubleWritable cannot be cast to org.apache.hadoop.hive.serde2.io.HiveDecimalWritable
錯誤。
CREATE EXTERNAL TABLE hive_es_map( price DOUBLE, itemid BIGINT, myname STRING ) STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler' TBLPROPERTIES('es.nodes'='192.168.181.160','es.resource' = 'indexname/typename','es.mapping.names' = 'itemid:itemId, myname:myName, devicenumber:deviceNumber');
在建立Hive外部表時指定映射關係時,也須要對應好數據類型,不然也會出現相似數據類型轉換失敗錯誤。
注意:
從ES的date數據類型轉換到Hive的date/timestamp數據類型,均出錯,出錯信息爲:java.io.IOException: java.lang.IllegalArgumentException: 2015-06-03T14:54:46+0800
hive> add jar /opt/cloudera/parcels/CDH-5.3.6-1.cdh5.3.6.p0.11/lib/hive/lib/elasticsearch-hadoop-hive-2.1.1.jar;
#向ES中導入Hive中表sample_07數據 hive> INSERT OVERWRITE TABLE hive_es_test SELECT s.id, s.code FROM sample_07 s;
當Elasticsearch中不存在相應索引時,通過執行以上插入語句,在Elasticsearch中就會建立一個新索引:indexname,新類型:typename(固然是在Hive建立新外部表時指定好的),數據也已經添加入其中。
沒有指定列映射類型時,下面是部分默認狀況下的Hive與ElasticSearch數據類型映射關係。
Hive | ES | 默認映射結果 |
---|---|---|
bigint | long | 無問題 |
timestamp | date | 無問題 |
double | double | 無問題 |
date | string | 有問題 |
decimal | string | 有問題 |
注意:
能夠看到有問題的映射是兩端不能匹配的映射。當存在有問題的映射時,在Hive中執行SELECT * FROM table_decimal
時會拋出異常:
Failed with exception java.io.IOException:org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.ClassCastException: org.apache.hadoop.io.Text cannot be cast to org.apache.hadoop.hive.serde2.io.HiveDecimalWritable
即數據類型從ElasticSearch到Hive數據類型轉換失敗。可見,在使用Hive對存儲在ElasticSearch中的數據進行操做時,要注意使用雙方均支持的數據類型。
咱們選擇如下幾條有表明性的SQL查詢語句,來驗證使用Hive能夠對存儲在Elasticsearch中的數據進行正確的查詢操做。
hive> add jar /opt/cloudera/parcels/CDH-5.3.6-1.cdh5.3.6.p0.11/lib/hive/lib/elasticsearch-hadoop-hive-2.1.1.jar; hive> select count(*) from hive_es_angel where id>1000;
在執行此語句時,能夠看到map-reduce的執行過程:
Hadoop job information for Stage-1: number of mappers: 5; number of reducers: 1 2015-10-15 14:30:28,181 Stage-1 map = 0%, reduce = 0% 2015-10-15 14:30:38,623 Stage-1 map = 2%, reduce = 0%, Cumulative CPU 4.07 sec 2015-10-15 14:30:39,678 Stage-1 map = 4%, reduce = 0%, Cumulative CPU 8.8 sec 2015-10-15 14:30:41,766 Stage-1 map = 5%, reduce = 0%, Cumulative CPU 9.36 sec
這說明,Hive在執行此語句時,並無用到Elasticsearch創建的索引,以使查詢效率更高,而是將Elasticsearch相應數據所有獲取下來。
注意:
Hive並無用到Elasticsearch查詢高效的好處。
hive> add jar /opt/cloudera/parcels/CDH-5.3.6-1.cdh5.3.6.p0.11/lib/hive/lib/elasticsearch-hadoop-hive-2.1.1.jar; hive> select * from hive_es_angel left join sample_08 on hive_es_angel.name=sample_08.code;
其中sample_08表是Hive普通表,hive_es_angel是數據存儲在HBase中的Hive外表。
經驗證,經過執行上面語句,能夠將Hive普通表與Hive的Elasticsearch外表進行正確的關聯。
這樣一來,ES的SQL插件elasticsearch-sql所不能完成的join等查詢語句,即可以經過Hive很好的執行了。
hive> add jar /opt/cloudera/parcels/CDH-5.3.6-1.cdh5.3.6.p0.11/lib/hive/lib/elasticsearch-hadoop-hive-2.1.1.jar; hive> SELECT SUM(field_double) FROM hive_es_double;
因爲ElasticSearch並不支持decimal數據類型,故只能在Hive中對小數列建立double數據類型,這時使用Hive也沒法進行精確求和,這在須要進行小數精確統計時,是一大問題。
Solr也有此缺陷,可見目前ES、Solr天生不適合進行精確計算。故將數據放在ES中,使用Hive或Impala進行SQL精確統計,並不是一個好辦法。
hive中創建的普通表,impala能夠讀取使用。執行join語句時,impala明顯比hive快不少。在impala中執行INVALIDATE METADATA 、 REFRESH table_name語句以便 Impala 識別新的或已更改的數據。
可是,對於EXTERNAL TABLE數據存放在ES上的,Hive SQL能夠正確執行,Impala SQL執行不正確,出錯信息以下所示。
ERROR: AnalysisException: Failed to load metadata for table: default.hive_table CAUSED BY: TableLoadingException: Unrecognized table type for table: default. es_table
可見使用elasticsearch-hadoop來作Impala計算,是不可行的。相比較下,數據存儲在HBase中,使用Impala執行SQL語句卻沒有問題。具體能夠查看《使用Hive或Impala執行SQL語句,對存儲在HBase中的數據操做》一文。
數據存儲在Elasticsearch中,使用Hive進行SQL操做,並非一個好主意,這是因爲ES的數據類型所限致使的ES與Hive的數據類型對應問題,而且Hive並不能用到Elasticsearch創建的索引的高效查詢好處。雖然以上方案能夠解決使用Hive對Elasticsearch較複雜SQL語句查詢,但不方便也不高效,且Impala也不能支持。 故,目標1達成,但目標2沒有達成。