“二级多列索引”是针对目标记录的某个或某些列建立的“键-值”数据,以列的值为键,以记录的RowKey为值,当以这些列为条件进行查询时,引擎可以通过检索相应的“键-值”数据快速找到目标记录。华为基于hbase开发的ctbase产品就提供了二级索引的实现,在建表时有两个选择,一个是把索引数据放在单独一张表上,一个是把索引数据与原数据放在同一张表中,为了能获得最佳的性能表现,一般是把索引数据与主数据放在一起,本文也是以此为例(索引数据放在单独的表中只是数据位置不一样,其它都一样),通过在rowkey前增加数字前缀,使得索引数据总是存放在主数据后面。当全体数据按RowKey排序时,排在前面的都是主数据,我们称之为主数据区,排在后面的均为索引,我们称之为索引区。
让我们通过一个示例来详细了解一下二级多列索引表的结构,假定有一张客户信息表(custom_info),以其中一个Region为例,请看图1,所有数据按RowKey进行字典排序,自动分成了索引区和主数据区两段,主数据区的Column Family是d,下辖v_cust_no, ci_name, ci_reg_birdy, ci_sex, ci_mbtelno, ci_addr等Qualifier,索引区的与主数据区在同一个Column Family,但单独建了一个Qualifier名字为i,这列只有rowkey,值都为空。 接下来是最重要的部分,即索引和主数据的RowKey,我们先看主数据的RowKey,它由数字0为前缀(后面跟着一个分隔符”-“)和原始id(这边是v_cust_no)组成。接下来看索引的RowKey,它的结构要相对复杂一些,格式为:索引编号-索引键-索引值,图中只展示了一个二级索引(实际上可以有很多二级索引),这其中索引编号是指二级索引的编号,根据创建的顺序进行编号,从1开始,由于主数据的前缀为0加分隔符,这样就保证了索引数据一定放在主数据之后,接下来的索引键就是由组成这个索引的列值组成,这个例子中就是ci_name,最后的索引值就是对应的主数据的原始id了(主数据rowkey去掉前缀)。
现在,假设要查找用户名(ci_name)为张三的数据,ctbase的客户端首先会根据它内部的一张元数据表(ctmeta)定位到该列对应的索引名及编号,这样就将scan的区间收缩到[1-,2-),接着拼接查询字段的值,我们得到了索引键:张三,scan区间又进一步收窄为[1-张三,1-李四),于是我们可以很快地找到1-张三-39570341370020000002这条索引,进而得到了索引值,也就是目标数据的RowKey:0^39570341370020000002,最后再通过Get操作得到对应的主数据。