zoukankan      html  css  js  c++  java
  • Hbase 学习(九) 华为二级索引(原理)

    转自:http://my.oschina.net/u/923508/blog/413129

    这个是华为的二级索引方案,已经开放源代码了,下面是网上的一篇讲解原理的帖子,发出来和大家共享一下。

    经过本人认真阅读了一下代码,发现这个源码仅供参考,想要集成到原有的集群当中是有点儿难度的,它对hbase的源码进行不少的修改。

    源码地址:https://github.com/Huawei-Hadoop/hindex

    下面来对其方案做一个分析。

    1.整体架构

    这个架构在Client Ext中设定索引细节,在Balancer中收集信息,在Coprocessor中管理二级索引数据。

    architecture  华为hbase二级索引(secondary index)细节分析

    2.表创建

    在创建表的时候,在同一个region server上创建索引表,且一一对应。

    tableCreate 华为hbase二级索引(secondary index)细节分析

    3.插入操作

    在主表中插入某条数据后,用Coprocessor将索引列写到索引表中去,写道索引表中的数据的主键为:region开始key+索引名+索引列值+主表row key。这么做,是为了让其在同一个分布规则下,索引表会跟主表在通过region server上,在查询的时候就可以少一次rpc。

    putOperation 华为hbase二级索引(secondary index)细节分析

    4.scan操作

    一个查询到来的时候,通过coprocessor钩子,先从索引表中查询范围row,然后再从主表中相关row中扫描获得最终数据。

    scan 华为hbase二级索引(secondary index)细节分析

    5. split操作处理

    为了使主表和索引表在同一个RS上,要禁用索引表的自动和手动split,只能由主表split的时候触发,当主表split的时候,对索引表按其对应数据进行划分,同时,对索引表的第二个daughter split的row key的前面部分修改为对应的主键的row key。

    split 华为hbase二级索引(secondary index)细节分析

    6. 性能

    查询性能极大提升,插入性能下降10%左右

    performance1 华为hbase二级索引(secondary index)细节分析

    performance2 华为hbase二级索引(secondary index)细节分析

    总结,本文对华为hbase使用coprocessor进行二级索引的方案的创建表,插入数据,查询数据的步骤进行了一个粗略分析,以窥其全貌。在使用的时候,可以作为一个参考。

    转载自:http://www.dengchuanhua.com/167.html

    ————————————————————————————————————————————————————————————

    二级索引实现方式:http://www.aboutyun.com/thread-14201-1-1.html

    HBase的一级索引就是rowkey,我们只能通过rowkey进行检索。如果我们相对hbase里面列族的列列进行一些组合查询,就需要采用HBase的二级索引方案来进行多条件的查询。 
    常见的二级索引方案有以下几种: 
    1.MapReduce方案 
    2.ITHBASE方案 
    3.IHBASE方案 
    4.Coprocessor方案 
    5.Solr+hbase方案

    MapReduce方案

    IndexBuilder:利用MR的方式构建Index 
    优点:并发批量构建Index 
    缺点:不能实时构建Index
    举例: 
    原表:
    [Bash shell] 纯文本查看 复制代码
    1
    2
    3
    row  1      f1:name  zhangsan
    row  2      f1:name  lisi
    row  3      f1:name  wangwu




    索引表:

    [Bash shell] 纯文本查看 复制代码
    1
    2
    3
    row     zhangsan    f1:id   1
    row     lisi        f1:id   2
    row     wangwu      f1:id   3




    Demo

    [Bash shell] 纯文本查看 复制代码
    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;
     
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
     
    import org.apache.commons.collections.map.HashedMap;
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.HBaseConfiguration;
    import org.apache.hadoop.hbase.client.HConnection;
    import org.apache.hadoop.hbase.client.HConnectionManager;
    import org.apache.hadoop.hbase.client.Put;
    import org.apache.hadoop.hbase.client.Result;
    import org.apache.hadoop.hbase.client.Scan;
    import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
    import org.apache.hadoop.hbase.mapreduce.MultiTableOutputFormat;
    import org.apache.hadoop.hbase.mapreduce.TableInputFormat;
    import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
    import org.apache.hadoop.hbase.mapreduce.TableMapper;
    import org.apache.hadoop.hbase.util.Bytes;
    import org.apache.hadoop.mapreduce.Job;
    import org.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");
                //String family = 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 rootDir = "hdfs://hadoop1:8020/hbase";
            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);
     
        }
    }



    [Bash shell] 纯文本查看 复制代码
    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) in 0.6520 seconds
     
    => Hbase::Table - studentinfo
     
     
    hbase(main):003:0> put 'studentinfo','1','f1:name','zhangsan'
    0 row(s) in 0.1640 seconds
     
    hbase(main):004:0> put 'studentinfo','2','f1:name','lisi'
    0 row(s) in 0.0240 seconds
     
    hbase(main):005:0> put 'studentinfo','3','f1:name','wangwu'
    0 row(s) in 0.0290 seconds
     
    hbase(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=wangwu
    3 row(s) in 0.0530 seconds




    [Bash shell] 纯文本查看 复制代码
    1
    2
    3
    4
    5
    6
    创建索引表
     
    hbase(main):007:0> create 'studentinfo-name','f1'
    0 row(s) in 0.7740 seconds
     
    => Hbase::Table - studentinfo-name




    执行结果
    <ignore_js_op>

    ITHBASE方案

    优点:ITHBase(Indexed Transactional HBase)是HBase的一个事物型的带索引的扩展。 
    缺点:需要重构hbase,几年没有更新。 
    http://github.com/hbase-trx/hbase-transactional-tableindexed

    IHBASE方案

    **优点:**IHBase(Indexed HBase)是HBase的一个扩展,用干支持更快的扫描。 
    缺点:需要重构hbase。 
    原理:在Memstore满了以后刷磁盘时,IHBase会进行拦截请求,并为这个memstore的数据构建索引,索引另一个CF的方式存储在表内。scan的时候,IHBase会结合索引列中的标记,来加速scan。 
    http://github.com/ykulbak/ihbase

    Coprocessor方案

    HIndex–来自华为的HBase二级索引 
    http://github.com/Huawei-Hadoop/hindex
    The solution is 100% Java, compatible with Apache HBase 0.94.8, and is open sourced under ASL.
    Following capabilities are supported currently. 
    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是一个独立的企业级搜索应用服务器,它对并提供类似干Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出查找请求,并得到XML格式的返回结果。 
    Solr是一个高性能,采用Java5开发,基干Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能节理界面,是一款非常优秀的全文搜索引擎。
    HBase无可置疑拥有其优势,但其本身只对rowkey支持毫秒级的快速检索,对于多字段的组合查询却无能为力。 
    基于Solr的HBase多条件查询原理很简单,将HBase表中涉及条件过滤的字段和rowkey在Solr中建立索引,通过Solr的多条件查询快速获得符合过滤条件的rowkey值,拿到这些rowkey之后在HBASE中通过指定rowkey进行查询。 
    <ignore_js_op>
  • 相关阅读:
    cookie和session及token的区别联系
    linux/Deepin /Debian 9 Stretch安装Wine
    Deepin 15.9系统直接运行exe运行程序
    cookie和session及token的区别联系
    Deepin 15.9系统直接运行exe运行程序
    deepin系统右键刷新解决增删改文件没有变化
    linux/Deepin /Debian 9 Stretch安装Wine
    deepin系统右键刷新解决增删改文件没有变化
    Linux系统中的截图功能(类似QQ、微信、Snipaste截图功能)
    Linux系统中的截图功能(类似QQ、微信、Snipaste截图功能)
  • 原文地址:https://www.cnblogs.com/cxzdy/p/5169075.html
Copyright © 2011-2022 走看看