谈笑间学会大数据-Hive索引

Hive 只有有限的索引功能。Hive中没有普通关系型数据库中键的概念,但是还是可以对一些字段建立索引来加速某些操作的。一张表的索引数据存储在另外一张表中。

同时,因为这是一个相对比较新的功能,所以目前还没有提供很多的选择。然而,索引处理模块被设计成为可以定制的Java编码的插件,因此,用户可以根据需求要对其进行实现,以满足自身的需求。

当逻辑分区实际上太多太细而几乎无法使用时,建立索引也就成为分区的另一个选择。建立索引可以帮助裁剪掉一张表的一些数据块,这样能够减少MapReduce的输入数据量。并非所有的查询都可以通过建立索引获得好处。通过explain命令可以查看某个查询语句是否用到了索引。

Hive中的索引和那些关系型数据库中的一样,需要进行仔细评估才能使用。维护索引也需要额外的存储空间,同时创建索引也需要消耗计算资源。用户需要在建立索引为查询带来的好处和因此而需要付出的代价之间做出权衡。

创建索引

普通索引

下面我们来做一下样例,在管理分区表中的employees表建立一个索引。建表语句如下:

create table employees (
  name					string,
  salary				float,
  subordinates	array<string>,
  deductions		map<string,float>,
  address				struct<street:string, city:string, state:string, zip:int>
)
partitioned by (country string, state string)
;

下面我们开始对分区字段country建立索引:

create index employees_index on table employees (country) 
as 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
with deferred rebuild idxproperties ('creator' = 'me', 'created_at' = 'some_time')
in table employees_index_table
partitioned by (country, name)
comment 'Employees indexed by country and name.'
;

在这种情况下,我们没有像原表那样对索引表进行同一粒度的分区划分。其实我们是可以那么做的。如果我们完全省略掉 partitioned by 语句的话,那么索引将会包含原始表的所有分区。

AS … 语句指定了索引处理器,也就是一个实现了索引接口的Java类。Hive本身包含了一些典型的索引实现。这里所展示的CompactIndexHandler 就是其中的一个实现。可以通过第三方的实现来最优化地处理特定的场景,支持特定的文件格式,等等。

并非一定要求索引处理器在一张新表中保留索引数据,但是如果需要的话,会使用到 in table … 子句。这个句式提供了和创建其他类型表一样的很多功能。特别地,例子中没有使用到row format 、stored as、stored by、location等这些指定参数,都可以在comment语句前面增加的。

目前除了S3中的数据,对外部表和视图都是可以建立索引的

Bitmap索引

Hive v0.8 版本中新增了一个内置bitmap 索引处理器。bitmap索引普遍应用于排重后值较少的列。下面是对前面的例子使用bitmap索引处理器重写后的语句:

create index employees_index on table employees (country) 
as 'BITMAP'
with deferred rebuild idxproperties ('creator' = 'me', 'created_at' = 'some_time')
in table employees_index_table
partitioned by (country, name)
comment 'Employees indexed by country and name.'
;

重建索引

如果用户指定了deferred rebuild,那么新索引将呈现空白状态。在任何时候,都可以进行第一次索引创建或者使用alter index 对索引进行重建:

alter index employee_index on table employees partition (country = 'US') rebuild;

如果省略掉partition,那么将会对所有分区进行重建索引。

还没用一个内置的机制能够在底层的表或者某个特定的分区发生改变时,自动触发重建索引。但是,如果用户具有一个工作流来更新表分区中的数据的话,那么用户可能已经在其中某处使用到了众多的Alter Table语句…同样的,也可以对对应的索引执行重建索引语句alter index … rebuild。

如果重建索引失败,那么在重建开始之前,索引将停留在之前的版本状态。从这种意义上看,重建索引操作是原子性的。

显示索引

下面这个命令将会显示这个索引表对所有列建立的索引:

show formatted index on employees ;

关键字formatted是可选的。增加这个关键字可以使输出中包含列名称。用户还可以替换index为indexs,这样输出中就可以列举出更多个索引信息了。

删除索引

如果有索引表的话,删除一个索引将会删除这个索引表:

drop index if exists employees_index on table employees ;

Hive不允许用户直接使用drop table语句直接删除索引表。而通常情况下,if exists都是可选的,其用于当索引不存在时避免抛出错误信息。如果被索引的表被删除了,那么其对应的索引和索引表也会被删除。同样地,如果原始表的某个分区被删除了,那么这个分区对应的分区索引也同时会被删除掉。

如何自定义索引处理器?

在Hive Wiki页面上有一个实现自定义索引处理器的完整例子。

链接:https://cwiki.apache.org/confluence/display/Hive/IndexDev#CREATE_INDEX

  • 其中还包含了索引的初步设计文档
  • 用户也可以使用org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler中的源代码作为例子
    创建好索引后,实现索引处理器的Java代码中也要做一些初始验证和为索引表定义模式的过程。同事还要实现重建索引处理逻辑,其会读取需要创建索引的表,然后写索引存储。但是索引被删除后,处理器还需要清理掉所有为索引所使用到的非表存储。如果需要,还要依赖Hive去删除索引表。处理器必须能够参与到优化查询中。