Cloudera Impala官方文档中文翻译-2(Using Impala to Query HBase Tables)

Using Impala to QueryHBase Tables(利用impala查询HBase Tables)

         默认情况下,impalatable使用存储在HDFS中的数据文件,这种存储方式适用于批量数据加载和查询(bulk loads and query)。相反,HBase可以对用于OLTP风格的负载的数据进行高效率查询,比如查找单个row或者一个range的values。

         对于impala用户来说,HBase是key-value存储形式的数据库,value包含多个fields。Key在impala table中被map到某一个column,而value的各个fields被map到impala table的其他columns。

Overview of Using HBasewith Impala(概览)

         使用impala withHBase时:

l  使用Hive shell创建table

A、可以使用STORED BY

‘org.apache.hadoop.hive.hbase.HBaseStorageHandler ‘语句

       B、直接把impala table map到一个已有的HBase table中

l  Map到HBase row key的impala column必须是string类型的

l  由于impala和hive共享metastore,一旦在hive中创建table后,在impalashell中使用INVALIDATE METADATA语句刷新即可看到新的table

l  在impala中查询HBase数据时,尽量使用WHERE从句定位单个key或者一个key range,这样可以提高查询效率,全表scan对于HBase效率很低

确保impala user具有对HBasetable的read/write权限。

 

Configuring HBase for Usewith Impala(配置)

         HBase在Impala Box之外工作,没有强制需要的配置。

         为了避免在HBase不可用的情况下,impala启动或者更新元数据的延迟,Cloudera建议设置timeoutvalue在/etc/impala/conf/hbase-site.xml中(在非Cloudera Manager的环境下才需要):

<property>
  <name>hbase.client.retries.number</name>
  <value>3</value>
</property>
<property>
  <name>hbase.rpc.timeout</name>
  <value>3000</value>
</property>

         目前,ClouderaManager并不提供仅针对impala的HBase特有配置文件,所以你在Cloudera Manager中进行的任何的HBase配置更改都会在所有的HBase applications中生效。因此,这个timeout配置不建议在cloudera manager中设置。

 

Supported Data Types forHBase Columns(针对HBase列支持的数据类型)

         为了弄清Impalacolumn数据如何映射到HBase中的字段(field),你应该有一些关于HBase的背景知识。在Hive shell中利用CREATE TABLE语句设置映射关系。见theHive wiki作为起点,Examples of Querying HBase Tables from Impala作为例子。

         HBase作为一种“bitbucket”进行工作,它并不强制要求对key或者value字段输入值,所有的强制输入都是在Impala这边进行的。

         为了在impala查询HBase时获得最好的性能,大多数查询会在WHERE中的column对应的row key进行比较操作。当在Hive shell中创建table时,把映射为HBase row key列的那一列设置为STRING类型。Impala可以把针对某个column的条件测试(例如操作符=, <, BETWEEN, 和IN)翻译成HBase中的快速查找,但是这个优化(predicate push down即谓词下推)仅当列为STRING类型时才有效。

         从Impala 1.1开始,Impala也支持读写在HiveCREATE TABLE语句中定义的二进制类型的列,即在Hive table中使用#binary定义(通常简写为#b)。定义数值column为二进制类型通常可以降低其在HBase table中的空间占用。

切记Row key列定义成string类型的,这样可以进行快速查找。其他列可以为binary类型的,这样可以节省存储空间。

Performance Considerationsfor the Impala-HBase Integration(性能考虑)

         为了理解HBase上进行SQL查询的性能特点,你应该有一些相关的背景知识。可以以 the Hive wiki为起点,因为Impala与Hive共享同一个metastore,所以Hive table到HBase table的列映射信息也适用于Impala。

         Impala使用HBaseclient API通过JNI来查询HBase的数据。查询不直接读HFiles。额外的通信开销使得选择将数据存储在HBase还是HDFS变得很重要,同时构造高效的查询可以高效地获取HBase数据也变得很重要。

l  使用HBase table用来进行singlerow或者一个range of rows的查询,而不是scan entire table的query(如果query中不包含WHERE从句,说明很可能它对于HBase table是低效率的)

l  如果你做一个join查询,在一个大的facttable上做汇总操作,然后将结果与一个小维度的table进行join操作,考虑使用Impala存储fact table,并且HBase存储这个小维度table(因为Impala在这种情况下会对HBase table进行全表scan,而不是做single-row的HBase查找,基于这个join column,只有在HBase table足够小的情况下,全表扫描才不至于时间过长,这样才不会出现查询性能瓶颈)

