使用Hive或Impala執行SQL語句,對存儲在Elasticsearch中的數據操做(二)

使用Hive或Impala執行SQL語句,對存儲在Elasticsearch中的數據操做

Hive Impala Elasticsearch Hadoop SQLjavascript


 

摘要:css

使用Elasticsearch-SQL能夠對存儲在Elasticsearch中的數據執行簡單的SQL查詢操做,然而並不支持多表join等聯接查詢。
Hive是基於Hadoop的一個數據倉庫工具,能夠將結構化的數據文件映射爲一張數據庫表,並提供簡單的SQL查詢功能,能夠將SQL語句轉換爲MapReduce任務進行運行。
所以若是Hive能夠從Elasticsearch中取數據,並結合Hive的SQL查詢功能,便能作到較爲複雜的SQL查詢操做。html

咱們的目標是:html5

  1. 支持Elasticsearch多表聯接查詢;
  2. 結合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簡介

Elasticsearch是一個基於Apache Lucene(TM)的開源搜索引擎。它基於RESTful web接口,提供實時、穩定、可靠的分佈式服務。node

Elasticsearch的數據類型

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的數據類型

相應的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執行SQL語句

要打通Elasticsearch與Hive,須要Elasticsearch for Apache Hadoop下的elasticsearch-hadoop-hive。
Elasticsearch for Apache Hadoop提供了三類解決方案:Elasticsearch on YARN、repository-hdfs、elasticsearch-hadoop proper。
詳情查看:Elasticsearch for Apache Hadoopgit

建立Hive外部表

先有Hive再有Elasticsearch

在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中直接對ElasticSearch中數據進行操做。
便是在Hive中執行以上建立ES外部表的命令,便可以在Hue中看到ElasticSearch中的數據。
如下是幾種典型的建立Hive外部表命令:

  • 在Hive指定decimal數據類型
  
  
  
  
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

向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;
  
  
  
  
#向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中的數據進行操做時,要注意使用雙方均支持的數據類型。

從Elasticsearch讀

咱們選擇如下幾條有表明性的SQL查詢語句,來驗證使用Hive能夠對存儲在Elasticsearch中的數據進行正確的查詢操做。

where子句

  
  
  
  
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很好的執行了。

Double數據類型求和

  
  
  
  
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精確統計,並不是一個好辦法。

數據存儲在Elasticsearch上,使用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沒有達成。

相關文章
相關標籤/搜索