Hbase 学习(九) 华为二级索引(原理)
转自:http://my.oschina.net/u/923508/blog/413129
这个是华为的二级索引方案,已经开放源代码了,下面是网上的一篇讲解原理的帖子,发出来和大家共享一下。
经过本人认真阅读了一下代码,发现这个源码仅供参考,想要集成到原有的集群当中是有点儿难度的,它对hbase的源码进行不少的修改。
源码地址:https://github.com/Huawei-Hadoop/hindex
下面来对其方案做一个分析。
1.整体架构
这个架构在Client Ext中设定索引细节,在Balancer中收集信息,在Coprocessor中管理二级索引数据。

2.表创建
在创建表的时候,在同一个region server上创建索引表,且一一对应。
3.插入操作
在主表中插入某条数据后,用Coprocessor将索引列写到索引表中去,写道索引表中的数据的主键为:region开始key+索引名+索引列值+主表row key。这么做,是为了让其在同一个分布规则下,索引表会跟主表在通过region server上,在查询的时候就可以少一次rpc。
4.scan操作
一个查询到来的时候,通过coprocessor钩子,先从索引表中查询范围row,然后再从主表中相关row中扫描获得最终数据。
5. split操作处理
为了使主表和索引表在同一个RS上,要禁用索引表的自动和手动split,只能由主表split的时候触发,当主表split的时候,对索引表按其对应数据进行划分,同时,对索引表的第二个daughter split的row key的前面部分修改为对应的主键的row key。
6. 性能
查询性能极大提升,插入性能下降10%左右
总结,本文对华为hbase使用coprocessor进行二级索引的方案的创建表,插入数据,查询数据的步骤进行了一个粗略分析,以窥其全貌。在使用的时候,可以作为一个参考。
转载自:http://www.dengchuanhua.com/167.html
————————————————————————————————————————————————————————————
二级索引实现方式:http://www.aboutyun.com/thread-14201-1-1.html
常见的二级索引方案有以下几种:
1.MapReduce方案
2.ITHBASE方案
3.IHBASE方案
4.Coprocessor方案
5.Solr+hbase方案
MapReduce方案
优点:并发批量构建Index
缺点:不能实时构建Index
原表:
| 1 2 3 | row  1      f1:name  zhangsanrow  2      f1:name  lisirow  3      f1:name  wangwu | 
索引表:
| 1 2 3 | row     zhangsan    f1:id1row     lisi        f1:id2row     wangwu      f1:id3 | 
Demo
| 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | package IndexDouble;importjava.io.IOException;importjava.util.HashMap;importjava.util.Map;importjava.util.Set;importorg.apache.commons.collections.map.HashedMap;importorg.apache.hadoop.conf.Configuration;importorg.apache.hadoop.hbase.HBaseConfiguration;importorg.apache.hadoop.hbase.client.HConnection;importorg.apache.hadoop.hbase.client.HConnectionManager;importorg.apache.hadoop.hbase.client.Put;importorg.apache.hadoop.hbase.client.Result;importorg.apache.hadoop.hbase.client.Scan;importorg.apache.hadoop.hbase.io.ImmutableBytesWritable;importorg.apache.hadoop.hbase.mapreduce.MultiTableOutputFormat;importorg.apache.hadoop.hbase.mapreduce.TableInputFormat;importorg.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;importorg.apache.hadoop.hbase.mapreduce.TableMapper;importorg.apache.hadoop.hbase.util.Bytes;importorg.apache.hadoop.mapreduce.Job;importorg.apache.hadoop.util.GenericOptionsParser;public class IndexBuilder {    private String rootDir;    private String zkServer;    private String port;    private Configuration conf;     private HConnection hConn = null;    private IndexBuilder(String rootDir,String zkServer,String port) throws IOException{        this.rootDir = rootDir;        this.zkServer = zkServer;        this.port = port;        conf = HBaseConfiguration.create();        conf.set("hbase.rootdir", rootDir);        conf.set("hbase.zookeeper.quorum", zkServer);        conf.set("hbase.zookeeper.property.clientPort", port);        hConn = HConnectionManager.createConnection(conf);      }    static class MyMapper extends TableMapper<ImmutableBytesWritable, Put>{        //记录了要进行索引的列        private Map<byte[], ImmutableBytesWritable> indexes = new                 HashMap<byte[], ImmutableBytesWritable>();        private String familyName;        @Override        protected void map(ImmutableBytesWritable key, Result value,                Context context) throws IOException, InterruptedException {            //原始表列            Set<byte[]> keys = indexes.keySet();            //索引表的rowkey是原始表的列,索引表的列是原始表的rowkey            for(byte[] k : keys){                //获得新建索引表的表名                ImmutableBytesWritable indexTableName = indexes.get(k);                //Result存放的是原始表的数据                //查找到内容             根据列族 和 列 得到原始表的值                byte[] val = value.getValue(Bytes.toBytes(familyName), k);                if(val != null) {                    //索引表                    Put put = new Put(val);//索引表行键                    //列族  列   原始表的行键                    put.add(Bytes.toBytes("f1"),Bytes.toBytes("id"),key.get());                    context.write(indexTableName, put);                }            }        }        //真正运行Map之前执行一些处理。        @Override        protected void setup(Context context) throws IOException,                InterruptedException {            //通过上下文得到配置            Configuration conf = context.getConfiguration();            //获得表名            String tableName = conf.get("tableName");             //Stringfamily = conf.get("familyName");            //获得列族            familyName = conf.get("columnFamily");            //获得列            String[] qualifiers = conf.getStrings("qualifiers");             for(String qualifier : qualifiers) {                //建立一个映射,为每一个列创建一个表,表的名字tableName+"-"+qualifier                //原始表的列    索引表新建表名                indexes.put(Bytes.toBytes(qualifier),                         new ImmutableBytesWritable(Bytes.toBytes(tableName+"-"+qualifier)));            }        }       }    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {        String zkServer = "hadoop1";        String port = "2181";        IndexBuilder conn = new IndexBuilder(rootDir,zkServer,port);        String[] otherArgs = new GenericOptionsParser(conn.conf, args).getRemainingArgs();         //IndexBuilder: TableName,ColumnFamily,Qualifier        if(otherArgs.length<3){            System.exit(-1);        }        //表名        String tableName = otherArgs[0];        //列族        String columnFamily = otherArgs[1];        conn.conf.set("tableName", tableName);        conn.conf.set("columnFamily", columnFamily);        //列  可能存在多个列        String[] qualifiers = new String[otherArgs.length-2];        for(int i = 0; i < qualifiers.length; i++) {            qualifiers[i] = otherArgs[i+2];        }        //设置列        conn.conf.setStrings("qualifiers", qualifiers);        @SuppressWarnings("deprecation")        Job job = new Job(conn.conf,tableName);        job.setJarByClass(IndexBuilder.class);        job.setMapperClass(MyMapper.class);        job.setNumReduceTasks(0);//由于不需要执行reduce阶段        job.setInputFormatClass(TableInputFormat.class);        job.setOutputFormatClass(MultiTableOutputFormat.class);        Scan scan = new Scan();        TableMapReduceUtil.initTableMapperJob(tableName,scan,                 MyMapper.class, ImmutableBytesWritable.class, Put.class, job);        job.waitForCompletion(true);    }} | 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | 创建原始表hbase(main):002:0> create 'studentinfo','f1'0 row(s) in0.6520 seconds=> Hbase::Table - studentinfohbase(main):003:0> put 'studentinfo','1','f1:name','zhangsan'0 row(s) in0.1640 secondshbase(main):004:0> put 'studentinfo','2','f1:name','lisi'0 row(s) in0.0240 secondshbase(main):005:0> put 'studentinfo','3','f1:name','wangwu'0 row(s) in0.0290 secondshbase(main):006:0> scan 'studentinfo'ROW                      COLUMN+CELL 1                       column=f1:name, timestamp=1436262175823, value=zhangsan 2                       column=f1:name, timestamp=1436262183922, value=lisi 3                       column=f1:name, timestamp=1436262189250, value=wangwu3 row(s) in0.0530 seconds | 
| 1 2 3 4 5 6 | 创建索引表hbase(main):007:0> create 'studentinfo-name','f1'0 row(s) in0.7740 seconds=> Hbase::Table - studentinfo-name | 

ITHBASE方案
缺点:需要重构hbase,几年没有更新。
http://github.com/hbase-trx/hbase-transactional-tableindexed
IHBASE方案
缺点:需要重构hbase。
原理:在Memstore满了以后刷磁盘时,IHBase会进行拦截请求,并为这个memstore的数据构建索引,索引另一个CF的方式存储在表内。scan的时候,IHBase会结合索引列中的标记,来加速scan。
http://github.com/ykulbak/ihbase
Coprocessor方案
http://github.com/Huawei-Hadoop/hindex
1.multiple indexes on table,
2.multi column index,
3.index based on part of a column value,
4.equals and range condition scans using index, and
5.bulk loading data to indexed table (Indexing done with bulk load).
Solr+hbase方案
Solr是一个高性能,采用Java5开发,基干Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能节理界面,是一款非常优秀的全文搜索引擎。
基于Solr的HBase多条件查询原理很简单,将HBase表中涉及条件过滤的字段和rowkey在Solr中建立索引,通过Solr的多条件查询快速获得符合过滤条件的rowkey值,拿到这些rowkey之后在HBASE中通过指定rowkey进行查询。
<ignore_js_op>

 
                    
                
 






 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号