HBase总结(4)--数据扫描与Scan对象

一、介绍

Put、Delete与Get对象都是Row的子类,从该继承关系中我们就可以了解到Get、Delete与Pu对象本身就只能进行单行的操作,HBase客户端还提供了一套能够进行全表扫描的API,方便用户能够快速对整张表进行扫描,以获取想要的结果---scan

二、流程介绍

全表扫描是一种不需要行键值的操作,因此初始化时不需要指定行键值,因此就产生了不同的使用方法

1、不进行Scan对象创建的全表扫描

在该过程中,Htable对象会在扫描请求发送前隐式的创建一个scan对象,然后传递给Hbase服务器集群。

 

[java] view plain copy

  1. public void scanWithoutInit(String tableName,String family)  
  2.     {  
  3.         Configuration conf=init();  
  4.         try {  
  5.             HBaseAdmin admin=new HBaseAdmin(conf);  
  6.             if(!admin.tableExists(tableName))  
  7.             {  
  8.                 System.err.println("the table "+tableName+" is not exist");  
  9.                 admin.close();  
  10.                 System.exit(1);  
  11.             }  
  12.             //创建表连接  
  13.             HTable table=new HTable(conf, tableName);  
  14.             //获取全表扫描  
  15.             ResultScanner resultScanner=table.getScanner(Bytes.toBytes(family));  
  16.             //对结果进行显示  
  17.             Iterator<Result> results=resultScanner.iterator();  
  18.             while(results.hasNext())  
  19.             {  
  20.                 Result result=results.next();  
  21.                 for(KeyValue kv:result.raw())  
  22.                 {  
  23.                     System.out.println(Bytes.toString(kv.getRow()));  
  24.                     System.out.println(Bytes.toString(kv.getFamily()));  
  25.                     System.out.println(Bytes.toString(kv.getQualifier()));  
  26.                     System.out.println(Bytes.toString(kv.getValue()));  
  27.                 }  
  28.             }  
  29.         } catch (Exception e) {  
  30.             // TODO: handle exception  
  31.             e.printStackTrace();  
  32.         }  
  33.     }  

getScanner()方法时,如果不输入指定的scan对象,则需要输入相应的列簇或者列。因此在不进行scan对象创建的扫描中,需要明确指出列簇或者列,如果需要扫描多个列簇时,该方法就无法起到作用了。

2、进行初始化的全表扫描

初始化一个scan对象,然后对该对象进行相应的配置过,通过 getScanner(Scan scan) 函数进行全表扫描。

 

[java] view plain copy

  1. public void scanWithInit(String tableName)  
  2.     {  
  3.         Configuration conf=init();  
  4.         try {  
  5.             HBaseAdmin admin=new HBaseAdmin(conf);  
  6.             if(!admin.tableExists(tableName))  
  7.             {  
  8.                 System.err.println("the table "+tableName+" is not exist");  
  9.                 admin.close();  
  10.                 System.exit(1);  
  11.             }  
  12.             //创建扫描类  
  13.             Scan scan=new Scan();  
  14.             scan.setStartRow(Bytes.toBytes("row-1"));  
  15.             scan.setStopRow(Bytes.toBytes("row-9"));  
  16.             //创建表连接  
  17.             HTable table=new HTable(conf, tableName);  
  18.             ResultScanner rs=table.getScanner(scan);  
  19.             Result result;  
  20.             while((result=rs.next())!=null)  
  21.             {  
  22.                 KeyValue[] kvs=result.raw();  
  23.                 for(KeyValue kv:kvs)  
  24.                 {  
  25.                     System.out.println(Bytes.toString(kv.getRow()));  
  26.                     System.out.println(Bytes.toString(kv.getFamily()));  
  27.                     System.out.println(Bytes.toString(kv.getQualifier()));  
  28.                     System.out.println(Bytes.toString(kv.getValue()));  
  29.                 }  
  30.             }  
  31.             rs.close();  
  32.             table.close();  
  33.         } catch (Exception e) {  
  34.             // TODO: handle exception  
  35.             e.printStackTrace();  
  36.         }  
  37.     }  


在上段代码中,使用了setStartRow() 与 setStopRow() 两个函数进行调优。Scan有多个函数可以进行对全表扫描做出相应的规范。

3、数据遍历与显示ScannerResult

通过上述两种方法可以发送对一张表是遍历请求,当发送后,服务器会相应的启动全表扫面程序,从而准备向客户端返回相应的数据。因此根据客户端的遍历需要对数据尽心请求,然后将请求的结果进行返回,客户端拿到后进行展示

(1)next()的单行返回数据的方法

 

