一 Hypertable 是什么:
Hypertable 是一个正在进行中的开源项目,以google的bigtable论文为基础指导,使用c++语言实现。
目标:
- 是为了解决大并发,大数据量的数据库需求。
- 目前只支持最基本的查询功能
缺点:
- 不支持事物, 不支持关联查询.
- 对单条查询的响应时间可能也不如传统数据库(要看数据量,量越大,对hypertable越有 力)。
优点:
- 并发性: 可以处理大量并发请求,和管理大量数据。
- 规模:可扩缩性好,扩容只需要增加集群中的机器就ok了。
- 可用性: 任何节点失效,既不会造成系统瘫痪也不会丢失数 据。在集群节点足够的情况下,并发量和数据量对性能基本没有影响。
注意:Hypertable不是关系数据库。而且它对稀疏数据是只存储其有效部分的。举个例子来说,假设一个表有10列。表中的一条记录,只有第三列有 值。那么实际上只有第三列被存储了,无值的列没有保留空位。这些特点使得 Hypertable 在使用的时候与关系数据库不同。
二 hypertable 的总体架构
上面是 Hypertable 项目文档中的总体架构图。简单介绍一下各个组成部分
- Hyperspace:
可以认为是一个文件存储系统,用来存储一些元数据信息,同时提供一些锁的功能。在google的bigtable论文中,这个模块 叫做 Chubby。是一个小集群来实现的。在 Hypertable 目前的版本中,这是一台单台服务器,内部采用 Berkeley Db 实现。单点服务器制造了一个系统瓶颈,这台服务器不能失效,所以在将来的版本中,这个模块将采用类似 Chubby 的集群实现。
----------------------------------------------------------------
ref:http://hi.baidu.com/cpuramdisk/item/b4ba346f65a9210aa1cf0f36
Hyperspace是类似Google Bigtable系统中的Chubby 功能。Chubby在Google Bigtable系统中主要实现两个功能,一是为Bigtable提供一个粗粒度锁服务;其次是提供高效,可靠的主机选举服务。由于Bigtable的粗粒度锁服务往往构建在具有统一namespace的文件系统上(早期在Database上),因此它同时具备轻量级的存储功能,可以存储一些元数据信息。如图3-1所示,Hyperspace作为一个服务器族存在,通常情况下,一个Hyperspace Server族一般由5或11台服务器组成,他们基于Paxos选举算法,在服务器中选举出一个Active Server,其它的服务器作为Standby Servers存在,在系统运行过程中,Active Server和Standby Servers之间会同步状态和数据(数据经常由文件系统或数据库自己完成)。截至本文档发布之前,Hyperspace还未发布Active/Standby功能。从实现的角度来看,实现1+1的备份方式,也可以作为Hyperspace HA 的一种实现方法,但显然可靠性要低于Chubby的实现方式。
目前,Hyperspace基于BSD DB构建它的锁服务,通过BSD DB API,Hyperspace构建一个namespace,该namespace中包含目录和文件节点,每一个目录或文件可以赋予许多的属性,如锁的属性。Hyperspace Client是访问Hyperspace的客户端模块。Hypertable中的其它系统模块通过该Client与Hyperspace Server建立Session链接,通过该链接完成Hyperspace中目录和文件的操作(如读,写,锁操作等)。Session链接采用租约机制,客户端必须定期更新租约期限,如果到期未更新,Hyperspace认为客户端out of service,随机释放客户端所占用的文件和锁资源。Hyperspace Client为客户端应用提供了callback方式的事件通知机制,客户端应用可以通过Session链接,向Hyperspace注册自己关注的对象(目录或文件)的有关事件,也可以向Session本身注册时间callback。如文件,或目录的删除时间,锁操作事件,Session的终止事件等。
由于Hyperspace的设计满足高可靠性要求,因此它除了提供粗粒度锁服务以外,还承担着部分的小数据量的存储任务。Metadata0 tablet location就存储在Hyperspace,作为整个Hypertable tablets索引的根节点。另外,Hyperspace也会存储Metadata schema,access control list(目前未实现);同时,由于Hypersapce提供了Hypertable系统中所有主机节点的锁服务,所有节点会在Hyperspace的namespace中创建自己的主机节点,并获取相应的锁,因此Hyperspace同时充当了记录Hypertable系统中主机状态的任务,并且根据客户端注册的callback信息分发相应的状态改变事件。
由此可见,Hyperspace作为一个需要设计成具有高可用性的子系统,如果Hyperspace停止工作,Hypertable也就对外不能提供服务了。
----------------------------------------------------------------
- Master:
Master有两个主要责任。1 管理元操作,比如建表,更改表结构等。2 管理RangeServer,检测 RangeServer 的工作状态,调整 RangeServer 服务的数据以实现负载均衡。 - RangeServer :
RangeServer 是真正提供服务的单元,每个 RangeServer 管理一张表的部分数据。RangeServer 的详细信息,后面在介绍
---------------------------------------------------------------
ref: http://hi.baidu.com/cpuramdisk/item/b4ba346f65a9210aa1cf0f36
在Hypertable系统中,表按row range分割为许多tablet,这些tablet由range server维护,一个range server主机可以维护多个tablet。Range server负责处理所有的该row range的读写操作。
如图3-2,range server处理写数据(如insert、update、delete等数据操作)时,range server将检查它的格式是否合法以及该操作的访问权限(目前还未实现access control);检查成功后,先将数据(和操作)写入Commit Log文件,随后将数据按顺序缓存在Cell Cache中,随着Cell Cache不断增长,达到Cell Cache的容量门限,range server将新建一个Cell Cache,将旧的Cell Cache写入DFS cell store文件,此过程也称作为Minor Compaction(次级紧置化)。Minor compaction起到主要作用有两个,一是通过将Cell Cache写入DFS,回收Cell Cache内存,使得range server不会因为cell cache的无限增长而消耗完内存资源;其次,由于range server将写数据首先保存在commit log文件中,以备系统崩溃后,能读取commit log恢复到崩溃前的数据状态;因此,在旧的cell cache被写入cell store文件后,commit log中相应的log就可以被清除,从而有效地回收了commit log文件空间。
随着数据操作的不断增加,Cell Store文件也不断增多,当文件个数达到门限时,range server将执行merging compaction操作,该操作将选择部分cell store文件与cell cache合并为一个较大的cell store文件。此时的merging compaction操作中,所有文件和cache的数据被重新排序到新的cell store文件中,并不执行数据的计算合并操作,因此所有的delete数据仍然存在于新的cell store文件中。
有一种特殊的merging compaction操作,发生在tablet分裂前,range server会将该tablet的所有cell store文件和cell cache合并为一个大的cell store文件,该操作称为Major Compaction(当前hypertable并未实现定时major compaction)。Major compaction在合并文件和cache过程中会对计算数据进行合并计算,所产生的新cell store文件不再包含delete操作的数据。Major compaction可以有效地回收存储空间,其次,由于新产生的cell store文件已经完成数据操作的合并运算,使得数据的读写操作性能更高。
如图3-2所示,数据读取操作需要访问多个cell store文件和cell cache,如2.2.2所述,cell store文件中包含有多个索引块,这些索引块运行时缓存在内存中,当一个读取操作来到range server时,range server将检查它的格式是否合法以及该操作的访问权限(目前还未实现access control);检查成功后,range server将定位该row key可能存在的所有cell store文件,包括cell cache,扫描相关cell store和cell cache,为该次读操作在内存执行merging操作,并返回结果。由于所有key,value数据对在cell store和cache中已经按字典序排列,因此扫描和merging操作的效率较高。
Range server在处理读写请求时,仍然可以进行其它的处理操作。在进行minor compaction前,由于range server会新建一个cell cache,因此,在进行minor compaction时不会阻塞读写请求。其它的如执行tablet split,merging compaction,以及major compaction时,range server会在cell cache中给新来的写数据置时间标记,以便和正在参与操作的cache数据区别开来。
Tablet的永久存储模式是DFS上的cell store文件、log文件以及Hyperspace上的schema,tablet的索引在2.2.1所述的metadata table中。如果一个range server停止服务,hypertable系统(通常是Master调度)将选择另一个的range server(该range server可能已经维护了其它的tablet)去恢复(Recover)该tablet。Range server在恢复tablet过程中,首先从metadata table中读取该tablet的metadata,该metadata中包含有cell store文件列表(参见2.2.1),以及一组Redo指针(??),这些指针指向Commit Log中需要Redo的操作记录。Range server根据这些
--------------------------------------------------------------- - DFS Broker :
它的主要作用是使用底层的文件系统来完成 Hypertable 对文件系统的请求。Hypertable 对文件系统的使用有一个很简单的接口,只需要文件系统提供几个很简单的操作就可以。 Hypertable 的读写文件等操作都是以socker形式向 DFS Broker 发出请求来完成。这样对于不同的文件系统,只要实现一个 DFS Broker 就可以与 Hypertable 一起工作了。 - 存储引擎:(K: where?)
Hypertable 设计是为了使用分布式存储系统,但是当然也可以使用本地文件系统。 存储引擎只需要提供最简单的几个功能就可以与 Hypertable 协同工作了。
- 怎么将数据分布到各个节点
(注意,这里只是指对数据的服务分布到节点的问题,存储由底层存储引擎解决)
一种简单的方法是把数据按照某种方式均匀分布到所 有节点。但是这就要求每一次查询都要所有节点参与。这只有在每个表,每次查询结果数据量都足够大的时候才是可行的。数据库显然不符合这个要求(搜索引擎在 这一点上是ok的)(K:没懂)
Hypertable 实际上是把一个表,按照主键顺序分成 range,每个range被一个 RangeServer 管理起来。 - 负载均衡
在 Hypertable 中,Master 负责负载均衡。它会检查各个 RangeServer 的状态,根据情况,调整 RangeServer 所负责的具体 Range. - 数据的存储
因为 Hypertable 使用其他的分布式存储系统,所以它本省不需要考虑这个问题。但是为了适应其他的分布式存储,要求 Hypertable 在实现的时候只能使用文件系统的一个子集,而且要时刻考虑到分布式文件系统的一些特点。这直接决定了底层存储结构的设计。而 couch db 这种,自己开发了存储引擎的,在上层设计上就可以自由得多。 - 版本控制和一致性
Hypertable 提供多版本(K:应该是数据的version)支持,根据配置保存一定的历史版本记录,以时间作为索引。当使用查询限制条件的limit=1的时候,如果出来不止一条记录,不要奇怪,因为还 有版本这个维度。除非再加上revs=1。 - 可靠性
一个节点挂掉,不能影响服务的提供。因为数据都存储在分布式的文件系统上。所以一个节点挂掉的时候,数据并没有丢失。这个时候,Master 会调度其他节点接过挂掉节点所负责的 range 继续对外提供服务。
- range
在 hypertable 中,一张表被按照主键划分成 N 个 range。range 是负责均衡的单位,一个 range 只能被一个 RangeServer 所管理。range在增长到一定大小之后要分裂。
举一个具体的例子来解释一下。我们的示例表只有两个字段,id 和 name。 id是主键。开始的时候,整个表只有一个range, 所有对这个表的操作,都由一个 RangeServer 来处理。现在假设我们不断的插入数据,range内的数据在增长,当数据增长到一个配置值,这里假设是100条记录吧(实际上一般是百兆级别)。我们认为 这个range已经太大了,需要分裂。 怎么分裂呢?按照主键从中间开始分成两个range。比如id现在的范围是1 – 100 那么从50开始,1-50的是一个range,51-无穷的是第二个range。这个时候 Master 会根据负载均衡,把其中一个调度到其他 RangeServer 上。这样就实现的负载均衡。这个例子里主键是id。那么第一个range,1-50的那个是不是就不会增长分裂了呢。不一定的,别忘了 hypertable 是保留多版本的。所以数据的修改也会导致range里数据量的增加,然后再分裂。 - access group
数据库对数据的存储在逻辑上有两种方式:
按行存储:可以把所有列的数据存储在一起; 按列存储:也可以把列分开存储. 两种存储方式各有利 弊。适用不同的应用场景。
Hypertable 里增加了access group 概念。可以把几个列组成一个 access group,那么这几个列就会存储在一起。极端的,每个列一个access group 则等于按列存储。所有列一个access group 则等于按行存储。 - column family 和 column qualifier
可以把 column family 想象成传统数据库的列,column qualifier 想象成列的某种分类。这个设计是为了方便互联网应用而做出的。这个概念在使用 Hypertable 的时候很有作用。本文的目的是介绍 Hypertable 的实现。对此不做详细讨论。
--------------------------------------------------------------------------------------------
Column Qualifiers
This feature provides a way for users to introduce sparse column data that can be easily selected with Hypertable Query Language (HQL) or any of the other query interfaces.
A column specification in the Hypertable CREATE TABLE statement actually defines a set of related columns known as acolumn family. Users may supply an optional column qualifier and specify the qualified column as family:qualifier. The qualifier is a NUL-terminated string. For example, if a column familytag is specified in a CREATE TABLE statement, as shown below,
- CREATE TABLE Info (
- tag
- );
then qualified columns such as the following may be created/inserted into the table.
<code>tag:bigtable tag:nosql tag:bigdata</code>
(K:相比于hypertable.com的documentation, 上面那段介绍简直太TM土了)
Data Representation
Like a relational database, Hypertable represents data as tables of information. Each row in a table has cells containing related information, and each cell is identified, in part, by a row key and column name. Support for up to 255 column names is provided when the table is created. Hypertable provides two additional features:
- • column qualifier - The column names defined in the table schema are referred to as column families. Applications may supply an optional column qualifier, with each distinct qualifier representing a qualified column instance belonging to the column family . The application can define an unlimited number of qualified instances of a column family. The application supplied column name has the formatfamily:qualifier, and column data is stored in a sparse format such that one row may have millions of qualified instances of a column family, while another row may have none or just a few instances.
- timestamp - This is a 64-bit field associated with each cell that allows for different cell versions. The value represents nanoseconds since theUnix epoch and can be supplied by the application or auto-assigned by the server. The number of versions stored can be configured in the table schema and the number of versions returned can be specified in the query predicate. The versions are stored in reverse-chronological order, so that the newest version of the cell is returned first.
The following diagram illustrates how data is represented in Hypertable. The table is an example taken from a web crawler that stores information for each page that it crawls in a row of the table.
The above diagram illustrates the use of the column qualifier. A Web search engine builds an index (much like the one in the back of a book) that points words to the Web documents that contain them. Included in this index are not only the words included in the Web page, but also words included in the anchor text of the remote links that point to the Web page. This is how image results can appear in Web search results. For example, given an image of a Ferrari (which contains no text), if there are enough links pointing to the image that contain the word "Ferrari" in the anchor text, then the page may get a high score for the query "Ferrari" and appear in the search results.
The one dimension that is missing from the above diagram is the timestamp. Imagine that each cell in the diagram above has a z-axis that contains timestamped versions of the cell. This multi-dimensional table gets flattened out, under the hood, as sorted lists of key/value pairs as illustrated in the following diagram.
--------------------------------------------------------------------------------------------
Physical Layout
A relational database assumes that each column defined in the table schema will have a value for each row that is present in the table. NULL values are usually represented with a special marker (e.g. \N). The primary key and column identifier are implicitly associated with each cell based on its physical position within the layout. The following diagram illustrates how a relational database table might be laid out on disk.
Hypertable (and Bigtable) takes its design from the Log Structured Merge Treepdf. It flattens out the table structure into a sorted list of key/value pairs, each one representing a cell in the table. The key includes the full row and column identifier, which means each cell is provided complete addressing information. Cells that are NULL are simply not included in the list which makes this design particularly well-suited for sparse data. The following diagram illustrates how Hypertable stores table data on-disk.
Though there can be a fair amount of redundancy in the row keys and column identifiers, Hypertable employs key-prefix and block data compression which considerably mitigates this problem.
- CellStore
一个 CellStore 由一些列的 block 再加上一个对block的索引以及一些查询优化信息(Bloom Filter)组成。关于Bloom Filter 后边再介绍,我们先把注意力放到bolock和索引上。
首先,一个 CellStore 中的数据是按照主键排序了的,其次,索引是只索引到block的。
举一个具体的例子来看一下(我们只关注block和索引,忽略 Bloom Filter 信息文件头信息等)。还是那个id,name两个列的表。我们现在看一个CellStore,id从0到400.每一百数据为一个block。那么存储起 来好像是类似的样子 :
一个range收到查询请求的时候先读取CellStore中的索引部分,这样可以定位出所需要的数据在哪个block中,然后读取相应的block并遍历查找所需要的数据。一般一个block的大小为64k。
看起来很简单,问题来了,数据的插入显然不是按照顺序插入的,怎么存储成这种排序的形式呢?这是 因为所有插入操作其实都是在内存中进行。当内存中数据达到一定的数量的时候才持久化成上面的形式到文件系统里。
那么假设现在id为0-400的数据已经持 久化到文件系统了,新来的这一范围的数据怎么办呢(比如对id为205的数据做更新,我们知道所有的更新操作实际上是插入新的数据来实现的)?还是先写到 内存中,当内存中的数据达到一定数量的时候在持久化成另外一个CellStore.
那么查询的时候怎么得到所需要的数据呢,对的,要在几个 CellStore(内存中那个没持久化的也可以认为是一个特殊的CellStore)同时进行查找然后合并。再借用 Hypertable 的一个图释
随着数据的变化,Cell Store在逐渐的增加,这样就会减慢查询的效率。为了解决这个问题,需要后台有进程合并已经持久化的Cell Store。这一个过程叫做merging compaction(big table术语)。这也是丢弃无用记录的好时候(hypertable 允许配置保留最近n个版本的记录或者最近n时间的记录)。这个过程就类似一个归并排序的过程。那么当数据越来越多的时候,是不是即便有合并过程,也会导致出现非常多的CellStore呢?别忘了,我们的range是有大小限制的。如果数据很多,range是要分裂的,另外一个range会被调度到较空闲 的 RangeServer 去运行。所以只要集群的节点足够,不需要担心这个问题。
介绍到这里应该对range的存储结构和工作方法有大略的认识了
- Table的MetaData
table由range组成。一个 table有哪些range组成,各个range所管理的范围是什么。这些信息怎么存储呢?这些其实也是以一个表(元数据表)的形式存贮在 Hypertable 中的。只是这个表有些特殊。先看一个从big table转过来的图释
注意:bigtable 里的chubby就是Hypertable里面的Hyperspace。
这个图释是什么意思呢?
在Hyperspace里面存储了 元数据表 的 元数据 信息(K: bigtable 看样子是把元数据表的metadata 存在chubby上了)。 听着绕嘴吧,这是因为元数据表也是一张普通的表,它足够大的时候也要分裂成很多range。关于元数据表的range等信息息存储在Hyperspace 中,叫做Root table。Root table只增长,不分裂。也就是说Root table永远只有一个range,这是为了控制找到一个具体表信息的间接性不会大于三层。
假设我们要查找某个表的信息。这些信息是存储在元数据表中的。 我们需要先查找元数据表,但是实际上我们不知道去如何以及怎样查找元数据表,所以先要向hyperspace请求元数据表的元信息,具体来说就是查到我们 所需要查询的信息在元数据表的哪个rang中。然后去相应的range查找具体信息。为了减少与hyperspace的交互,客户端会缓存一些Root table的信息。(介绍到这里,大的逻辑层面上的重要概念就介绍完了。大家可以对Hypertable有一个大致的整体了解。但是很多优化,扩展等细节信息都被省略掉了,比 如数据压缩,Bloom Filter等。更细致的信息就需要大家自己去读源代码了。)
-------------------------------------------------
ref:http://hi.baidu.com/cpuramdisk/item/b4ba346f65a9210aa1cf0f36
Tablet存储
Hypertable为用户规划表数据存储提供了一定灵活度,从hypertable的扁平化过程可以看出,它采用面向列的存储模式。Hypertable采用access group方式组织数据存储(在表schema中定义),一个access group包含一个或多个column family。对于一个row range,属于一个access group的所有数据被组织在一起存储,access group是hypertable面向存储的最小访问单位。这样,对于有应用相关性的列,被组织存储在一起,可以有效地提高数据的读写效率。
一个Tablet包含一个表中特定row range的数据,它由系统中一台主机(range server)维护,系统中一台主机可以维护多个表的多个tablet。Tablet在存储前都被扁平化处理,以(key,value)对的形式存储在文件中,实际存储中,(key,value)对中加入了该数据的操作类型,如插入、更新、删除等。Tablet以文件形式存储。如图2-5所示,为一个典型的tablet存储目录结构。
Figure 2-5 An example of table directory in range server
在主机在维护tablet时,会在文件系统的table目录下创建对应的表目录,目录用表名命名。如上图所示,该主机维护了Pages,Accounts两个表的tablet。在每个table目录下会根据表的schema创建相应的access group目录,如Pages有三个access group,Accounts有两个access group。在access group目录下,系统会为每一个tablet创建一个目录,由系统生成的随机数(row range 系统编号)字符串命名。当前状态下,该主机维护了Pages表的两个tablets。由此可见,一个完整的row range(tablet)数据是指该表目录下,所有access group目录中,在相同row range目录下的文件集合。
如图2-5所示,表是以cs(CellStore)文件形式存储。CellStore文件存储Access Group中的(Key,Value)列表(带操作类型),文件中的数据经过排序,压缩,并且不会被修改。在CellStore文件内部包含多个64K(可配置)大小的块,为了便于索引CellStore中的数据,在CellStore文件的结尾处保存了这些块的索引数据,以便系统能迅速定位到数据在文件中的哪个64K块中。Cell store的索引主要有三个部分:
l Bloom Filter:该索引部分采用Bloom Filter技术,用于64k块内索引,目前保留,未实现;
l 块索引:该索引部分记录每64k块的索引,用于快速定位块,它的格式为 row key + 块在文件内的偏移;
l Trailer:用于定位Bloom Filter块,块索引部分的定位。系统读取这部分,获取Bloom Filter和块索引的位置。
随着数据的增长,在一个row range(tablet)中,一个access group可以动态产生多个CellStore文件,这些文件由Range Server动态维护,参照Range Server描述。
一个示例
如图2-6所示的逻辑模型,示例crawldb table用于存储从internet抓取的网页信息,其中:Row Key为网页的URL,出于排序效率考虑,URL中主机域名字符顺序往往被反置,如www.facebook.com被处理为com.facebook.www;Column Family包括title、content、anchor,其中tile保存网页的标题,content保存网页html内容,anchor保存网页被其它网页引用的链接,qualifier就是其它网页的URL,内容为其它网页中该链接的页面显示字符,同样anchor链接的URL主机域字符串被反置。对于不同时间获取的同一网页的有关内容被打上不同的时间戳,如图纵向座标可以看到不同的版本。
Figure 2-6 Crawldb Table Logical Model
六 源码心得
- key结构
在 hypertable 中数据是一系列的 key/value 对。其中 key 是一个所谓四维的关键字:
看到这样的 Key 可想而知,对于每行的每个列,都有一个上面这样的 key 存在。所以当 row key 比较长,而列的内容不是很大的时候,如果发现key占用的空间比value要大,也不要奇怪。插一句,通过对表本身的设计,可以达到数据非常好的可压缩 性,再配以适合的压缩算法可以很大的提升对空间的利用。事实上,如何设计一个良好的 row key 在对 hyoertable 的使用中也是很重要的一个方面,别忘了 row key 是支持范围查找的。这种 key/value 结构对于按列存储有很好的支持,所以在设计 hypertable 应用的时候,列完全可以作为一种强有力的可查询手段。
--------------------------------------------------------------------
ref: http://hypertable.com/documentation/architecture/
ANATOMY OF A KEY
The following diagram illustrates the format of the key that Hypertable uses internally.
- control - This field is consists of bit flags that describe the format of the remaining fields. There are certain circumstances where the timestamp or revision number may be absent, or where they are identical, in which case, they're collapsed into a single field. This field contains that information and tells Hypertable how to properly interpret the key.
- row key - This field contains a '\0' terminated string that represents the row key.
- column family - This field is a single-byte field that indicates the column family code.
- column qualifier - This field contains a '\0' terminated string that represents the column qualifier.
- flag - Deletes are handled through the insertion of special "delete" records (or tombstones) that indicate that some portion of a row's cells have been deleted. These delete records are applied at query time and the deleted cells are garbage collected during major compactions.
- timestamp - This field is an 8-byte (64-bit) field that contains the cell timestamp, represented as nanoseconds since the Unix epoch. By default, the timestamp is stored big-endian, ones-compliment so that within a given cell, versions are stored newest to oldest.
- revision - This field is an 8-byte (64-bit) field that contains a high resolution timestamp that currently is used internally to provide snapshot isolation for queries.
- 按索引查询
Hypertable 目前版本还只能按照主键进行查询。很多应用又的确有通过索引查询的需求,那么如何实现这种需求呢。我们可以读一读与 hypertable 同源的 Hbase 的实现。Hbase 现在已经支持了索引,可以预计,将来 Hypertable 支持索引的方式与 Hbase 应该是近似的。
那么 Hbase 是如何来对列做索引的呢?其实就是再建立一张表,用需要被索引的列做键值,value是被索引记录的主键。实际上 Hbase 是允许用户自己定义索引的生成算法的,这里要注意,索引表的 row key 也要是唯一值。不然会认为后面的是对前面的版本覆盖。可是对于某些列,做索引的时候必然无法保证值的唯一。比如一个员工登记表,员工号是唯一 row key,而我们希望在员工名字上作索引,显然员工名字是有可能有重复的。按照上面的说法,为了在员工名字上建立索引我们需要另建一张表,row key 是员工名字,value 是员工号。假设员工号为10和40的员工都叫做张三。那么索引表里在row key 张三下就会出现两条记录,值分别是10和40. 这个时候就无法区分到底是新插入不同的记录还是对原来记录的修改,造成混乱。那么怎么解决呢,我们看一下Hbase的一个默认算法类 SimpleIndexKeyGenerator.java。 简单来说,他用被索引列的 column value 和 row key 作为索引列的 row key。还是上面的例子,现在我们索引表里两条记录分别是 row key = 张三_10 value = info1; row key = 张三_40 value = info2. 因为查询是支持范围查找的,所以当我们只查“张三”的时候,被索引的列都可以查到了。上面是简化例子说明,具体信息请查看源代码。