On this page
Indexes
自 3.0 起删除索引
还有一些替代选项可能与索引相似:
具有自动重写的实例化视图可以产生非常相似的结果。 Hive 2.3.0添加了对实例化视图的支持。
Note
索引已在 3.0 版(HIVE-18448)中被“删除”。
Introduction
本文解释了为 Hive(HIVE-417)添加索引支持的建议设计。索引是一种标准的数据库技术,但是有许多可能的变化。我们采用的方法不是尝试提供“一刀切”的索引实现,而是采用可插拔的方式定义索引(与StorageHandlers相关),并提供一个具体的索引实现作为参考,从而为随着时间的流逝,贡献者可以插入其他索引方案。直到 Hive 0.7 才提供索引支持。
Scope
仅支持单表索引。一旦 Hive 支持了其他视图(例如联接索引),则可以更恰当地将其表示为实例化视图。
本文档当前仅涵盖索引的创建和维护。后续文章将说明如何使用索引优化查询(构建在FilterPushdownDev上)。
CREATE INDEX
CREATE INDEX index_name
ON TABLE base_table_name (col_name, ...)
AS 'index.handler.class.name'
[WITH DEFERRED REBUILD]
[IDXPROPERTIES (property_name=property_value, ...)]
[IN TABLE index_table_name]
[PARTITIONED BY (col_name, ...)]
[
[ ROW FORMAT ...] STORED AS ...
| STORED BY ...
]
[LOCATION hdfs_path]
[TBLPROPERTIES (...)]
[COMMENT "index comment"]
有关 ROW FORMAT 等各种子句的详细信息,请参见Create Table。
默认情况下,索引分区与基表的分区匹配。 PARTITIONED BY 子句可用于指定表分区列的子集(此列列表可能为空,以指示索引跨越表的所有分区)。例如,即使索引仅按日期进行分区(每个索引分区跨越所有区域),也可以按日期区域对表进行分区。
无法在视图上创建索引。我们(最终)将在非本机表上支持它们(如果相应的存储处理程序指示它支持它们)。
索引处理程序可能要求被索引的基表具有特定格式。
问题:我们应该允许 EXTERNAL 表上的索引吗?删除表后,这对于隐式 DROP 意味着什么?是否存在 EXTERNAL 索引的概念?
如果索引处理程序以表格形式存储其表示形式,则可以使用 index_table_name 来控制为此目的自动创建的“索引表”的名称。可以使用 STORED AS(例如 RCFILE 或 SEQUENCFILE)或 STORED BY(例如将索引表存储在 nonlocal 表(例如 HBase)中)来控制索引表的存储格式,尽管某些索引处理程序可能需要使用特定的存储格式。并非所有的索引处理程序都以表格形式存储它们的表示形式。一些可能使用非表文件,而另一些可能使用完全在 Hive 外部维护的结构(例如,持久键/值存储)。
Metastore Model
下图显示了具有索引支持的新 Metastore 模式:
http://issues.apache.org/jira/secure/attachment/12449601/idx2.png
Metastore 模式中的新 IDXS 表每个创建的索引包含一个条目。它与 TBLS 表有两个关系:
ORIG_TBL_ID 是强制性外键,它引用包含要构建索引的数据的基表的 ID。
IDX_TBL_ID 是一个可选的外键,它引用包含索引表示形式的表的 ID。它是可选的,因为并非所有索引实现都使用表进行存储。对于确实使用表进行存储的索引,隐式创建的表会将其 TBL_TYPE 设置为 INDEX_TABLE。
因此,给定以下 DDL:
CREATE TABLE t(i int, j int);
CREATE INDEX x ON TABLE t(j)
AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler';
元存储中的 TBLS 表将具有两个条目:
一个用于基本表 t
一个用于索引表,自动命名为
default+t_x+
在 x 的 IDXS 条目中,ORIG_TBL_ID 将引用 x 的 TBL_ID,IDX_TBL_ID 将引用default+t_x+
的 TBL_ID。
为了避免生成名称,可以改为提供用户指定的名称,例如 t_x:
CREATE INDEX x ON TABLE t(j)
AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
IN TABLE t_x;
请注意,索引名称由包含的基表(如分区)限定,因此可以在两个不同的表中使用相同的索引名称。但是,索引表的名称与所有其他表和视图在同一命名空间中,因此它们在同一数据库中必须唯一。
索引具有一个存储 Descriptors,该 Descriptors 包含索引所覆盖的原始表中的列的子集。如果索引表示形式存储在表中,则索引自身的存储 Descriptors 中的其他大多数字段(例如 LOCATION)将是无关紧要的。
TBD:
将 IDX_TYPE 更改为 IDX_HANDLER
LAST_ACCESS_TIME 是什么意思?上一次优化程序使用此索引?
需要 LAST_REBUILD_TIME?我们如何在分区级别跟踪它?它应该在 metastore 中(而不仅仅是 HDFS)
在索引分区是基表分区的子集的情况下,我们需要一种在元存储中对此建模的方法
Metastore Upgrades
这是 MySQL Metastore 升级声明。
DROP TABLE IF EXISTS {{IDXS}};
CREATE TABLE {{IDXS}} (
{{INDEX_ID}} bigint(20) NOT NULL,
{{CREATE_TIME}} int(11) NOT NULL,
{{DEFERRED_REBUILD}} bit(1) NOT NULL,
{{INDEX_HANDLER_CLASS}} varchar(256) DEFAULT NULL,
{{INDEX_NAME}} varchar(128) DEFAULT NULL,
{{INDEX_TBL_ID}} bigint(20) DEFAULT NULL,
{{LAST_ACCESS_TIME}} int(11) NOT NULL,
{{ORIG_TBL_ID}} bigint(20) DEFAULT NULL,
{{SD_ID}} bigint(20) DEFAULT NULL,
PRIMARY KEY ({{INDEX_ID}}),
UNIQUE KEY {{UNIQUEINDEX}} ({{INDEX_NAME}},{{ORIG_TBL_ID}}),
KEY {{IDXS_FK1}} ({{SD_ID}}),
KEY {{IDXS_FK2}} ({{INDEX_TBL_ID}}),
KEY {{IDXS_FK3}} ({{ORIG_TBL_ID}}),
CONSTRAINT {{IDXS_FK3}} FOREIGN KEY ({{ORIG_TBL_ID}}) REFERENCES {{TBLS}} ({{TBL_ID}}),
CONSTRAINT {{IDXS_FK1}} FOREIGN KEY ({{SD_ID}}) REFERENCES {{SDS}} ({{SD_ID}}),
CONSTRAINT {{IDXS_FK2}} FOREIGN KEY ({{INDEX_TBL_ID}}) REFERENCES {{TBLS}} ({{TBL_ID}})
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Table structure for table {{INDEX_PARAMS}}
--
DROP TABLE IF EXISTS {{INDEX_PARAMS}};
CREATE TABLE {{INDEX_PARAMS}} (
{{INDEX_ID}} bigint(20) NOT NULL,
{{PARAM_KEY}} varchar(256) NOT NULL,
{{PARAM_VALUE}} varchar(767) DEFAULT NULL,
PRIMARY KEY ({{INDEX_ID}},{{PARAM_KEY}}),
CONSTRAINT {{INDEX_PARAMS_FK1}} FOREIGN KEY ({{INDEX_ID}}) REFERENCES {{IDXS}} ({{INDEX_ID}})
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
REBUILD
ALTER INDEX index_name ON table_name [PARTITION (...)] REBUILD
有关 PARTITION 子句的语法,请参见LanguageManual DDL#Add_Partitions。
如果在 CREATE INDEX 上指定了 WITH DEFERRED REBUILD,则新创建的索引最初为空(无论表是否包含任何数据)。 ALTER INDEX ... REBUILD 命令可用于为所有分区或单个分区构建索引结构。
如果基表中的数据发生更改,则必须使用 REBUILD 命令使索引更新。这是一个原子操作,因此如果该表先前已被索引,并且重建失败,则旧索引保持不变。
DROP INDEX
DROP INDEX index_name ON table_name
可以使用 DROP INDEX 随时删除索引。这也将级联到索引表(如果存在)。
尝试直接使用 DROP TABLE 删除索引表将失败。
当删除索引基表时,DROP 隐式级联到所有索引(及其对应的索引表,如果有的话)。
当索引基表删除其分区之一时,这将隐式级联以从所有索引中删除相应的分区。
问题:如果索引分区粒度与表分区粒度不同,该怎么办?可能只是忽略删除操作,而让用户使用新的 ALTER INDEX DROP PARTITION 语句进行手动清理。
Plugin Interface
索引处理程序具有以下主要职责:
在 CREATE INDEX 期间,验证基本表的格式,然后生成索引表的结构(如果有),并将所有其他信息填充到索引的存储 Descriptors 中
在 REBUILD 期间,生成一个计划,用于读取基表的数据并写入索引存储和/或索引表
在 DROP 期间,删除任何特定于索引的存储(Hive 自动删除索引表)
在查询期间,参与优化以便将诸如过滤器之类的运算符转换为索引访问计划(此部分目前不在范围内)
下面定义了相应的 Java 接口以及处理程序应扩展的伴随抽象 Base Class。
package org.apache.hadoop.hive.ql.metadata;
import java.util.List;
import org.apache.hadoop.conf.Configurable;
import org.apache.hadoop.hive.ql.plan.api.Task;
/**
* HiveIndexHandler defines a pluggable interface for adding new
* index handlers to Hive.
*/
public interface HiveIndexHandler extends Configurable
{
/**
* Determines whether this handler implements indexes by creating
* an index table.
*
* @return true if index creation implies creation of an index table in Hive;
* false if the index representation is not stored in a Hive table
*/
boolean usesIndexTable();
/**
* Requests that the handler validate an index definition and
* fill in additional information about its stored representation.
*
* @param baseTable the definition of the table being indexed
*
* @param index the definition of the index being created
*
* @param indexTable a partial definition of the index table to be used for
* storing the index representation, or null if usesIndexTable() returns
* false; the handler can augment the index's storage descriptor
* (e.g. with information about input/output format)
* and/or the index table's definition (typically with additional
* columns containing the index representation, e.g. pointers into HDFS)
*
* @throw HiveException if the index definition is invalid with
* respect to either the base table or the supplied index table definition
*/
void analyzeIndexDefinition(
org.apache.hadoop.hive.metastore.api.Table baseTable,
org.apache.hadoop.hive.metastore.api.Index index,
org.apache.hadoop.hive.metastore.api.Table indexTable)
throws HiveException;
/**
* Requests that the handler generate a plan for building the index;
* the plan should read the base table and write out the index representation.
*
* @param baseTable the definition of the table being indexed
*
* @param index the definition of the index
*
* @param partitions a list of specific partitions of the base
* table for which the index should be built, or null if
* an index for the entire table should be rebuilt
*
* @param indexTable the definition of the index table, or
* null if usesIndexTable() returns null
*
* @return list of tasks to be executed in parallel for building
* the index
*
* @throw HiveException if plan generation fails
*/
List<Task<?>> generateIndexBuildTaskList(
org.apache.hadoop.hive.metastore.api.Table baseTable,
org.apache.hadoop.hive.metastore.api.Index index,
List<org.apache.hadoop.hive.metastore.api.Partition> partitions,
org.apache.hadoop.hive.metastore.api.Table indexTable)
throws HiveException;
}
/**
* Abstract base class for index handlers. This is provided as insulation
* so that as HiveIndexHandler evolves, default implementations of new
* methods can be added here in order to avoid breaking existing
* plugin implementations.
*/
public abstract class AbstractIndexHandler implements HiveIndexHandler
{
}
对于 CREATE INDEX,Hive 首先在处理程序上调用 usingIndexTable()以确定是否将创建索引表。如果返回 false,则如果用户为索引指定了任何表存储选项,则该语句将立即失败。但是,如果 usesIndexTable()返回 true,则 Hive 会根据索引定义(例如覆盖的列)以及用户提供的任何表存储选项,为索引表创建部分表定义。接下来,Hive 调用 analyticsIndexDefinition(为 indexTable 参数传递 null 或部分索引表定义)。处理程序通过验证定义进行响应(如果检测到任何不受支持的组合,则引发异常),然后将有关 index 和 indexTable 参数的附加信息填充为输出。然后,Hive 将这些结果存储在 metastore 中。
TBD:我们将添加删除索引时调用处理程序的方法(例如,为将索引表示形式存储在外部系统(例如 HBase)中的处理程序提供清理机会)
Reference Implementation
参考实现将创建所谓的“紧凑”索引。这意味着,它不存储每次出现特定值的 HDFS 位置,而是仅存储包含该值的 HDFS 块的地址。在值通常在附近的行中多次出现的情况下,此方法针对点查找进行了优化。索引大小保持较小,因为块少于行。权衡是在查询过程中需要额外的工作才能从索引块中滤除其他行。
紧凑索引存储在索引表中。索引表列由基础表中的索引列组成,其后是_bucketname 字符串列(指示包含已索引块的文件的名称),其后是_offsets array<string>列(指示相应文件中的块偏移)。索引表按排序方式存储在索引列上(但不存储在生成的列上)。
参考实现可以插入
ADD JAR /path/to/hive_idx-compact.jar;
CREATE INDEX ...
AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler';
TBD:用于构建索引的算法
TBD:搜索索引的机制
TBD:在基表上验证(可以是任何托管表吗?)
TBD:验证索引表格式(可以是任何托管表格式吗?)
TBD
SHOW/DESCRIBE INDEX(HIVE-1497)的规格
更改索引删除分区吗?
ALTER INDEX SET IDXPROPERTIES,更改表格式等
当表或分区的结构在被索引后发生变化时会发生什么
未指定 WITH DEFERRED REBUILD 时将自动索引作为 INSERT 的一部分
防止在索引表上创建索引?
Metastore 升级脚本
索引表的统计信息收集
与新的 Hive 并发控制功能相交(我们对各种索引操作采取什么锁?)
当前状态(JIRA)
||
||
|T|Key|Summary|Assignee|Reporter|P|Status|Resolution|Created|Updated|Due|
Loading...