Query predicates(谓词、判断)用来表示row key的start和stop key,从而限制了lookup操作的scope。如果row key不对应string类型的列,那么通常是无法正确排序的,因为comparison操作无法正常进行。

Non-key列的谓词判断被发送到HBase作为SingleColumnValueFilters进行scan,提供一些性能提升。这种情况下,HBase比在impala中使用相同的谓词返回更少的行(?这句没看懂)。尽管non-key列谓词的使用会有一些性能提升,但是这种提升与使用row-key谓词的情况相比还是微不足道的。因为这种情况下,HBase要扫描的总行数依然是没有限制的。只要有row key的predicate,那么HBase就能快速定位并返回那一行,相反的是,如果只有non-key的predicate,那么即使查询结果只有一行,HBase也要进行全表scan。

 

Interpreting EXPLAINOutput for HBase Queries(理解EXPLAIN语句的输出)

         例如,这有一些针对Impalatable(已经映射到HBase table)的查询。例子中展示了除了EXPLAIN语句的输出,还可以看到根据哪些信息可以预知该查询针对HBase table是否是高效的查询。

         第一列(cust_id)在CREATEEXTERNAL TABLE语句中被指定为key列,将该列声明为STRING类型对于性能来说是很重要的;其他列例如BIRTH_YEAR, NEVER_LOGGED_ON也声明为STRING,而不是它们本来的INT和BOOLEAN类型,因为Impala可以在HBasetable中更高效地优化这些类型。为了比较,我们将YEAR_REGISTERED这列声明为INT类型,来展示针对这一列的filtering是低效的。

describe hbase_table;
Query: describe hbase_table
+-----------------------+--------+---------+
| name                  | type   | comment |
+-----------------------+--------+---------+
| cust_id               | string |         |
| birth_year            | string |         |
| never_logged_on       | string |         |
| private_email_address | string |         |
| year_registered       | int    |         |
+-----------------------+--------+---------+

         关于使用row key列等值比较条件进行单行查询是性能最好的例子:

explain select count(*) from hbase_table where cust_id = '[email protected]';
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
| Estimated Per-Host Requirements: Memory=1.01GB VCores=1                            |
| WARNING: The following tables are missing relevant table and/or column statistics. |
| hbase.hbase_table                                                                  |
|                                                                                    |
| 03:AGGREGATE [MERGE FINALIZE]                                                      |
| |  output: sum(count(*))                                                           |
| |                                                                                  |
| 02:EXCHANGE [PARTITION=UNPARTITIONED]                                              |
| |                                                                                  |
| 01:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 00:SCAN HBASE [hbase.hbase_table]                                                  |
|    start key: [email protected]                                                |
|    stop key: [email protected]\0                                               |
+------------------------------------------------------------------------------------+

         另外一类高效查询是针对rowkey列的一个range查找,使用SQL操作符例如>, <, =, BETWEEN。下面例子也包好一个non-key列的等值test,因为这一列也是STRING类型。Impala可以HBase执行这个test,体现在hbase filter中(见下面的output),在HBase中进行filtering比将数据全部传给impala再在impala这边进行filtering更高效。

explain select count(*) from hbase_table where cust_id between 'a' and 'b'
  and never_logged_on = 'true';
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
...

