你可以使用 Impala 查询 HBase 表。这一能力允许方便的访问一种相对默认的 Impala 而言针对不同类型的负载调优的存储系统(This capability allows convenient access to a storage system that is tuned for different kinds of workloads than the default with Impala)。默认的 Impala 表使用存放在 HDFS 中的数据文件,它非常适合批量加载和使用全表扫描的查。相比之下,HBase 可以对查找个别行或某个范围值的 OLTP 类型的工作负载的数据执行高效查询(In contrast, HBase can do efficient queries for data organized for OLTP-style workloads, with lookups of individual rows or ranges of values)。
对于具有 RDBMS 背景的 Impala 用户来说,HBase 是一种键-值(key-value)存储,值包括多个字段。键映射到 Impala 标准的一个列,并且值中不同的字段被映射到 Impala 表中其他的列。
当你使用 Impala 访问 HBase 时:
为了在 Impala 中使用 HBase 表,请确保 impala 用户具有 HBase 表的 read/write 权限,在 HBase shell 中使用 GRANT 命令授予。关于 HBase 安全的详细信息,参见 http://hbase.apache.org/book/hbase.accesscontrol.configuration.html。
继续阅读:
为了理解 Impala 列数据类型如何映射到 HBase 字段,首先你应当有一些 HBase 的背景知识。你通过在 Hive shell 中执行 CREATE TABLE 语句设置这些映射。参见 the Hive wiki 起点,已经 Examples of Querying HBase Tables from Impala 查看例子。
HBase 以一种"bit Bucket"的方式工作,从这个意义上说,HBase 不限制键和值字段的类型,所有的类型限制都是在 Impala 侧(HBase works as a kind of "bit bucket", in the sense that HBase does not enforce any typing for the key or value fields. All the type enforcement is done on the Impala side)。
为了 Impala 查询 HBase 表的最佳性能,绝大多数查询将在 WHERE 子句中对 HBASE row key 列进行比对。当通过 Hive shell 创建了表时,对应 HBase row key 使用 STRING 数据类型。Impala 可以转换条件测试(通过操作符如 =,< BETWEEN,IN)转换为 HBase 的快速查找(fast lookups),但是这一优化("谓词下推")仅当列定义为 STRING 时有效(Impala can translate conditional tests (through operators such as =, <, BETWEEN, and IN) against this column into fast lookups in HBase, but this optimization ("predicate pushdown") only works when that column is defined as STRING)。
自 Impala 1.1 开始,Impala 同样支持在 Hive CREATE TABLE 语句中使用二进制数据类型定义的列的读取和写入,在 Hive 表定义中使用 #binary 关键字定义,通常缩写为 #b。定义数字列为二进制可以减少 HBase 表的总数据量。你还是需要定义 HBase row key 为 STRING,以便于这系列的快速查找。
要了解针对存储在 HBase 中数据的 SQL 查询的性能特点,首先你应当具有关于 HBase 和 面向 SQL 系统交互的背景知识。参见 the Hive wiki 获得起点知识;因为 Impala 与 Hive 共享相同的 metastore 数据库,Hive 表到 HBase 表的列的映射信息也适用于 Impala。
Impala 使用 HBase 客户端 API 通过 Java Native Interface (JNI) 查询存放在 HBase 中的数据。这些查询不会直接读取 HFiles 。额外的通信开销使得选择哪些数据存放在 HBase 或 HDFS 中,以及构造可以快速从 HBase 获取数据的高效查询变得很重要:
查询的谓词以开始和结束的键值应用到 row key上,从而限制了特定的查询范围。假如 row key 没有映射成字符串列,这时候排序通常不正确并且比较操作通常不工作。例如,假如 row key 没有映射到字符串列,评估大于(>)或小于(<)无法完成。
在非键列上的谓词可以作为 SingleColumnValueFilters 发送到 HBase 进行扫描,提供一些性能提升。在这时候,HBase 会返回比这些谓词直接在 Impala 中使用更少的行。虽然这样会有一些改进,但是没有使用开始和结束行的效果那么大。这是因为只要使用了开始和结束行之后,HBase 必须检查的行数没有限制(This is because the number of rows that HBase must examine is not limited as it is when start and stop rows are used)。只有 row key 谓词仅仅对单行使用,HBase 将定位并返回这一行。相反地,如果一个非键列上的谓词被使用,即使它仅适用于单行,HBase 也必须扫描整个表来查找到正确的结果。
假如你有调用 org.apache.hadoop.hbase.client.Scan 类的 setCacheBlocks 或 setCaching 方法的 HBase Java 应用,你可以通过 Impala 查询选项设置这些相同的缓存行为,来控制 HBase region server 上的内存压力。例如,当在 HBase 上执行全表扫描(对 HBase 默认是低效的)的查询,你可以减少内存使用并通过关闭 HBASE_CACHE_BLOCKS 设置并设置 HBASE_CACHING 为较大的值来加速。
请在 impala-shell 中执行类似下面的命令,设置这些选项:
-- 与调用 setCacheBlocks(true) 或 setCacheBlocks(false) 方法相同 set hbase_cache_blocks=true; set hbase_cache_blocks=false; -- 与调用 setCaching(rows) 方法相同 set hbase_caching=1000;
Or update the impalad defaults file /etc/default/impala and include settings for HBASE_CACHE_BLOCKS and/or HBASE_CACHING in the -default_query_options setting for IMPALA_SERVER_ARGS. SeeModifying Impala Startup Options for details.
以下是常见的使用 Impala 查询 HBase 表的使用情况:
在 HBase 中存放非常宽的表。宽表包括很多很可能上千的列,通常记录重要主题的许多属性,如在线服务的用户信息。这些表通常是稀疏的,也就是说,这些列的绝大多数的值为 NULL, 0, false, 空字符串, 或其他的空格或占位符值(例如,任意网站的特定用户,可能从不会使用这个网站的某些功能,填写他们个人资料的某些部分,访问网址的特定部分,如此等等)。针对这种表的典型的查询是查找单行数据返回关于特定主题的所有信息,而不是像通常的 Impala 管理表那样求和、计算均值、或过滤几百万行的记录。
或者 HBase 表可以与一个大的 Impala 管理表来进行连接。例如,分析对应网站流量的大的 Impala 表,找出访问页面最多的前 50 名用户。把这个结果与 HBase 中宽用户表连接,查找这些用户的属性。连接中 HBase 端将进行 50 次高效的单行查找,而不是扫描整个用户表。
对于 HBase 表,Impala INSERT 语句同样有效。INSERT ... VALUES 语法对 HBase 表非常适合,因为对于 HBase 表来说,插入单行是高效操作(对于正常的、数据文件存放在 HDFS 中的 Impala 表,INSERT ... VALUES 语句会产生小的数据文件,极其低效,因此对于包含大量的数据的表不要使用这一技术)。
当使用 INSERT ... SELECT 语法时,HBase 表中的结果可能少于你的预期。对于每一个 row key,HBase 只存放最近的版本,因此如果 INSERT ... SELECT 语句中复制了包含相同键值列的多行数据,对于每一个键值,随后的查询将只返回单行。
尽管 Impala 不支持 UPDATE 语句,但你可以通过每次都是用相同键值的连续的 INSERT 语句来实现相同的效果。
Impala 与 HBase 的集成有以下限制和约束,其中一些继承自 HBase 和 Hive 的集成,一些是 Impala 独有的:
假如你对内部(Impala 管理的)的、已经映射到 HBase 表的表执行 DROP TABLE 语句,HBase 中对应的表不会被删除。而这种情况下 Hive DROP TABLE 语句会同时删除 HBase 表
对 HBase 表 INSERT OVERWRITE 语句不可用。你可以插入新数据,或者通过插入使用相同键值的新行来修改数据,但是不能替换表的整个内容。假如你需要这一功能,可以在 Hive 中使用 INSERT OVERWRITE 来实现
假如你对映射到 HBase 表的表执行 CREATE TABLE LIKE 语句,新表同样是一个 HBase 表,但是继承了底层的相同原来的 HBase 表名。新表是老表的有效的别名,而不是一个具有相同列结构的新表。为了避免歧义,应避免对 HBase 表使用 CREATE TABLE LIKE 语句
使用 Impala INSERT ... SELECT 语法复制数据到 HBase 表,可能会产生比查询的结果集更少的行。假如结果集中包含相同键列值的多个行,这个键值的每一行都将取代之前的行。因为插入行的顺序是变幻莫测的,你无法使用这一技术保存"最新"版本的特定键值
你可以把 HBase 表映射到 Hive 表,使用或者不使用字符串 row key。下面的例子使用如下定义的 HBase 表:
create 'hbasealltypessmall', 'bools', 'ints', 'floats', 'strings' enable 'hbasealltypessmall'
在 Hive shell 中执行如下 CREATE TABLE 语句(Impala CREATE TABLE 语句目前不支持所需的子句,因此你需要切换到 Hive 来创建这个表,然后切换回 Impala 的 impala-shell 执行查询)
hive> CREATE EXTERNAL TABLE hbasestringids ( id string, bool_col boolean, tinyint_col tinyint, smallint_col smallint, int_col int, bigint_col bigint, float_col float, double_col double, date_string_col string, string_col string, timestamp_col timestamp) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ( "hbase.columns.mapping" = ":key,bools:bool_col,ints:tinyint_col,ints:smallint_col,ints:int_col,ints:\ bigint_col,floats:float_col,floats:double_col,strings:date_string_col,\ strings:string_col,strings:timestamp_col" ) TBLPROPERTIES("hbase.table.name" = "hbasealltypesagg");
再次在 Hive 中执行下面的 CREATE TABLE 语句,然后切换回 Impala 和 impala-shell 来执行查询。
CREATE EXTERNAL TABLE hbasealltypessmall ( id int, bool_col boolean, tinyint_col tinyint, smallint_col smallint, int_col int, bigint_col bigint, float_col float, double_col double, date_string_col string, string_col string, timestamp_col timestamp) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ( "hbase.columns.mapping" = ":key,bools:bool_col,ints:tinyint_col,ints:smallint_col,ints:int_col,ints:bigint_col,floats\ :float_col,floats:double_col,strings:date_string_col,strings:string_col,strings:timestamp_col" ) TBLPROPERTIES("hbase.table.name" = "hbasealltypessmall");
当你建立了对 HBase 表的映射后,你可以对这个表进行查询。
# 假如 row key 映射出字符串列,范围谓词可以被应用到扫描中 select * from hbasestringids where id = '5'; # row key 上的谓词没有转换成扫描参数 # 因为 row key 被映射成 int (但是以 ASCII 存储,以字典顺序排序) select * from hbasealltypessmall where id < 5;