由于数据需要经常改动,所以将数据存储在Hbase中,通过Hive关联Hbase表的方式来对Hbase进行查询操作。
原先我是在本地通过虚拟机搭建的伪分布式,因此做Hive关联Hbase操作时需要做不少的操作,比如将Hbase相关的jar添加到Hive,将Hbase配置文件添加到hadoop/conf目录下等。具体操作可见如下文章:
http://blog.csdn.net/u013850277/article/details/73522538目前的平台为:HDP 并且通过Ranger做了权限管理。因为用了Hdp, 如果要用Hive 关联Hbase表则不需要再进行则不需要做任何额外的操作。直接可以通过建立Hive表就可以关联Hbase了。
建立Hive表关联Hbase表,有两种方式:建立Hive 内部表(对应的Hbase表不存在),另一种方式是建立Hive外部表(Hbase表以存在)。
Hive内部表的方式,创建表成功后,Hbase中同时自动创建对应的Hbase表,且数据是保存在Hbase中,如果删除Hive表,Hbase表同时也会被删除掉。
Hive 外部表的方式,创建成功后,数据同样保存在Hbase,只不过Hive表删除不会影响到Hbase表。
Hive表关联查询Hbase时,默认配置查询出来的结果总是Hbase最新版本所对应的数据。
异常一: Hive 操作时缺少Hbase对应的 jar包
在hdp46 机器上通过Hive连接Hbase出现如下错(这个hdp46号机器,目前装了 Hive的client,并没有安装Hbase对应的Client)
hive> CREATE TABLE IF NOT EXISTS t_hive_hbase10(id string, cards String, salary string) STORED BY "org.apache.hadoop.hive.hbase.HBaseStorageHandler" WITH SERDEPROPERTIES ( "hbase.columns.mapping" = ":key,info:id,info:salary") TBLPROPERTIES ("hbase.table.name" ="t_hive_hbase10");
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/hbase/client/Connection
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.apache.hadoop.hive.ql.parse.ParseUtils.ensureClassExists(ParseUtils.java:230)
at org.apache.hadoop.hive.ql.parse.StorageFormat.fillStorageFormat(StorageFormat.java:64)
at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.analyzeCreateTable(SemanticAnalyzer.java:11114)
at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.genResolvedParseTree(SemanticAnalyzer.java:10316)
at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.analyzeInternal(SemanticAnalyzer.java:10401)
at org.apache.hadoop.hive.ql.parse.CalcitePlanner.analyzeInternal(CalcitePlanner.java:216)
at org.apache.hadoop.hive.ql.parse.BaseSemanticAnalyzer.analyze(BaseSemanticAnalyzer.java:230)
at org.apache.hadoop.hive.ql.Driver.compile(Driver.java:464)
at org.apache.hadoop.hive.ql.Driver.compile(Driver.java:320)
at org.apache.hadoop.hive.ql.Driver.compileInternal(Driver.java:1219)
at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:1260)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1156)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1146)
at org.apache.hadoop.hive.cli.CliDriver.processLocalCmd(CliDriver.java:217)
at org.apache.hadoop.hive.cli.CliDriver.processCmd(CliDriver.java:169)
at org.apache.hadoop.hive.cli.CliDriver.processLine(CliDriver.java:380)
at org.apache.hadoop.hive.cli.CliDriver.executeDriver(CliDriver.java:740)
at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:685)
at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:625)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.util.RunJar.run(RunJar.java:233)
at org.apache.hadoop.util.RunJar.main(RunJar.java:148)
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.hbase.client.Connection
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)
... 27 more
解决方案一:
根据报错将对应的Hbase的jar包copy一份到Hive中的lib目录下。
解决方案二:hdp46通过ambari安装一个hbase的client。因为笔者这个平台是通过Ambari+hdp搭建的,所方案二就显得很方便了。直接通过,ambari 的管理界面选择添加一个client。
异常二:权限问题
笔者以前习惯通过Hive外部表管理非Hive中的数据,所以这里也同样采用外部表的方式。
1、在Hive中通过如下语句创建时出现异常(org.apache.hadoop.hive.ql.exec.DDLTask. MetaException(message:org.apache.hadoop.hbase.TableNotFoundException)
hive> CREATE EXTERNAL TABLE IF NOT EXISTS t_hbase10(id string, cards String, salary string) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ('hbase.columns.mapping' = ':key,info:id,info:salary') TBLPROPERTIES ('hbase.table.name' ='t_hbase10')
> ;
异常详情如下所示:
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException(message:org.apache.hadoop.hbase.TableNotFoundException: t_hbase10
at org.apache.hadoop.hbase.client.HBaseAdmin.getTableDescriptor(HBaseAdmin.java:572)
at org.apache.hadoop.hbase.client.HBaseAdmin.getTableDescriptor(HBaseAdmin.java:545)
at org.apache.hadoop.hbase.client.HBaseAdmin.getTableDescriptor(HBaseAdmin.java:577)
at org.apache.hadoop.hive.hbase.HBaseStorageHandler.preCreateTable(HBaseStorageHandler.java:245)
at org.apache.hadoop.hive.metastore.HiveMetaStoreClient.createTable(HiveMetaStoreClient.java:690)
at org.apache.hadoop.hive.metastore.HiveMetaStoreClient.createTable(HiveMetaStoreClient.java:683)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.hive.metastore.RetryingMetaStoreClient.invoke(RetryingMetaStoreClient.java:159)
at com.sun.proxy.$Proxy5.createTable(Unknown Source)
at org.apache.hadoop.hive.ql.metadata.Hive.createTable(Hive.java:757)
at org.apache.hadoop.hive.ql.exec.DDLTask.createTable(DDLTask.java:4322)
at org.apache.hadoop.hive.ql.exec.DDLTask.execute(DDLTask.java:314)
at org.apache.hadoop.hive.ql.exec.Task.executeTask(Task.java:160)
at org.apache.hadoop.hive.ql.exec.TaskRunner.runSequential(TaskRunner.java:89)
at org.apache.hadoop.hive.ql.Driver.launchTask(Driver.java:1745)
at org.apache.hadoop.hive.ql.Driver.execute(Driver.java:1491)
at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:1289)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1156)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1146)
at org.apache.hadoop.hive.cli.CliDriver.processLocalCmd(CliDriver.java:217)
at org.apache.hadoop.hive.cli.CliDriver.processCmd(CliDriver.java:169)
at org.apache.hadoop.hive.cli.CliDriver.processLine(CliDriver.java:380)
at org.apache.hadoop.hive.cli.CliDriver.executeDriver(CliDriver.java:740)
at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:685)
at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:625)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.util.RunJar.run(RunJar.java:233)
at org.apache.hadoop.util.RunJar.main(RunJar.java:148)
)
hive>
原因: 通过Hive关联Hbase,也就是要通过Hive创建Hbase相关的关联表,这个Hive用户必须得拥有操作Hbase的相关权限。但是,笔者事先并没有对Hive授予操作Hbase表的权限。
解决方法:
给 Hive 用户授权(授予Hive拥有操作Hbase对应表的权限),如下图所示:
再次创建验证
hive> CREATE EXTERNAL TABLE IF NOT EXISTS t_hbase10(id string, cards String, salary string) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ('hbase.columns.mapping' = ':key,info:id,info:salary') TBLPROPERTIES ('hbase.table.name' ='t_hbase10');
OK
Time taken: 0.281 seconds
hive> show tables;
OK
t_hbase10
Time taken: 0.158 seconds, Fetched: 11 row(s)
hive>
解决问题的过程:
因为一开始笔者觉得Ambari 这个管理工具还是挺不错的,像Hive关联Hbase这类操作的相关配置应该自带了,所以试着在没有进行任何相应的配置情况下便直接使用了。但是,出现异常后,异常信息并没有很明显表明是没有相关权限,便想着是不是还得进行相应的配置才可以使用(因为笔者发现Hive中确实没有Hbase相应的jar)。进行了相应的配置完后,结果还是有同样的异常出现。无奈,只能将相应的配置进行了还原。后来试了下通过Hive建立内部表的方式,出现了如下异常:
CREATE TABLE IF NOT EXISTS t_hive_hbase10(id string, cards String, salary string) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ('hbase.columns.mapping' = ':key,info:id,info:salary') TBLPROPERTIES ('hbase.table.name' ='t_hive_hbase10')
java.sql.SQLException: Error while processing statement: FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException(message:org.apache.hadoop.hbase.security.AccessDeniedException: org.apache.hadoop.hbase.security.AccessDeniedException: Insufficient permissions for user 'hive/hdp40@BBDATA.COM' (action=create)
看到这个异常才想起应该是权限问题,也就是说要通过Hive创建Hbase相关的关联表,这个Hive用户必须得拥有操作Hbase的相关权限。