| 01:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 00:SCAN HBASE [hbase.hbase_table]                                                  |
|    start key: a                                                                    |
|    stop key: b\0                                                                   |
|    hbase filters: cols:never_logged_on EQUAL 'true'                                |
+------------------------------------------------------------------------------------+

         这样的查询是低效的:如果Impala必须评估一些predicates,因为Impala必须scan整个HBase table。Impala只能把关于STRING类型column的predicate下推给HBase处理,而下例中是INT类型,故output中最下面的predicate:这一行表示这个等值test会在数据都传输给impala之后才能进行:(explain输出的predicate:语句不会在HBase中执行,这一点与hbase filtersstart keystop key不同

explain select count(*) from hbase_table where year_registered = 2010;
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
...

| 01:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 00:SCAN HBASE [hbase.hbase_table]                                                  |
|    predicates: year_registered = 2010      

         这样的查询也是低效的:如果key列与任何非常量值进行比较。这里,即使key column是STRING类型的,并且使用=操作符,Impala也必须scan整个HBase table,因为key column是与另外一列的value进行比较,而不是一个常量:

explain select count(*) from hbase_table where cust_id = private_email_address;
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
...

| 01:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 00:SCAN HBASE [hbase.hbase_table]                                                  |
|    predicates: cust_id = private_email_address                                    |
+------------------------------------------------------------------------------------+

         当前,针对row key的OR,IN语句test没有优化成直接的查找,这个限制未来可能会被解决。所以请每次check EXPLAIN的output来观察你的query是否是一个对于HBase table来说高效的查询。

explain select count(*) from hbase_table where
  cust_id = '[email protected]' or cust_id = '[email protected]';
+----------------------------------------------------------------------------------------+
| Explain String                                                                         |
+----------------------------------------------------------------------------------------+
...

| 01:AGGREGATE                                                                           |
| |  output: count(*)                                                                    |
| |                                                                                      |
| 00:SCAN HBASE [hbase.hbase_table]                                                      |
|    predicates: cust_id = '[email protected]' OR cust_id = '[email protected]' |
+----------------------------------------------------------------------------------------+

explain select count(*) from hbase_table where
  cust_id in ('[email protected]', '[email protected]');
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
...

| 01:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 00:SCAN HBASE [hbase.hbase_table]                                                  |
|    predicates: cust_id IN ('[email protected]', '[email protected]')      |
+------------------------------------------------------------------------------------+

         拆分成单个针对单行的查询,然后在application中合并结果,或者combine单行查询使用UNION ALL关键词:

select count(*) from hbase_table where cust_id = '[email protected]';
select count(*) from hbase_table where cust_id = '[email protected]';

explain
  select count(*) from hbase_table where cust_id = '[email protected]'
  union all
  select count(*) from hbase_table where cust_id = '[email protected]';
+------------------------------------------------------------------------------------+
| Explain String                                                                     |
+------------------------------------------------------------------------------------+
...

| |  04:AGGREGATE                                                                    |
| |  |  output: count(*)                                                             |
| |  |                                                                               |
| |  03:SCAN HBASE [hbase.hbase_table]                                               |
| |     start key: [email protected]                                            |
| |     stop key: [email protected]\0                                           |
| |                                                                                  |
| 10:MERGE                                                                           |
...

| 02:AGGREGATE                                                                       |
| |  output: count(*)                                                                |
| |                                                                                  |
| 01:SCAN HBASE [hbase.hbase_table]                                                  |
|    start key: [email protected]                                                |
|    stop key: [email protected]\0                                               |
+-------------------------------------------

总结

即尽量使用string类型的列,尽量使用WHERE限制key的范围,这样避免将所有数据传输到impala中进行查找。

         Impala只能把针对STRING类型列的predicates下推到HBase中去,但是对于其他类型比如INT型的column的predicate,只能是在impala这边做过滤,所以必须对HBase进行全表scan。

         如果key column不是和常量值进行比较,那么也是低效的,也要进行全表扫描,比如select count(*) from hbase_table where cust_id =private_email_address。

        

Configuration Options forJava HBase Applications(配置参数)

         如果你有一个HBaseJava application调用了 org.apache.hadoop.hbase.client.Scan的setCacheBlocks或者setCaching方法,你也可以使用Impala查询参数来设置这些值来控制HBaseregion server的内存压力。例如,当在HBase中进行查询并导致全表scan是,你可以通过关闭HBASE_CACHE_BLOCKS设置并指定一个很大的值给HBASE_CACHING来降低内存占用并且加速查询。

         设置这些参数,在impala-shell中执行如下命令:

-- Same as calling setCacheBlocks(true) or setCacheBlocks(false).
set hbase_cache_blocks=true;
set hbase_cache_blocks=false;

-- Same as calling setCaching(rows).
set hbase_caching=1000;

         或者更新impalad的默认文件/etc/default/impala,并且设置HBASE_CACHE_BLOCKSand/or HBASE_CACHING in the -default_query_options setting forIMPALA_SERVER_ARGS。细节请参考Modifying Impala Startup Options

Note:在Impala 2.0或者更新版本中,这些选项是可设置的,通过JDBC或者ODBC接口,使用SET语句。

Use Cases for QueryingHBase through Impala(用例)

Impala查询HBase table的通常情景:

l  在impala中保存大的facttables,在HBase中保存smaller dimension tables。Fact tables使用Parquet或者其他类型的二进制格式(针对scan操作进行优化的)文件存储。Join操作scan这个大的impala fact table,并且使用高效的single-row lookup来交叉引用HBase中的table。即大表和小表join时,用impala扫描大表,结果作为join过滤条件传给HBase,以快速定位对应的row。

l  使用HBase存储快速增长的counter数据,比如一个webpage已经被访问了多少次,一个user已经发起了多少次连接等。HBase对于捕捉这种变化无常的data是非常有效的,因为它的append-only存储机制对于把每个change写入disk非常高效,并且一个query总是返回最新的value。

l  在HBase中存储非常wide的table。Wide table可能有几千个columns,通常记录着某个项目的很多属性。这些table通常是sparse的,大部分列的值是NULL或者0、false、空字符串等。例如某个网站服务的用户作为一个row,他可能仅仅用过其中的几个服务,通常的query是:查找一个single row,提取出所有列的信息,而不是做sum、averge等impala中常见的操作。

 

比如impala table中存储着某个网站的流量信息(一张大表),impala选出了浏览该网站的50个user,现在如果要看这些user的属性的话,我们只需与HBase中存储的user table进行join,这样只需scan这50个rows,而不必扫描全表。

 

Loading Data into an HBaseTable(加载数据到HBasetable中)

         Impala中可以对HBase表insert单行,因为插入单行操作对于HBase本来就是有效的,但是对于存储在HDFS中的其他impala table,insert单行是不行的,因为这样会产生很多小文件,必须批量插入。

         Impala中没有update语句,但是使用相同的rowkey进行insert时可以起到update的效果,因为相同的row key插入时会覆盖原来的value。

Limitations andRestrictions of the Impala and HBase Integration(二者集成的限制和束缚)

l  Impala中的DROP TABLE语句执行后,HBase中的table没有remove,只是impala中的remove了

l  Hive中支持INSERT OVERWRITE语句,可以清空整个table,然后插入新数据,但是impala里不支持对于HBase table的这类语句,你只能插入新行或者使用相同的row key更新原有行

l  Impala中对HBase table执行CREATE TABLE LIKE语句时,在HBase中发生的是产生一个对旧表的别名,并没有完全复制出一个新表,所以应该避免使用此语句

l  在impala中使用INSERT…SELECT语句向HBasetable中插入数据时,首先插入的行数可能比SELECT出来的少,因为各个行可能有key列值相同的,那样就只会产生一列结果,其次,无法保证多个相同key的rows插入时,由于后来的row会替换已有row的值,这样就没法保证最终插入的row的值是最新的了,谨慎使用。

Examples of Querying HBaseTables from Impala(查询实例)

1、  首先在HBase中创建一个表,HBase中创建的table是“enabled”状态,在hbaseshell中dropping:他们之前必须执行disable ‘table_name’语句;

$ hbase shell
...
create 'hbasealltypessmall', 'bools', 'ints', 'floats', 'strings'
quit

2、在hive中创建外部表指向HBasetable,注意用来做key的列最好使用string类型,其他类型也可以,但是lookup的速度要慢很多,string最快;

         下例中创建了一个外部表映射到hbase table中。由于是一个外部表,所以在impala或者Hive中drop之后,原始的hbase table并没有删除。STORED BY语句目前在Impala中还不支持,所以需要在Hive shell中使用CREATE TABLE语句执行。WITH SERDEPROPERTIED语句声明了第一列(id)代表row key列,并且映射其余列到HBase列簇中。

$ hive
...
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" = "hbasealltypessmall");

Note:在Hive中创建table之后,下次connectto impala时要执行INVALIDATE METADATA table_name语句,以便让impala知道这个新的table。

Without a String Row Key

         本例中定义lookupkey column为INT类型,而不是STRING类型。

Note:尽管这样定义可以,但是Cloudera强烈建议使用STRING类型作为key列,因为这样lookup操作更快。

         再次,执行CREATETABLE语句在Hive中,然后切换到Impala和impala-shell中执行查询:

$ hive
...
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");

Example Queries

         一旦建立了与HBasetable的映射关系,你就可以执行查询了。例如:

 

# if the row key is mapped as a string col, range predicates are applied to the scan
select * from hbasestringids where id = '5';

# predicate on row key doesn't get transformed into scan parameter, because
# it's mapped as an int (but stored in ASCII and ordered lexicographically)
select * from hbasealltypessmall where id < 5;

 

你可能感兴趣的:(Cloudera Impala官方文档中文翻译-2(Using Impala to Query HBase Tables))