• 一个自定义 HBase Filter -“通过RowKeys来高性能获取数据”


    摘要:  大家在使用HBase和Solr搭建系统中经常遇到的一个问题就是:“我通过SOLR得到了RowKeys后,该怎样去HBase上取数据”。使用现有的Filter性能差劲,网上也没有现成的自定义Filter解决方案,在这里把这个问题的解决办法分享给大家,抛砖引玉一下。先讲一下,虽然使用自定义过滤器来达到取数据的目的,但它其实并不是一个好的解决办法,因为它的性能是有问题的,具体分析还要看我的博客HBase 高性能获取数据 - 多线程批量式解决办法http://www.cnblogs.com/wgp13x/p/4245182.html


    Solr和HBase专辑

    1、“关于Solr的使用总结的心得体会”(http://www.cnblogs.com/wgp13x/p/3742653.html)

    2、“中文分词器性能比较”(http://www.cnblogs.com/wgp13x/p/3748764.html)

    3、“Solr与HBase架构设计”(http://www.cnblogs.com/wgp13x/p/a8bb8ccd469c96917652201007ad3c50.html)

    4、 “大数据架构: 使用HBase和Solr将存储与索引放在不同的机器上”(http://www.cnblogs.com/wgp13x/p/3927979.html)

    5、“一个自定义 HBase Filter -通过RowKeys来高性能获取数据”(http://www.cnblogs.com/wgp13x/p/4196466.html)


           
             大数据架构: 使用HBase和Solr将存储与索引放在不同的机器上此文一经推出,览者众多,也有很多同仁朋友问我问题,看来近年关注先进大数据架构的公司越来越多了,基本上有数据接入的公司都会有这一问题。具我所知,“我该选Oracle还是MySQL作数据存储呢?”,“MySQL数据库索引创建后对双百分号%like不起作用啊!”,“没事,数据量再大我加存储柜不就行了?哈哈哈!”,这些都是还在用关系型数据库存储大数据的公司,它们往往对查询这块束手无策;它们的对策往往是:“我退而求其次,往年的数据我搜不了,我只搜今年的数据不就OK啦?反正业务单位我也能搞定。”--这是有垄断有背景的公司,也是不思进取的公司,“我分表,用户查近三个月的数据多,查前面的数据少,我每个月分一张表,解决了。”--这是吃了这顿没下顿的公司,抓紧把当前的项目搞完拿钱走人的公司,“上内存数据库哎,那个快。”--这是不管三七二十一、以屁股决定脑袋的公司。不管怎么说,能关注当前大数据架构技术的公司都是不落伍
     
          现在我把大家在使用HBase和Solr搭建系统中经常遇到的一个问题的解决办法在这里分享给大家,这个问题就是:“我通过SOLR得到了RowKeys后,该怎样去HBase上取数据”。
     
          相信有人开始发问了,HBase不是提供了功能很强劲的Filter了吗?Comparision Filters,Dedicated Filters,Decorating Filters,可以或可以且,可以相等,还可以组合,看起来很丰满,用起来很骨感。经过一番实践过后,性能低得吓人,使用200条RowKey在300百万的数据集中取数据,要等上好几钟,究其原因,多Filter的或组合过滤就是在HBase的数据里滚了一遍又一遍,不慢才怪。
     
            那么应该怎么做呢?自定义HBase Filter,这样只要滚一遍就好啦。RowKeyFilter就是自定义的Filter,它继承自FilterBase类,类中主要定义了三个属性,byte[] value用来传入RowKeys,Map<Object, Object>用来存放传入的RowKeys,撞到了就返回,boolean filterRow用来告诉HBase是否滤掉。下面是具体的RowKeyFilter代码。
     
    import java.io.DataInput;
    import java.io.DataOutput;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
     
    import org.apache.hadoop.hbase.KeyValue;
    import org.apache.hadoop.hbase.filter.FilterBase;
    import org.apache.hadoop.hbase.util.Bytes;
     
    /**
     * @description 自定义过滤器,用来读取大量离散行
     * @author 王安琪
     * @time 2014年11月8日上午10:47:17
     * @className RowKeyFilter
     */
    public class RowKeyFilter extends FilterBase
    {
        private byte[] value = null;
        private boolean filterRow = true;
        /**
         * map中存放需要读的行RowKey
         */
        public Map<Object, Object> map = new HashMap<Object, Object>();
     
        public RowKeyFilter()
        {
            super();
        }
     
        public RowKeyFilter(byte[] value)
        {
            this.value = value;
        }
     
        @Override
        public ReturnCode filterKeyValue(KeyValue ignored)
        {
            if (this.filterRow == false)
                return ReturnCode.INCLUDE;
            else
                return ReturnCode.NEXT_ROW;
        }
     
        /**
         * 行过滤,查询该行RowKey是否在Map中
         */
        @Override
        public boolean filterRowKey(byte[] buffer, int offset, int length)
        {
            byte[] rowKey = Arrays.copyOfRange(buffer, offset, offset + length);
            String str = new String(rowKey);
            if (map.containsKey(str))
            { // 在0(1)时间内返回,效率较高
                this.filterRow = false// false表示包括这一行
            }
            return this.filterRow;
        }
     
        @Override
        public void reset()
        {
            this.filterRow = true;
        }
     
        @Override
        public boolean filterRow()
        {
            return filterRow;
        }
     
        /**
         * 将Map中的数据以Byte[]形式传给服务器
         */
        @Override
        public void write(DataOutput dataOutput) throws IOException
        {
            Bytes.writeByteArray(dataOutput, this.value);
        }
     
        /**
         * 服务器读取Byte[]数据,再将数据存储到Map中 不同的RowKey以","分割
         */
        @Override
        public void readFields(DataInput dataInput) throws IOException
        {
            this.value = Bytes.readByteArray(dataInput);
     
            String string = new String(this.value);
            String[] strs = string.split(",");
            for (String str : strs)
            {
                map.put(str, str);
            }
        }
    }
     
    自定义Filter如何加载到HBase中,网上有很多的介绍,这里就不作说明了,下面列举出了如何使用RowKeyFilter的代码段来达到筛选的目的。
     
    /**
         * 根据rowKeys获取数据
         * 
         * @param rowKeys:每个rowkey之间使用逗号分隔符
         * @param filterColumn:表示过滤的列,如果为空表示所有列的数据都返回
         * @param isContiansRowkeys:设置为true,表示返回结果集中包含rowkeys;否则返回结果集中不包含rowkeys
         * @return
         */
        /* @Override */
        public Datas getDatasFromHbase(String rowKeys, List<String> filterColumn,
            boolean isContiansRowkeys)
        {
            Datas datas = new Datas();
            HTableInterface hTableInterface = getTable(tableName);
            Scan scan = new Scan();
            if (filterColumn != null)
            {
                for (String column : filterColumn)
                {
                    scan.addColumn(columnFamilyName.getBytes(), column.getBytes());
                }
            }
            if (rowKeys != null && rowKeys.length() > 0)
            {
                RowKeyFilter rowKeyFilter = new RowKeyFilter(rowKeys.getBytes());
                            scan.setFilter(rowKeyFilter);
            }
            ResultScanner resultScanner = null;
            List<Data> listData = new ArrayList<Data>();
            try
            {
                resultScanner = hTableInterface.getScanner(scan);
                for (Result result : resultScanner)
                {
                    Data data = new Data();
                    if (isContiansRowkeys)
                    {
                        data.setRowkey(new String(result.getRow()));
                    }
                    Map<String, String> map = new HashMap<String, String>();
                    List<String> content = new ArrayList<String>();
                    String[] temp = null;
                    if (filterColumn != null)
                    {
                        temp = new String[filterColumn.size()];
                    }
                    for (KeyValue keyValue : result.raw())
                    {
                        if (filterColumn == null)
                        {
                            content.add(new String(keyValue.getValue()));
                        }
                        else if (filterColumn != null)
                        {
                            String qualifier = new String(keyValue.getQualifier());
                            String value = new String(keyValue.getValue());
                            if (filterColumn.contains(qualifier))
                            {
                                int index = filterColumn.indexOf(qualifier);
                                temp[index] = value;
                            }
                        }
                    }
                    if (temp != null)
                    {
                        for (int i = 0; i < temp.length; i++)
                        {
                            content.add(temp[i]);
                        }
                    }
                  data.setContent(content);
                    listData.add(data);
                }
                datas.setDatas(listData);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            finally
            {
                resultScanner.close();
                try
                {
                    hTableInterface.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
            return datas;
        }
     
            经过验证,在MySQL单表数量为1000万时,过滤主键300个ID共花费20s左右;在HBase单表数据量达到1000万条时,过滤300条RowKey的数据共花了10多秒,显然此Filter的性能比自带Filter的性能提高了不少,还要优于MySQL主键获取,但我觉得尚且不够,性能还远远达不到目标要求。这种方式肯定不能达到高速度取数据的目的,高性能方法还要看我最新的博客:HBase 高性能获取数据 - 多线程批量式解决办法http://www.cnblogs.com/wgp13x/p/4245182.html
     
            另,有挂靠《系统集成项目管理师》的公司吗?我刚考过,有需要的Q我详聊写在2014年末。
     



  • 相关阅读:
    POJ 1062 坑爹的聘礼(枚举等级差选择性找边)
    c++ string函数详细返回值及用法!
    POJ 2240 利率变权值 Floyd变乘法
    POJ 1797 最大运载量
    API code
    编程题目的讨论
    C语言位运算符:与、或、异或、取反、左移和右移
    &与&& C语言
    反思
    CreateWindow的出错解决
  • 原文地址:https://www.cnblogs.com/wgp13x/p/4196466.html
Copyright © 2020-2023  润新知