[java] view plain copy

  1. ResultScanner rs=table.getScanner(Bytes.toBytes(family));  
  2. //进项单行获取演示  
  3. Result result=null;  
  4. while((result=rs.next())!=null)  
  5. {  
  6.     KeyValue[] kvs=result.raw();  
  7.     for(KeyValue kv:kvs)  
  8.     {  
  9.         System.out.println(Bytes.toString(kv.getRow()));  
  10.         System.out.println(Bytes.toString(kv.getFamily()));  
  11.         System.out.println(Bytes.toString(kv.getQualifier()));  
  12.         System.out.println(Bytes.toString(kv.getValue()));  
  13.     }  
  14. }  
  15. rs.close();  

next()方法会默认想客户端请求发送一行数据请求,刚服务器端的scan程序接收到请求后会将经需要返回的数据封装成一个result对象返回给客户端,因此客户端可以通过result对象去接受该行数据。接收到的数据则跟Get中的result使用方法是相同的。

(2)next(int n)的多行返回数据的方法

next(int n):该函数会向服务器发送多个请求,以返回多条数据请求。

 

[java] view plain copy

  1. //一次获取多个结果(行数据)进行展示  
  2.             rs=table.getScanner(Bytes.toBytes(family));  
  3.             Result[] results=null;  
  4.             while((results=rs.next(2))!=null)  
  5.             {  
  6.                 for(Result r:results)  
  7.                 {  
  8.                     KeyValue[] kvs=r.raw();  
  9.                     for(KeyValue kv:kvs)  
  10.                     {  
  11.                         System.out.println(Bytes.toString(kv.getRow()));  
  12.                         System.out.println(Bytes.toString(kv.getFamily()));  
  13.                         System.out.println(Bytes.toString(kv.getQualifier()));  
  14.                         System.out.println(Bytes.toString(kv.getValue()));  
  15.                     }  
  16.                 }  
  17.             }  
  18.             rs.close();  

next(int n)函数返回的是一个result数组。用户接受到数据后可以进行相应的操作。

(3)迭代器遍历

 

[java] view plain copy

  1. //进行迭代的方式进行输出  
  2.             rs=table.getScanner(Bytes.toBytes(family));  
  3.             Iterator<Result> resultIterator=rs.iterator();  
  4.             while(resultIterator.hasNext())  
  5.             {  
  6.                 result=resultIterator.next();  
  7.                 KeyValue[] kvs=result.raw();  
  8.                 for(KeyValue kv:kvs)  
  9.                 {  
  10.                     System.out.println(Bytes.toString(kv.getRow()));  
  11.                     System.out.println(Bytes.toString(kv.getFamily()));  
  12.                     System.out.println(Bytes.toString(kv.getQualifier()));  
  13.                     System.out.println(Bytes.toString(kv.getValue()));  
  14.                 }  
  15.             }  
  16.             //关闭表  
  17.             rs.close();  

(4)注意点

因为当用户发送一个scan全表扫描后,region服务器会为全表扫描创建扫描资源,因此长时间启用全表扫描的话会占用region服务器的大量资源,所以在要求在使用完scanner扫描器后尽快释放掉资源。

rs.close() 会告知服务其扫描器租约已经结束,服务器就会释相应的全局扫描的资源。

三、Scan对象

(1)setStartRow() / setStopRow

设置扫描的开始行与结束行,通过这两个可以直接确scan在扫描的范围,通过缩小范围可以减少扫描到时间,从而提高扫描的效率

(2)addFamily() / addColumn() 

通过这两个函数,可以在列或者列簇上的扫描位置。HBase是面向lie出书的数据库,而同一个列簇的数据全部存放在同一个位置文件中。因此如果可以确定扫描那个一列簇时,可以减少扫描的范围,从而缩短扫描的时间。而在确定到某一个列时也会因为HBase的面向列存储使得其效率提高。

(3)setMaxVersion() / setMaxVersion(int version)

设置返回的版本数量,默认为返回最新的数据。第一个函数则会返回所有的版本数据,第二个函数可以设置返回的版本数量

(4)setTimeStamp(long max) 

返回该时间戳的数据

(5)setTimeRange(long min,long max)

设定返回的时间戳的范围,只有版本值在该范围之内的数据才会被返回到客户端

(6)setFilter(Filter f)

设置过滤器,有时候扫描全表返回的数量过大时,可以通过过滤器将不符合的数据进行过滤,这样可以减少从服务器到客户端的数据传送,挺高扫描效率。

(7)setCacheBlocks(boole open)

在进行全表扫描过程中,服务器端提供了一个缓存区,该缓存区可以将指定的数据量全部放入到内存中,这样可以提高读取效率。缓存区的打开也可以通过htable客户端进行打开。在开发后用户可以通过 setCache(int n)的方式设置每次缓存的数量为多少。通过调整该函数以提高读取的效率。

四、总结

scan的全表扫描区别于其他三个操作,虽然获取数据与Get获取的数据是相同的,其与Get也具有形似的属性,可以通过修改这些属性去对数据获取进行调优,从而使得提高数据获取的效率。

转载于:https://my.oschina.net/sniperLi/blog/1594744

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值