一、介绍
在HBase客户端的API中提供了两种从服务器端获取数据的方式。Get行获取和Scan扫描表的方式。下面就简单介绍一些使用Get获取数据时的使用方法
二、数据获取
Get数据的获取与上节Put数据插入一样,分为多种使用方式。
1、单行获取:get(Get get)
单行获取每次RPC请求值发送一个Get对象中的数据,因为Get对象初始化时需要输入行键,因此可以理解为一个Get对象就代表一行。一行中可以包含多个列簇或者多个列等信息
public void get(String tableName,String rowKey,String family,String qualifier)
{
Configuration conf=init();
try {
//进行管理员获取
HBaseAdmin admin=new HBaseAdmin(conf);
if(!admin.tableExists(Bytes.toBytes(tableName)))
{
System.err.println("the table "+tableName+" is not exist");
admin.close();
System.exit(1);
}
admin.close();
//创建表连接
HTable table=new HTable(conf,TableName.valueOf(tableName));
//创建一个获取对象
Get get=new Get(Bytes.toBytes(rowKey));
//根据传入的值,进行获取判断
if(family!=null && qualifier!=null)
{
get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
}
else if(family != null && qualifier == null)
{
get.addFamily(Bytes.toBytes(family));
}
//获取数据
Result result=table.get(get);
KeyValue[] kvs=result.raw();
for(KeyValue kv:kvs)
{
System.out.println(Bytes.toString(kv.getRow()));
System.out.println(Bytes.toString(kv.getFamily()));
System.out.println(Bytes.toString(kv.getQualifier()));
System.out.println(Bytes.toString(kv.getValue()));
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
从上述代码中我们可以看到,Get实例使用 addColumn / addFamily 着两个函数想Get中添加搜索范围。如果没有添加,则表示将整行数据进行返回。如果添加列簇,则将指定的列簇中的所有列进行返回,如果指定列,则将制定的列进行返回。
2、获取多行: get(List<Get> list)
多行获取获取实质就是在代码中对List<Get>实例进行迭代,从而发送多次数据请求(即多个RPC请求与数据操作,一次请求包含一次RPC请求和一次数据传输)。
public void getList(String tableName,String[] rows,String[] families,String[] qualifiers)
{
Configuration conf=init();
try {
//判断表是否存在
HBaseAdmin admin=new HBaseAdmin(conf);
if(!admin.tableExists(Bytes.toBytes(tableName)))
{
System.err.println("the table "+tableName+" is not exist");
admin.close();
System.exit(1);
}
//创建表连接
HTable table=new HTable(conf, Bytes.toBytes(tableName));
List<Get> gets=new ArrayList<>();
int length=rows.length;
for(int i=0;i<length;i++)
{
Get get=new Get(Bytes.toBytes(rows[i]));
get.addColumn(Bytes.toBytes(families[i]), Bytes.toBytes(qualifiers[i]));
gets.add(get);
}
//对结果进行递归输出
Result[] results=table.get(gets);
for(Result result:results)
{
KeyValue[] keyValues=result.raw();
for(KeyValue kv:keyValues)
{
System.out.println(Bytes.toString(kv.getRow()));
System.out.println(Bytes.toString(kv.getFamily()));
System.out.println(Bytes.toString(kv.getQualifier()));
System.out.println(Bytes.toString(kv.getValue()));
}
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
3、获取数据或者前一行:getRowOrBefore()
该函数是HTable类提供的一个借口。作为为:当参数中的行存在时,则将本行指定的列簇进行返回,如果不存在时,则返回表中存在的指定行的前一行的数据进行返回。
public void getRowOrBefore(String tableName,String row,String family,String qualifier)
{
Configuration conf=init();
try {
HBaseAdmin admin=new HBaseAdmin(conf);
if(!admin.tableExists(tableName))
{
System.out.println("the table "+tableName+" is not exist");
admin.close();
System.exit(1);
}
//创建表连接
HTable table=new HTable(conf, tableName);
//执行函数
Result result=table.getRowOrBefore(Bytes.toBytes(row),Bytes.toBytes(family));
//进行循环
KeyValue[] keyValues=result.raw();
for(KeyValue kv: keyValues)
{
System.out.println(Bytes.toString(kv.getRow()));
System.out.println(Bytes.toString(kv.getFamily()));
System.out.println(Bytes.toString(kv.getQualifier()));
System.out.println(Bytes.toString(kv.getValue()));
System.out.println(Bytes.toString(kv.getKey()));
}
table.close();
} catch (Exception e) {
// TODO: handle exception
}
}
注意:在函数中需要注意的是,所有行的row在HBase中的存储都是byte数组,其没有具体的类型,因此row-10 是小于 row-9。因此在进行比较是在第五位中1是小于9,HBase数据库则会认为row-10 是小于 row-9 的。如果指定顺序的话,则需要将数据的row的位数规定一致。则 row-9 应该更改为 row-09。通过这样的修改可以保证 row-09 是小于 row-10的。
4、结果显示:Result对象、KeyValue对象与Cell对象
(1)Result对象,在查询得到的结果,每一行数据会被作为一个Result对象,将数据存入到一个Result实例中。当我们需要获取一行数据时则需要获取该行数据所在的Result对象即可。该对象内部封装了一个KeyValue 对象数组。在0.98.4以前的本班。result类提供了 raw() 方法去获取整个result对象中的KeyValue数组。在0.98.4以后,则提供了一个新的节后: rowCells() 方法获取KeyValue对象,不过返回的是KeyValue 对象父类引用。
(2)KeyValue对象。该对象我们已经进行过介绍。因此这里我们只进行其使用的展示
public void KVObject(String tableName,String row,String family,String qualifier)
{
Configuration conf=init();
try {
HBaseAdmin admin=new HBaseAdmin(conf);
if(!admin.tableExists(Bytes.toBytes(tableName)))
{
System.err.println("the table "+tableName+" is not exist");
admin.close();
System.exit(1);
}
admin.close();
//创建表连接
HTable table=new HTable(conf, tableName);
//查询一行并返回result对象
Get get=new Get(Bytes.toBytes(row));
Result result=table.get(get);
//进行循环
KeyValue[] keyValues=result.raw();
for(KeyValue kv: keyValues)
{
System.out.println(Bytes.toString(kv.getRow()));
System.out.println(Bytes.toString(kv.getFamily()));
System.out.println(Bytes.toString(kv.getQualifier()));
System.out.println(Bytes.toString(kv.getValue()));
System.out.println(Bytes.toString(kv.getKey()));
}
table.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
(3)Cell对象:Cell对象是KeyValue对象的父类,Cell对象中的所有方法在KeyValue对象中全部被实现。因此根据继承的特征,我们可以使用Cell对象中的API操作KeyValue对象。
public void CellObject(String tableName,String row,String family,String qualifier)
{
Configuration conf=init();
try {
//查看表是否存在
HBaseAdmin admin=new HBaseAdmin(conf);
if(!admin.tableExists(tableName))
{
System.out.println("the table "+tableName+" is not exist");
admin.close();
System.exit(1);
}
admin.close();
//创建表连接
HTable table=new HTable(conf, tableName);
Get get=new Get(Bytes.toBytes(row));
get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
Result result=table.get(get);
Cell[] cells=result.rawCells();
for(Cell cell:cells)
{
System.out.println(Bytes.toString(cell.getRow()));
System.out.println(Bytes.toString(cell.getFamily()));
System.out.println(Bytes.toString(cell.getQualifier()));
System.out.println(Bytes.toString(cell.getValue()));
}
table.close();
} catch (Exception e) {
// TODO: handle exception
}
}
三、Get对象的详细配置
上述讲述了如何使用Get从HBase中获取数据,并将数据进行展示,其实Get对象中的很多属性可以控制在进行查询时的细节控制,从而控制数据从HBase服务器返回时的数据量,从而可以进行数据优化
(1)Get(byte[] row) / Get(byte[] row, RowLock lock)
初始化函数。在初始化函数时必须要指定Get将要获取的行键,第二个函数则是允许用户自己对Get上一个行锁,但是系统并不赞成用户这么使用。因为在多个客户端进行操作,且都上了自定义的行锁以后,可能会出现因为彼此的行锁需要对方的资源而死锁现象。但是两个客户端的长时间等待与系统连接资源的占用。
(2)addFamily() / addColumn()
添加列簇 / 添加列函数。通过该函数Get在数据获取时,获取的数据范围:两个函数都不设定时获取正行的所有数据。 使用 addFamily时获取制定列簇的所有列的数据。 addColumn则获取制定列的数据
(3)setTimeStamp()
获取指定的时间戳对象
(4)setTimeRange(long minTime,long maxTime)
获取该时间戳范围内的数据
(5)setMaxVersion(int version) / setMaxVersion()
在默认情况下,Get方法之获取一列的最新的版本。但是有时需要的话则会一次获取多个版本的数据。 第一个函数可以指定确切的返回的版本数量。第二个函数则相当于setMaxVersion(Integer.MAX_VALUE)。即获取列中所有版本的 数据。
(6)setCacheBlock(boolean open)
是否打开服务器端快缓存。在HBase中,整个表以region分块的方式被分布式的存在不同的region服务器中。每一个region服务器将会维护多个region。而在每一个region中都会存在快缓存区域。当每次去读某一个KeyValue数据块时,则会将整个数据加载到缓存区中。又因为加载的数据远大于一个KeyValue所含的数据大小。所以一般情况下缓存区域内都会存放当前KeyValue对象的连续的数据。但是如果在随机读写的程序中,这种数据加载进入缓存区并没有任何的作用,反而会因为在家时间而使得数据获取时间增长。因此我们要根据实际情况去选择是否开启region上的缓存区。连续读写时,开始缓存区可以增加搜索速度。在随机读写时,关闭缓存区可以缩小读取时间。
(7)setFilter(Filter f)
添加过滤器。因为HBase并没有原声的SQL指定环境,因此在SQL语句中的where条件语句就需要通过特定的借口去实现,而Filter则就是顶替了where 语句的作用。能够实现在在数据查询中的一些精细的控制。过滤器的内容会在后面的章节进行详细的解释
四、总结
上述主要讲解了Get的使用和一些在进行数据获取时的需要注意的点,有时候可以通过修改特定的属性从而达到不同的效果。而Get类中的大部分API并没有被提到,因此如果继续需要深入学习的话可以去官网的 API中详细查看Get类中的所有的API。如果上述有错误的地方,还望指出,共勉。