• HBase基础知识(7):扫描操作之ResultScanner类


    扫描操作不会通过一次RPC请求返回所有匹配的行,而是以行为单位进行返回。很明显,行的数目很大,可能有上千条甚至更多,同时在一次请求中发送大量数据,会占用大量的系统资源并消耗很长时间。

    ResultScanner类把扫描操作转换为类似的get操作,它将每一行数据封装成一个Result实例,并将所有的Result实例放入一个迭代器中。ResultScanner的一些方法如下:

    Result next() throws IOException
    Result[] next(int nbRows) throws IOException
    void close()

    有两种类型next()调用供用户选择。调用close()方法会释放所有由扫描控制的资源。

    扫描器租约
    要确保尽早释放扫描器实例,一个打开的扫描器会占用不少的服务端资源,累积多了会占用大量的堆空间。当使用完ResultScanner之后调用它的close()方法,同时,当把close()方法放到try/finally块中,以保证其在迭代获取数据过程中出现异常和错误时,仍然能执行close()。
    就像行锁一样,扫描器也使用同样的租约超时机制,保护其不被失效的客户单阻塞太久。用户可以使用修改锁租约处提到的那个配置属性来修改超时时间(单位:毫秒):

    <property>
      <name>hbase.regionserver.lease.period</name>
      <value>120000</value>
    </property>

    用户需要确保该属性值适当,这个值要同时适用于锁租约和扫描器租约。
    next()调用返回了一个单独的Result实例,这个实例代表了下一个可用的行。此外,用户可以使用next(int nbRows) 一次获取多行数据,它返回一个数组,数组中包含的Result实例最多可达nbRows个,每个实例代表唯一的一行。当用户扫描到表尾或到终止行时,由于没有足够的行来填充数据,返回的结果数组可能会小于既定长度。

    下边是实现扫描器获取表中数据代码

    import java.io.IOException;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.HBaseConfiguration;
    import org.apache.hadoop.hbase.client.HTable;
    import org.apache.hadoop.hbase.client.Result;
    import org.apache.hadoop.hbase.client.ResultScanner;
    import org.apache.hadoop.hbase.client.Scan;
    import org.apache.hadoop.hbase.util.Bytes;
    
    public class HBaseResultScanner {
        public static void main(String[] args) throws IOException {
            Configuration conf = HBaseConfiguration.create();
            HTable table = new HTable(conf, "testtable");
            Scan scan1 = new Scan();
            ResultScanner scanner1 = table.getScanner(scan1);
            for (Result res : scanner1) {
                System.out.println(res);
            }
            scanner1.close();
            Scan scan2 = new Scan();
            scan2.addFamily(Bytes.toBytes("colfam1"));
            ResultScanner scanner2 = table.getScanner(scan2);
            for (Result res : scanner2) {
                System.out.println(res);
            }
            scanner2.close();
            Scan scan3 = new Scan();
            scan3.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("col-5"))
                    .addColumn(Bytes.toBytes("colfam2"), Bytes.toBytes("col-33"))
                    .setStartRow(Bytes.toBytes("row-10"))
                    .setStopRow(Bytes.toBytes("row-20"));
            ResultScanner scanner3 = table.getScanner(scan3);
            for (Result res : scanner3) {
                System.out.println(res);
            }
            scanner3.close();
    
        }
    
    }

    代码插入了100行数据,每行有两个列族,每个列族下包含100个列。第一个扫描全表内容,第二个扫描操作只扫描一个列族,最后一个操作有严格的限制条件,其中包括对行范围的限制,同时还要求只扫描两个特定的列。
    输出如下:

    Scanning table # 3...
    keyvalues={row-10/colfam1:col-5/1300803775078/Put/vlen=8,row-10/colfam2:col-33/1300803775099/Put/vlen=9}
    keyvalues={row-100/colfam1:col-5/1300803775079/Put/vlen=9,
    row-100/colfam1:col-33/1300803775095/Put/vlen=10
    }
    keyvalues={row-11/colfam1:col-5/1300803775152/Put/vlen=8,
    row-11/colfam1:col-33/1300803775170/Put/vlen=9
    }
    keyvalues={row-12/colfam1:col-5/1300803775212/Put/vlen=8,
    row-12/colfam1:col-33/1300803775246/Put/vlen=9
    }
    keyvalues={row-13/colfam1:col-5/1300803775345/Put/vlen=8,
    row-13/colfam1:col-33/1300803775376/Put/vlen=9
    }
    keyvalues={row-14/colfam1:col-5/1300803775479/Put/vlen=8,
    row-14/colfam1:col-33/1300803775498/Put/vlen=9
    }
    keyvalues={row-15/colfam1:col-5/1300803775554/Put/vlen=8,
    row-15/colfam1:col-33/1300803775582/Put/vlen=9
    }
    keyvalues={row-16/colfam1:col-5/1300803775665/Put/vlen=8,
    row-16/colfam1:col-33/1300803775687/Put/vlen=9
    }
    keyvalues={row-17/colfam1:col-5/1300803775734/Put/vlen=8,
    row-17/colfam1:col-33/1300803775748/Put/vlen=9
    }
    keyvalues={row-18/colfam1:col-5/1300803775791/Put/vlen=8,
    row-18/colfam1:col-33/1300803775805/Put/vlen=9
    }
    keyvalues={row-19/colfam1:col-5/1300803775843/Put/vlen=8,
    row-19/colfam1:col-33/1300803775859/Put/vlen=9
    }
    keyvalues={row-2/colfam1:col-5/1300803774463/Put/vlen=7,
    row-2/colfam1:col-33/1300803774485/Put/vlen=8
    }

    再强调一次,匹配的行键都是按词典序列排列的,这使得结果非常有趣。用户可以简单地用0把行键补齐,这样扫描出来的结果顺序更有可读性。

  • 相关阅读:
    JNDI 是什么
    RuntimeException和非RuntimeException的区别
    dynamicinsert,dynamicupdate能够性能上的少许提升
    Session,有没有必要使用它?[转]
    c# textbox中光标所在行命令及选中命令移动到最后一行且光标提前[转]
    C#分布式事务(TransactionScope )
    .net中的分布式事务
    大道至简,职场上做人做事做管理[转]
    C#中TreeView的CheckBox的两种级联选择
    C# winform TreeView中关于checkbox选择的完美类[转]
  • 原文地址:https://www.cnblogs.com/ainima/p/6331834.html
Copyright © 2020-2023  润新知