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个,每个实例代表唯一的一行。当用户扫描到表尾或到终止行时,由于没有足够的行来填充数据,返回的结果数组可能会小于既定长度。有关怎样使用Result实例的问题请参阅前面介绍的"Result类",更详细的内容请参阅3.2.2节。
例3.18集中使用了之前解释过的功能,扫描了一张表,逐行处理了其中的列数据。
例3.18 使用扫描器获取表中数据
- 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();
创建一个空的Scan实例。
取得一个扫描器迭代访问所有的行。
打印行内容。
关闭扫描器释放远程资源。
只添加一个列族,这样可以禁止获取"colfam2"的数据。
使用builder模式将详细限制条件添加到Scan中。
代码插入了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/1300803780079/Put/vlen=9,
- row-100/colfam2:col-33/1300803780095/Put/vlen=10}
- keyvalues={row-11/colfam1:col-5/1300803775152/Put/vlen=8,
- row-11/colfam2:col-33/1300803775170/Put/vlen=9}
- keyvalues={row-12/colfam1:col-5/1300803775212/Put/vlen=8,
- row-12/colfam2:col-33/1300803775246/Put/vlen=9}
- keyvalues={row-13/colfam1:col-5/1300803775345/Put/vlen=8,
- row-13/colfam2:col-33/1300803775376/Put/vlen=9}
- keyvalues={row-14/colfam1:col-5/1300803775479/Put/vlen=8,
- row-14/colfam2:col-33/1300803775498/Put/vlen=9}
- keyvalues={row-15/colfam1:col-5/1300803775554/Put/vlen=8,
- row-15/colfam2:col-33/1300803775582/Put/vlen=9}
- keyvalues={row-16/colfam1:col-5/1300803775665/Put/vlen=8,
- row-16/colfam2:col-33/1300803775687/Put/vlen=9}
- keyvalues={row-17/colfam1:col-5/1300803775734/Put/vlen=8,
- row-17/colfam2:col-33/1300803775748/Put/vlen=9}
- keyvalues={row-18/colfam1:col-5/1300803775791/Put/vlen=8,
- row-18/colfam2:col-33/1300803775805/Put/vlen=9}
- keyvalues={row-19/colfam1:col-5/1300803775843/Put/vlen=8,
- row-19/colfam2:col-33/1300803775859/Put/vlen=9}
- keyvalues={row-2/colfam1:col-5/1300803774463/Put/vlen=7,
- row-2/colfam2:col-33/1300803774485/Put/vlen=8}
再强调一次,匹配的行键都是按词典序排列的,这使得结果非常有趣。用户可以简单地用0把行键补齐,这样扫描出来结果顺序更有可读性。这些都是在你的控制下完成的,所以请仔细设计行键。