Hive連接MongoDB
Hive上創建的表可以是HDFS-based,也可以是MongoDB-based。MongoDB-based的Hive表,其實就是一個將MongoDB collection的數據與Hive表的字段相關聯的映射。實施的步驟如下:
安裝
- 下載Hadoop Connector。可以從Maven的倉庫裏面下載http://repo1.maven.org/maven2/org/mongodb/mongo-hadoop/。其中需要使用到的有“core” JAR與“hive” JAR。
- 下載MongoDB Java Driver的JAR包。
- 將這些JAR包複製到Hadoop集羣的每個節點。可以用Hadoop DistributedCache將這些JAR包複製到集羣的每個節點,也可以將這些JAR包放到Hadoop的CLASSPATH下,如($HADOOP_PREFIX/share/hadoop/common)。
- 在Hive腳本里面,使用
ADD JAR
的命令來包含這些JAR包(core,hive以及Java driver),如ADD JAR /path-to/mongo-hadoop-hive-<version>.jar;
備註:上述JAR包不一定要放在Hadoop的CLASSPATH下,可以放在任意路徑,在ADD JAR $JAR_PATH
的時候將存放JAR包的路徑帶上即可。如
版本要求
Mongo-Hadoop支持Hive版本>=0.9。
支持Hadoop版本大於0.20.x。支持CDH4。
示例
CREATE TABLE individuals
(
id INT,
name STRING,
age INT,
work STRUCT<title:STRING, hours:INT>
)
STORED BY 'com.mongodb.hadoop.hive.MongoStorageHandler'
WITH SERDEPROPERTIES('mongo.columns.mapping'='{"id":"_id","work.title":"job.position"}')
TBLPROPERTIES('mongo.uri'='mongodb://localhost:27017/test.persons');
新創建的表individual是一個基於MongoDB的Hive表,通過Hive查詢這個表的方式與查詢基於HDFS的Hive表的方式是一樣的。
SELECT name, age
FROM individuals
WHERE id > 100;
其實這就相當於創建了一個映射,將存儲在MongoDB裏面的數據映射到Hive的表上,但是所有的數據還是存在於MongoDB中。
連接MongoDB - MongoStorageHandler
創建基於MongoDB的Hive表是通過MongoStorageHandler來處理的。它同樣處理從Hive表裏查詢與插入數據(通過select
與insert
)。
CREATE [EXTERNAL] TABLE <tablename>
(<schema>)
STORED BY 'com.mongodb.hadoop.hive.MongoStorageHandler'
[WITH SERDEPROPERTIES('mongo.columns.mapping'='<JSON mapping>')]
TBLPROPERTIES('mongo.uri'='<MongoURI>');
有兩種方式來指定所需連接的Mongo Collection。
1. 在上述示例裏面,通過mongo.uri
這個表屬性來指定,屬性的值填入的是MongoDB connection string,通過它來指向具體的collection。這種方式會將這個URI存入表的metadata裏面,如果需要填寫連接的一些認證信息(如username:password
等),該方式不太適合。
2. 第二種方式是把connection string填入一個properties文件,如:
# HiveTable.properties
mongo.input.uri=mongodb://...
然後提供這個文件的路徑給mongo.properties.path
這個表參數,如
CREATE TABLE ...
TBLPROPERTIES('mongo.properties.path'='HiveTable.properties')
備註:在創建相應Hive表時所引用的MongoDB collection不一定要空的。
在創建Hive表的時候,也可以選擇性的指定MongoDB collection裏的字段與Hive的列字段或struct字段的映射。指定的方式是在SERDEPROPERTIES裏通過mongo.columns.mapping
屬性來指定。在創建基於BSON文件的Hive表時也可以用到。
如果創建的表是EXTERNAL
的,那麼在Hive裏刪除這張表時,不會影響MongoDB裏面的數據,只會刪除這張表的metadata。如果沒有指定EXTERNAL
,那麼刪除表的時候會連帶MongoDB裏的數據一併刪除,因此最好是指定創建的表爲EXTERNAL
。
MongoStorageHandler的侷限
- INSERT INTO vs. INSERT OVERWRITE:目前任何通過StorageHandler創建的表都沒有辦法區分這兩個命令。
遇到的問題及解決方法
在建立好MongoDB-based的hive表之後,select * from table 都可以正確的查表。接着想將該表的數據導入HDFS-based的hive表。如
insert into table hdfs_based_table
select * from mongodb_based_table;
但是一直執行不成功,運行結果如下
這裏的提示信息還是太少,只看這些很難想到問題所在。因此可以看一下hive.log。
在log裏面發現,執行insert into 的時候,就會出現如下的失敗信息,然後就是重試一定的次數直到任務失敗。
對比執行select查表的日誌發現,select語句的執行並沒有用到Tez,而insert into的時候試圖使用Tez,所以問題可能出現在使用Tez上,因爲之前下載的mongo-hadoop-connector的JAR包可能只是支持map reduce計算框架的,還不支持Tez。因此可以嘗試一下將計算引擎換成map reduce。
如果是用Ambari,切換的方式爲,在Ambari的控制頁面下,選擇Hive -> Configs -> Optimization 下的Execution Engine爲Map Reduce,然後重啓Hive即可。 如下圖
重啓了Hive以後,重新執行insert into 結果如下
問題解決。