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 结果如下
问题解决。