文章目录
定义
HBase是一个面向列的数据库,在表中它由行排序。表模式定义只能列族,也就是键值对。一个表有多个列族以及每一个列族可以有任意数量的列。后续列的值连续地存储在磁盘上。表中的每个单元格值都具有时间戳。总之,在一个HBase:
· 表是行的集合。
· 行是列族的集合。
· 列族是列的集合。
· 列是键值对的集合。
HDFS HBase
HDFS是适于存储大容量文件的分布式文件系统。 HBase是建立在HDFS之上的数据库。
HDFS不支持快速单独记录查找。 HBase提供在较大的表快速查找
它提供了高延迟批量处理;没有批处理概念。 它提供了数十亿条记录低延迟访问单个行记录(随机存取)。
它提供的数据只能顺序访问。 HBase内部使用哈希表和提供随机接入,并且其存储索引,可将在HDFS文件中的数据进行快速查找。
HBase RDBMS
HBase无模式,它不具有固定列模式的概念;仅定义列族。 RDBMS有它的模式,描述表的整体结构的约束。
它专门创建为宽表。 HBase是横向扩展。 这些都是细而专为小表。很难形成规模。
没有任何事务存在于HBase。 RDBMS是事务性的。
它反规范化的数据。 它具有规范化的数据。
它用于半结构以及结构化数据是非常好的。 用于结构化数据非常好。
概述(Hbase version 1.2.12)
对于建表,和RDBMS类似,HBase也有namespace的概念,可以指定表空间创建表,也可以直接创建表,进入default表空间。
对于数据操作,HBase支持四类主要的数据操作,分别是:
Put :增加一行,修改一行;
Delete :删除一行,删除指定列族,删除指定column的多个版本,删除指定column的制定版本等;
Get :获取指定行的所有信息,获取指定行和指定列族的所有colunm,获取指定column,获取指定
column的几个版本, 获取指定column的指定版本等;
Scan :获取所有行,获取指定行键范围的行,获取从某行开始的几行,获取满足过滤条件的行等。
这四个类都是 org.apache.hadoop.hbase.client的子类,可以到官网API去查看详细信息,本文仅总结常用方法,力争让读者用20%的时间掌握80%的常用功能。
命名空间Namespace
在关系数据库系统中,命名空间
namespace指的是一个 表的逻辑分组 ,同一组中的表有类似的用途。命名空间的概念为 即将到来 的多租户特性打下基础:
配额管理( Quota Management (HBASE-8410)):限制一个namespace可以使用的资源,资源包括region和table等;
命名空间安全管理( Namespace Security Administration (HBASE-9206)):提供了另一个层面的多租户安全管理;
Region服务器组(Region server groups (HBASE-6721)):一个命名空间或一张表,可以被固定到一组 regionservers上,从而保证了数据隔离性。
命名空间管理
命名空间可以被创建、移除、修改。
表和命名空间的隶属关系 在在创建表时决定,通过以下格式指定:
:
Example:hbase shell中创建命名空间、创建命名空间中的表、移除命名空间、修改命名空间
#Create a namespace
create_namespace 'my_ns'
#create my_table in my_ns namespace
create 'my_ns:my_table', 'fam'
#drop namespace
drop_namespace 'my_ns'
#alter namespace
alter_namespace 'my_ns', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}
预定义的命名空间
有两个系统内置的预定义命名空间:
hbase :系统命名空间,用于包含hbase的内部表
default : 所有未指定命名空间的表都自动进入该命名空间
Example:指定命名空间和默认命名空间
#namespace=foo and table qualifier=bar
create 'foo:bar', 'fam'
#namespace=default and table qualifier=bar
create 'bar', 'fam'
创建表
废话不多说,直接上样板代码,代码后再说明注意事项和知识点:
private static final String TABLE_NAME = "blog:mytable2";
private static final String CF_DEFAULT = "mycf";
public static void createOrOverwrite(Admin admin, HTableDescriptor table) throws IOException {
// if (admin.tableExists(table.getTableName())) {
// admin.disableTable(table.getTableName());
// admin.deleteTable(table.getTableName());
// }
admin.createTable(table);
admin.close();
}
public static void createSchemaTables(Configuration config) throws IOException {
try (Connection connection = ConnectionFactory.createConnection(config);
Admin admin = connection.getAdmin()) {
HTableDescriptor table = new HTableDescriptor(TableName.valueOf(TABLE_NAME));
table.addFamily(new HColumnDescriptor(CF_DEFAULT).setCompressionType(Algorithm.NONE));
System.out.print("Creating table. ");
createOrOverwrite(admin, table);
System.out.println(" Done.");
}
}
public static void main(String... args) throws IOException {
Configuration config = HBaseConfiguration.create();
//Add any necessary configuration files (hbase-site.xml, core-site.xml)
config.addResource(new Path(System.getenv("HBASE_CONF_DIR"), "hbase-site.xml"));
config.addResource(new Path(System.getenv("HADOOP_CONF_DIR"), "core-site.xml"));
createSchemaTables(config);
}
关键知识点:
- 必须将HBase集群的hbase-site.xml文件添加进工程的classpath中,否则Configuration conf = HBaseConfiguration. create () 代码获取不到需要的集群相关信息,也就无法找到集群,运行程序时会报错;
- HTableDescriptor tableDesc = new HTableDescriptor(TableName. valueOf (TABLE_NAME )) 代码是描述表mytable,并将mytable放到了blog命名空间中,前提是该命名空间已存在,如果指定的是不存在命名空间,则会报 错org.apache.hadoop.hbase.NamespaceNotFoundException;
- 命名空间一般在建模阶段通过命令行创建,在java代码中通过admin.createNamespace(NamespaceDescriptor. create ( “blog” ).build()) 创建的机会不多;
- 创建 HBaseAdmin 对象时就已经建立了客户端程序与HBase集群的connection ,所以在程序执行完成后,务必通过 admin.close() 关闭connection;
- 可以通过 HTableDescriptor 对象设置 表的特性 ,比如: 通过tableDesc.setMaxFileSize(512) 设置一个region中的store文件的最大size,当一个region中的最大store文件达到这个size时,region就开始分裂; 通过tableDesc.setMemStoreFlushSize(512) 设置region内存中的memstore的最大值,当memstore达到这个值时,开始往磁盘中刷数据。 更多特性请自行查阅官网API;
- 可以通过 HColumnDescriptor 对象设置 列族的特性 ,比如:通过hcd.setTimeToLive(5184000) 设置数据保存的最长时间;通过 hcd.setInMemory(true ) 设置数据保存在内存中以提高响应速度;通过 hcd .setMaxVersions(10) 设置数据保存的最大版本数;通过 hcd.setMinVersions(5) 设置数据保存的最小版本数(配合TimeToLive使用)。更多特性请自行查阅官网API;
- 数据的版本数只能通过 HColumnDescriptor 对象设置,不能通过 HTableDescriptor对象设置;
- 由于HBase的数据是先写入内存,数据累计达到内存阀值时才往磁盘中flush数据,所以,如果在数据还没有flush进硬盘时,regionserver down掉了,内存中的数据将丢失。要想解决这个场景的问题就需要用到WAL(Write-Ahead-Log),tableDesc.setDurability(Durability. SYNC_WAL ) 就是设置写WAL日志的级别,示例中设置的是同步写WAL,该方式安全性较高,但无疑会一定程度影响性能,请根据具体场景选择使用;
- setDurability (Durability d)方法可以在相关的三个对象中使用,分别是:HTableDescriptor, Delete, Put(其中Delete和Put的该方法都是继承自父类org.apache.hadoop.hbase.client.Mutation) 。分别针对表、插入操作、删除操作设定WAL日志写入级别。需要注意的是, Delete和Put并不会继承Table的Durability级别(已实测验证) 。Durability是一个枚举变量,可选值参见4.2节。如果不通过该方法指定WAL日志级别,则为 默认 USE_DEFAULT 级别。
删除表
删除表没创建表那么多学问,直接上代码:
public static void deleteTable(Configuration config){
Admin admin=null;
try {
Connection connection = ConnectionFactory.createConnection(config);
admin = connection.getAdmin();
if (admin.tableExists(TableName.valueOf(TABLE_NAME))) {
admin.disableTable(TableName.valueOf(TABLE_NAME));
admin.deleteTable(TableName.valueOf(TABLE_NAME));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
admin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
说明 :删除表前必须先disable表。
修改表
实例代码
(1)删除列族、新增列族(注:换了个表测试)
修改之前,三个列族:
[hbase(main):011:0> desc "blog:article"
Table blog:article is ENABLED
blog:article
COLUMN FAMILIES DESCRIPTION
{NAME => 'action_log', BLOOMFILTER => 'ROW', VERSIONS => '10', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'TRUE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FORE
VER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
{NAME => 'f1', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', CO
MPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
{NAME => 'mycf', BLOOMFILTER => 'ROW', VERSIONS => '10', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'TRUE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER',
COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
3 row(s) in 0.0300 seconds
修改表,删除一个列族,新增一个列族,代码如下:
/**
* 添加和移除列族
*/
public static void addFamilyAndRemoveFamily(Configuration config){
Admin admin=null;
try {
Connection connection = ConnectionFactory.createConnection(config);
admin = connection.getAdmin();
if (admin.tableExists(TableName.valueOf(TABLE_NAME))){
admin.disableTable(TableName.valueOf(TABLE_NAME));
//get the TableDescriptor of target table
HTableDescriptor newtd = admin.getTableDescriptor (TableName.valueOf(Bytes.toBytes (TABLE_NAME)));
//remove 1 useless column families
newtd.removeFamily(Bytes.toBytes ( "mycf" ));
//create HColumnDescriptor for new column family
HColumnDescriptor newhcd = new HColumnDescriptor( "mycf_v1" );
newhcd.setMaxVersions(10);
newhcd.setKeepDeletedCells( true );
//add the new column family(HColumnDescriptor) to HTableDescriptor
newtd.addFamily(newhcd);
//modify target table struture
admin. modifyTable (TableName.valueOf(Bytes.toBytes (TABLE_NAME)),newtd);
admin.enableTable(TableName.valueOf(TABLE_NAME));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
admin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
修改之后:
[hbase(main):012:0> desc "blog:article"
Table blog:article is ENABLED
blog:article
COLUMN FAMILIES DESCRIPTION
{NAME => 'action_log', BLOOMFILTER => 'ROW', VERSIONS => '10', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'TRUE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FORE
VER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
{NAME => 'f1', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', CO
MPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
{NAME => 'mycf_v1', BLOOMFILTER => 'ROW', VERSIONS => '10', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'TRUE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER
', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
3 row(s) in 0.0370 seconds
逻辑很简单:
- 通过 admin.getTableDescriptor (TableName.valueOf(Bytes.toBytes (TABLE_NAME))) 取得目标表的描述对象,应该就是取得指向该对象的指针了;
- 修改目标表描述对象;
- 通过 admin. modifyTable (TableName.valueOf(Bytes.toBytes (TABLE_NAME)),newtd) 将修改后的描述对象应用到目标表。
(2)修改现有列族的属性(setMaxVersions)
/**
* 修改现有表的属性 例子是 修改最大的版本
*/
public static void setMaxVersions(Configuration config){
Admin admin=null;
try {
Connection connection = ConnectionFactory.createConnection(config);
admin = connection.getAdmin();
if (admin.tableExists(TableName.valueOf(TABLE_NAME))){
admin.disableTable(TableName.valueOf(TABLE_NAME));
//get the TableDescriptor of target table
HTableDescriptor htd = admin.getTableDescriptor (TableName.valueOf(Bytes.toBytes (TABLE_NAME)));
HColumnDescriptor infocf = htd.getFamily(Bytes. toBytes ( "mycf_v1" ));
infocf.setMaxVersions(100);
//modify target table struture
admin.modifyTable(TableName.valueOf(Bytes. toBytes ( TABLE_NAME)),htd);
admin.enableTable(TableName.valueOf(TABLE_NAME));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
admin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
新增、更新数据Put
常用构造函数:
(1)指定行键
public Put(byte[] row)
参数: row 行键
(2)指定行键和时间戳
public Put(byte[] row, long ts)
参数: row 行键, ts 时间戳
(3)从目标字符串中提取子串,作为行键
Put(byte[] rowArray, int rowOffset, int rowLength)
(4)从目标字符串中提取子串,作为行键,并加上时间戳
Put(byte[] rowArray, int rowOffset, int rowLength, long ts)
常用方法:
(1)指定 列族、限定符 ,添加值
add(byte[] family, byte[] qualifier, byte[] value)
(2)指定 列族、限定符、时间戳 ,添加值
add(byte[] family, byte[] qualifier, long ts, byte[] value)
(3) 设置写WAL (Write-Ahead-Log)的级别
public void setDurability(Durability d)
参数是一个枚举值,可以有以下几种选择:
ASYNC_WAL : 当数据变动时,异步写WAL日志
SYNC_WAL : 当数据变动时,同步写WAL日志
FSYNC_WAL : 当数据变动时,同步写WAL日志,并且,强制将数据写入磁盘
SKIP_WAL : 不写WAL日志
USE_DEFAULT : 使用HBase全局默认的WAL写入级别,即 SYNC_WAL
实例代码
(1)插入行
/**
* 插入行
* @param config
*/
public static void insertRow(Configuration config){
Table table =null;
Connection connection=null;
try {
connection = ConnectionFactory.createConnection(config);
table = connection.getTable(TableName.valueOf("blog:article"));
Put put = new Put(Bytes.toBytes ( "20190512_100001" ));
put.addColumn(Bytes.toBytes("f1"),Bytes.toBytes ( "name" ), Bytes.toBytes ( "lion"));
put.addColumn(Bytes.toBytes("f1"),Bytes.toBytes ( "address" ), Bytes.toBytes ( "shangdi"));
put.addColumn(Bytes.toBytes("f1"),Bytes.toBytes ( "age" ), Bytes.toBytes ( "30"));
put.setDurability(Durability.FSYNC_WAL );
table.put(put);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
table.close();
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
[hbase(main):043:0> get "blog:article","20190512_100001"
COLUMN CELL
f1:address timestamp=1557668524110, value=shangdi
f1:age timestamp=1557668524110, value=30
f1:name timestamp=1557668524110, value=lion
3 row(s) in 0.0130 seconds
注意:
- Put的构造函数都需要指定行键,如果是全新的行键,则新增一行;如果是已有的行键,则更新现有行。
- 创建Put对象及put.add过程都是在构建一行的数据,创建Put对象时相当于创建了行对象,add的过程就是往目标行里添加cell,直到table.put才将数据插入表格;
- 以上代码创建Put对象用的是构造函数1,也可用构造函数2,第二个参数是时间戳;
- Put还有别的构造函数,请查阅官网API。
(3) 从目标字符串中提取子串,作为行键,构建Put
Put put = new Put(Bytes. toBytes ( "100001_100002" ),7,6);
put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "name" ), Bytes. toBytes ("show" ));
put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "address" ), Bytes. toBytes ("caofang" ));
put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "age" ), Bytes. toBytes ( "30" ));
table.put(put);
table.close();
注意,关于: Put put = new Put(Bytes. toBytes ( “100001_100002” ),7,6)
- 第二个参数是偏移量,也就是行键从第一个参数的第几个字符开始截取;
- 第三个参数是截取长度;
- 这个代码实际是从 100001_100002 中截取了100002子串作为目标行的行键。
删除数据Delete
Delete类用于删除表中的一行数据,通过HTable.delete来执行该动作。
在执行Delete操作时,HBase并不会立即删除数据,而是对需要删除的数据打上一个“墓碑”标记,直到当Storefile合并时,再清除这些被标记上“墓碑”的数据。
如果希望删除整行,用行键来初始化一个Delete对象即可。如果希望进一步定义删除的具体内容,可以使用以下这些Delete对象的方法:
为了删除指定的列族,可以使用 deleteFamily
为了删除指定列的多个版本,可以使用 deleteColumns
为了删除指定列的 指定版本 ,可以使用 deleteColumn,这样的话就只会删除版本号(时间戳)与指定版本相同的列。如果不指定时间戳,默认只删除最新的版本
下面详细说明构造函数和常用方法:
构造函数
(1)指定要删除的行键
Delete(byte[] row)
删除行键指定行的数据。
如果没有进一步的操作,使用该构造函数将删除行键指定的行中 所有列族中所有列的所有版本 !
(2)指定要删除的行键和时间戳
Delete(byte[] row, long timestamp)
删除行键和时间戳共同确定行的数据。
如果没有进一步的操作,使用该构造函数将删除行键指定的行中,所有列族中所有列的 时间戳 小于等于 指定时间戳的数据版本 。
注意 :该时间戳仅仅和删除行有关,如果需要进一步指定列族或者列,你必须分别为它们指定时间戳。
(3)给定一个字符串,目标行键的偏移,截取的长度
Delete(byte[] rowArray, int rowOffset, int rowLength)
(4)给定一个字符串,目标行键的偏移,截取的长度,时间戳
Delete(byte[] rowArray, int rowOffset, int rowLength, long ts)
常用方法
Delete deleteColumn (byte[] family, byte[] qualifier) 删除指定列的 最新版本 的数据。
Delete deleteColumn s (byte[] family, byte[] qualifier) 删除指定列的 所有版本 的数据。
Delete deleteColumn (byte[] family, byte[] qualifier, long timestamp ) 删除指定列的 指定版本 的数据。
Delete deleteColumn s (byte[] family, byte[] qualifier, long timestamp ) 删除指定列的,时间戳 小于等于给定时间戳 的 所有 版本的数据。
Delete deleteFamily (byte[] family) 删除指定列族的所有列的 所有 版本数据。
Delete deleteFamily (byte[] family, long timestamp) 删除指定列族的所有列中 时间戳 小于等于 指定时间戳 的所有数据。
Delete deleteFamilyVersion (byte[] family, long timestamp) 删除指定列族中所有列的时间戳 等于 指定时间戳 的版本数据。
void setTimestamp (long timestamp) 为Delete对象设置时间戳。
实例代码
(1)删除整行的所有列族、所有行、所有版本
/**
* 删除整行
* @param config
*/
public static void deleteRow(Configuration config){
Table table =null;
Connection connection=null;
try {
connection = ConnectionFactory.createConnection(config);
table = connection.getTable(TableName.valueOf("blog:article"));
Delete delete = new Delete(Bytes.toBytes("20190512_100001"));
table.delete(delete);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
table.close();
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
[hbase(main):044:0> get "blog:article","20190512_100001"
COLUMN CELL
0 row(s) in 0.0180 seconds
(2)删除 指定列的最新版本
以下是删除之前的数据,注意看100003行的f1:age,这是该列最新版本的数据,值是300,在这之前的版本值是30:
[hbase(main):046:0> scan "blog:article"
ROW COLUMN+CELL
100001 column=f1:address, timestamp=1557665629702, value=shangdi
100001 column=f1:age, timestamp=1557665629702, value=30
100001 column=f1:name, timestamp=1557665629702, value=lion
100002 column=f1:address, timestamp=1557667236017, value=shangdi
100002 column=f1:age, timestamp=1557667236017, value=30
100002 column=f1:name, timestamp=1557667236017, value=lion
100003 column=f1:address, timestamp=1557669485106, value=shangdi
100003 column=f1:age, timestamp=1557669485106, value=300
100003 column=f1:name, timestamp=1557669485106, value=lion
3 row(s) in 0.0380 seconds
执行以下代码:
/**
* 删除 指定列的最新版本
*/
public static void deleteColumVersion(Configuration config){
Table table =null;
Connection connection=null;
try {
connection = ConnectionFactory.createConnection(config);
table = connection.getTable(TableName.valueOf("blog:article"));
Delete delete = new Delete(Bytes.toBytes("100003"));
delete.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("age"));
table.delete(delete);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
table.close();
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
然后查看数据,发现100003列的f1:age列的值显示为前一个版本的30了!其余值均不变:
hbase(main):047:0> scan "blog:article"
ROW COLUMN+CELL
100001 column=f1:address, timestamp=1557665629702, value=shangdi
100001 column=f1:age, timestamp=1557665629702, value=30
100001 column=f1:name, timestamp=1557665629702, value=lion
100002 column=f1:address, timestamp=1557667236017, value=shangdi
100002 column=f1:age, timestamp=1557667236017, value=30
100002 column=f1:name, timestamp=1557667236017, value=lion
100003 column=f1:address, timestamp=1557669485106, value=shangdi
100003 column=f1:name, timestamp=1557669485106, value=lion
3 row(s) in 0.0310 seconds
(3)主要的删除方法 不进行一一测试了
// Example application deleting data from HBase
// Create delete with specific row.
Delete delete = new Delete(Bytes.toBytes("row1"));
// Set timestamp for row deletes.
delete.setTimestamp(1);
// Delete the latest version only in one column
delete.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
// Delete specific version in one column
delete.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual3"), 3);
// Delete all versions in one column.
delete.addColumns(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
//Delete the given and all older versions in one column.
delete.addColumns(Bytes.toBytes("colfam1"), Bytes.toBytes("qual3"), 2);
// Delete entire family, all columns and versions.
delete.addFamily(Bytes.toBytes("colfam1"));
// Delete the given and all older versions in the entire column family, i.e., from all columns therein.
delete.addFamily(Bytes.toBytes("colfam1"), 3);
// Delete the data from the HBase table.
table.delete(delete);
示例中列举了用户通过设定不同的参数操作 delete() 方法。实际应用中没什么意义,可以随意注释掉一些调用,观察控制台显示结果变化。
删除操作所设定的时间戳只对匹配的单元格有影响,即匹配给定时间戳的列和值。另一方面,如果不设定时间戳,服务器会强制检索服务器端最新的时间戳,
这比执行一个具有明确时间戳的删除要慢。
如果尝试删除一个不存在的时间戳的 cell, 什么也不会发生。例如,某一列有两个版本,版本 10 和版本 20,删除版本 15 将不会影响现存的任何版本。
get 方法 (Get Method)
客户端 API 中的下一个步是从 HBase 中获取已保存的数据。为此,Table 接口提供了 get() 方法调用,以及相关的类。这类操作被划分为在单行上操作,
和在一次调用过程中在多个行上获取数据。
单行 get 操作 (Single Gets)
从一个 HBase 表中获取特定值的方法:
Result get(Get get) throws IOException
get() 操作界定为一个特定的行,但可以获取包含在该行上的任意数量的列或 cell. 创建 Get 实例时要提供一个行键 (row key), 使用下列构造器:
Get(byte[] row)
Get(Get get)
Get 的主构造器通过 row 参数指定要访问的那一行,第二个构造器接受一个已经存在的 Get 实例并复制该对象的整个细节信息,效果上等同于 clone 实例。
并且,类似于 put 操作,有很多方法来指定相当广泛依据来查找目标数据,也可以指定精确的坐标获取某个单元格 (cell) 数据:
Get addFamily(byte[] family)
Get addColumn(byte[] family, byte[] qualifier)
Get setTimeRange(long minStamp, long maxStamp) throws IOException
Get setTimeStamp(long timestamp)
Get setMaxVersions()
Get setMaxVersions(int maxVersions) throws IOException
addFamily() 调用将请求限定到给定的列族。可以多次调用以添加更多的列族。addColumn() 调用也类似,通过该调用可以更进一步限定访问的地址空间:
特定的列。其它方法可以使用户设定要查找数据的准确的时间戳,或者匹配一个时间范围的 cell.
最后,是指定要获取多少个版本的方法(如果没有设定准确的时间戳)。默认值为 1,意思为 get 调用只返回当前匹配的数据。没有参数的 setMaxVersions()
设定返回的版本数量为 Integer.MAX_VALUE, 也就是在列族描述符中(column family descriptor) 配置的最大版本数量,因此告诉 API 返回所有匹配 cell
的所有可用的版本。
之前提到过, HBase 为我们提供了一个辅助类 Bytes,其中有很多静态方法将 Java 类型转换为 byte[] 数组,反过来一样,Bytes 类提供了将数组转换为
Java 类型的方法。从 HBase 中获取数据,例如,以前保存的行,可以利用 Bytes 的这些辅助方法,将 byte[] 数据转换会 Java 类型。
static String toString(byte[] b)
static boolean toBoolean(byte[] b)
static long toLong(byte[] bytes)
static float toFloat(byte[] bytes)
static int toInt(byte[] bytes)
...
示例:
// Example application retrieving data from HBase
// Create the configuration.
Configuration conf = HBaseConfiguration.create();
// Instantiate a new table reference.
Connection connection = ConnectionFactory.createConnection(conf);
Table table = connection.getTable(TableName.valueOf("testtable"));
// Create get with specific row.
Get get = new Get(Bytes.toBytes("row1"));
// Add a column to the get.
get.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
// Retrieve row with selected columns from HBase.
Result result = table.get(get);
// Get a specific value for the given column.
byte[] val = result.getValue(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
// Print out the value while converting it back.
System.out.println("Value: " + Bytes.toString(val));
// Close the table and connection instances to free resources
table.close();
connection.close();
Get 类提供了许多方法调用,查阅 org.apache.hadoop.hbase.client.Get javadoc 获取详细信息。其中:
Get setCacheBlocks(boolean cacheBlocks)
boolean getCacheBlocks()
控制读操作如何在服务器端处理。每一个 HBase region server 有一个块缓存,用于保留最近访问的数据,以提升后续的读取效率。在某些情况下,最好
不要使用缓存以避免在完全随机的 get 访问时搅乱缓存中的信息。不要用不相关联的数据污染块缓存中的数据,最好跳过这些缓存的块使其保持不受破坏
以使其它客户端执行读取相关联的数据。
Get setCheckExistenceOnly(boolean checkExistenceOnly)
boolean isCheckExistenceOnly()
联合使用允许客户端检查某个特定的列集,或列族是否存在。示例如下:
// Checks for the existence of specific data
List<Put> puts = new ArrayList<Put>();
Put put1 = new Put(Bytes.toBytes("row1"));
put1.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"), Bytes.toBytes("val1"));
puts.add(put1);
Put put2 = new Put(Bytes.toBytes("row2"));
put2.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"), Bytes.toBytes("val2"));
puts.add(put2);
Put put3 = new Put(Bytes.toBytes("row2"));
put3.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual2"), Bytes.toBytes("val3"));
puts.add(put3);
// Insert two rows into the table.
table.put(puts);
Get get1 = new Get(Bytes.toBytes("row2"));
get1.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
get1.setCheckExistenceOnly(true);
// Check first with existing data.
Result result1 = table.get(get1);
byte[] val = result1.getValue(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
// Exists is “true”, while no cel was actually returned.
System.out.println("Get 1 Exists: " + result1.getExists());
System.out.println("Get 1 Size: " + result1.size());
System.out.println("Get 1 Value: " + Bytes.toString(val));
Get get2 = new Get(Bytes.toBytes("row2"));
get2.addFamily(Bytes.toBytes("colfam1"));
// Check for an entire family to exist.
get2.setCheckExistenceOnly(true);
Result result2 = table.get(get2);
System.out.println("Get 2 Exists: " + result2.getExists());
System.out.println("Get 2 Size: " + result2.size());
Get get3 = new Get(Bytes.toBytes("row2"));
get3.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual9999"));
// Check for a non-existent column.
get3.setCheckExistenceOnly(true);
Result result3 = table.get(get3);
System.out.println("Get 3 Exists: " + result3.getExists());
System.out.println("Get 3 Size: " + result3.size());
Get get4 = new Get(Bytes.toBytes("row2"));
get4.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual9999"));
get4.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
// Check for an existent, and non-existent column
get4.setCheckExistenceOnly(true);
Result result4 = table.get(get4);
// Exists is “true” because some data exists.
System.out.println("Get 4 Exists: " + result4.getExists());
System.out.println("Get 4 Size: " + result4.size());
● Alternative checks for existence
-------------------------------------------------------------------------------------------------------------------------------------
Table 类有另外一种方法检查数据在表中是否存在,提供如下方法:
boolean exists(Get get) throws IOException
boolean[] existsAll(List<Get> gets) throws IOException;
需要设定一个 Get 实例,就像使用 Table 的 get() 方法调用那样。只是验证某些数据是否存在,而不是从远程服务器上获取 cell 数据, 它们只返回
一个 boolean 类型的标志值表示数据是否存在。实际上,这些调用是在 Get 实例上使用 Get.setCheckExistenceOnly(true) 调用的快捷方式。
使用 Table.exists(), Table.existsAll(), 或者 Get.setCheckExistenceOnly() 在 region server 上的查找具有相同的语义,包括载入文件块来检查
一个行或列是否真的存在。只是避免在网络上携带数据,但对于检查非常多的列时很有用,或者进行非常频繁的检查。
Get setClosestRowBefore(boolean closestRowBefore)
boolean isClosestRowBefore()
提供某些模糊的行匹配。假设有一个复杂的行键设计,利用多个字段组成的复合数据。可以仅仅匹配行键中从左到右的数据,再假设有几个前导字段,但没有
更多具体的数据。可以使用 get() 方法请求某个特定的行。可以用一个 scan 操作开始。使用 setClosestRowBefore() 方法设置 closestRowBefore 值为 true
示例:
// Retrieves a row close to the requested, if necessary
Get get1 = new Get(Bytes.toBytes(“row3”));
// Attempt to read a row that does not exist.
get1.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
Result result1 = table.get(get1);
System.out.println("Get 1 isEmpty: " + result1.isEmpty());
CellScanner scanner1 = result1.cellScanner();
while (scanner1.advance()) {
System.out.println("Get 1 Cell: " + scanner1.current());
}
Get get2 = new Get(Bytes.toBytes("row3"));
get2.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
get2.setClosestRowBefore(true);
// Instruct the get() call to fall back to the previous row, if necessary.
Result result2 = table.get(get2);
System.out.println("Get 2 isEmpty: " + result2.isEmpty());
CellScanner scanner2 = result2.cellScanner();
while (scanner2.advance()) {
System.out.println("Get 2 Cell: " + scanner2.current());
}
// Attempt to read a row that exists.
Get get3 = new Get(Bytes.toBytes("row2"));
get3.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
get3.setClosestRowBefore(true);
Result result3 = table.get(get3);
System.out.println("Get 3 isEmpty: " + result3.isEmpty());
CellScanner scanner3 = result3.cellScanner();
while (scanner3.advance()) {
System.out.println("Get 3 Cell: " + scanner3.current());
}
Get get4 = new Get(Bytes.toBytes("row2"));
// Read exactly a row that exists.
get4.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual1"));
Result result4 = table.get(get4);
System.out.println("Get 4 isEmpty: " + result4.isEmpty());
CellScanner scanner4 = result4.cellScanner();
while (scanner4.advance()) {
System.out.println("Get 4 Cell: " + scanner4.current());
}
int getMaxResultsPerColumnFamily()
Get setMaxResultsPerColumnFamily(int limit)
int getRowOffsetPerColumnFamily()
Get setRowOffsetPerColumnFamily(int offset)
前面的一对方法用户处理 get 请求返回的 cell 的最大数量。后面的一对方法用于在行上设置一个可选的偏移量。
// Retrieves parts of a row with offset and limit
Put put = new Put(Bytes.toBytes("row1"));
for (int n = 1; n <= 1000; n++) {
String num = String.format("%04d", n);
put.addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("qual" + num), Bytes.toBytes("val" + num));
}
table.put(put);
Get get1 = new Get(Bytes.toBytes("row1"));
// Ask for ten cells to be returned at most.
get1.setMaxResultsPerColumnFamily(10);
Result result1 = table.get(get1);
CellScanner scanner1 = result1.cellScanner();
while (scanner1.advance()) {
System.out.println("Get 1 Cell: " + scanner1.current());
}
Get get2 = new Get(Bytes.toBytes("row1"));
get2.setMaxResultsPerColumnFamily(10);
// In addition, also skip the first 100 cells.
get2.setRowOffsetPerColumnFamily(100);
Result result2 = table.get(get2);
CellScanner scanner2 = result2.cellScanner();
while (scanner2.advance()) {
System.out.println("Get 2 Cell: " + scanner2.current());
}
Result 类 (The Result class)
使用 get() 方法调用获取数据时,会接收一个 Result 类的实例,其中包含所有匹配的单元格(cell)。 利用 Result 提供的方法,可以访问从服务器端返
回的给定行和匹配特定查询的所有数据的详细信息,例如列族,列限定符,时间戳,等等。
Result 有很多工具方法可以用于获取特定结果,第一类方法如下:
byte[] getRow()
byte[] getValue(byte[] family, byte[] qualifier)
byte[] value()
ByteBuffer getValueAsByteBuffer(byte[] family, byte[] qualifier)
ByteBuffer getValueAsByteBuffer(byte[] family, int foffset, int flength, byte[] qualifier, int qoffset, int qlength)
boolean loadValue(byte[] family, byte[] qualifier, ByteBuffer dst) throws BufferOverflowException
boolean loadValue(byte[] family, int foffset, int flength, byte[] qualifier, int qoffset, int qlength, ByteBuffer dst)
throws BufferOverflowException
CellScanner cellScanner()
Cell[] rawCells()
List<Cell> listCells()
boolean isEmpty()
int size()
getRow() 方法返回行键(row key), 调用 get() 方法时创建 Get 类实例时指定的行键值。size() 方法返回当前 Result 实例所包含 Cell 实例的数量。
可以使用这个调用,或者 isEmpty() 方法调用来检查自己的客户端代码,获取调用是否返回了一些匹配的数据。
getValue() 调用可以获取返回数据中某一特定的 cell 中的数据。由于不能在此调用中指定哪个时间戳,或者说,想要获取版本,因此得到的是最新版本
的数据。value() 调用返回找到的第一列中最新版本的数据。由于列在服务器上是按词汇顺序排序的,因此返回的列值首先是按列名(包括列族和限定符)
排序的。
还有其它一些单元格值的访问器,getValueAsByteBuffer() 和 loadValue(), 它们或者创建一个 Java ByteBuffer 对象,将数据的值封装到对象内的字节
数组中,或者将数据拷贝到提供的数据容器中。
访问原始的,低级别的 Cell 实例,通过 rawCells() 方法,返回当前 Result 实例内的 Cell 实例数组。listCells() 调用简单地将 rawCells() 调用
返回的数组转换到一个 List 实例中,给用户一个通过迭代器访问的便捷方法。Result 类也实现了 CellScannable 接口,因此可以直接地迭代访问其中
含有的 cell.
NOTE:
-------------------------------------------------------------------------------------------------------------------------------------
rawCells() 返回的数组是已经按词汇顺序排过序的,顾及到了 Cell 实例的完全坐标(full coordinates). 因此首先按列族排序,然后在每个列族内按
限定符排序,然后按时间戳,最后按类型 (type) 排序。
另一类访问器提供更加面向列的(column-oriented) 访问:
List<Cell> getColumnCells(byte[] family, byte[] qualifier)
Cell getColumnLatestCell(byte[] family, byte[] qualifier)
Cell getColumnLatestCell(byte[] family, int foffset, int flength, byte[] qualifier, int qoffset, int qlength)
boolean containsColumn(byte[] family, byte[] qualifier)
boolean containsColumn(byte[] family, int foffset, int flength, byte[] qualifier, int qoffset, int qlength)
boolean containsEmptyColumn(byte[] family, byte[] qualifier)
boolean containsEmptyColumn(byte[] family, int foffset, int flength, byte[] qualifier, int qoffset, int qlength)
boolean containsNonEmptyColumn(byte[] family, byte[] qualifier)
boolean containsNonEmptyColumn(byte[] family, int foffset, int flength, byte[] qualifier, int qoffset, int qlength)
通过 getColumnCells() 方法可以请求某个特定列的多个值,返回值版本的最大数量有之前调用 get() 方法时配置的 Get 实例界定,默认为 1.换句话说,
返回的列表可能包含 0 (给定 row 上的列没有值)或 1 个项目,意为值的最新版本。如果指定了返回大于默认的 1 个版本的值,列表可能包含任意数量的项目,
最多为指定的最大值。
getColumnLatestCell() 方法返回指定列的最新版本 cell, 但与 getValue() 相反,它不返回值的原始字节数组,而是完全的 Cell 实例。
containsColumn() 是检查某个特定的列内是否有 cell 返回的的便捷方法。
第三类访问返回数据的方法,是面向 map 的方法(map-oriented):
NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> getMap()
NavigableMap<byte[], NavigableMap<byte[], byte[]>> getNoVersionMap()
NavigableMap<byte[], byte[]> getFamilyMap(byte[] family)
最通用的方法时 getMap(), 在一个 Java Map 类实例中返回整个结果集,可以迭代访问所有的值。 getNoVersionMap() 做的是同样的事,只是仅仅包含每个列
最新版本的 cell. 最后,getFamilyMap() 方法可以只选择某个给定列族的数据,但包含所有版本。
不论使用 Result 的哪种访问方法来适应用户的需求,数据已经从服务器上通过网络传输到了客户端进程,因此不会导致性能或资源的负面影响。
最后,还有一些无法归为以上类别中的方法,参考 API javadoc 了解详情。
Get 列表 (List of Gets)
另一个与 put() 调用相似的 get() 方法调用是用户可以用一次请求获取多行数据,它允许用户快速高效地从远程服务器获取相关联的,或者完全随机的多
行数据。
NOTE:
-------------------------------------------------------------------------------------------------------------------------------------
实际上,请求有可能被发往多个不同的服务器,但这部分逻辑已经被封装起来。因此对于客户端代码来说,还是表现为一次请求。
方法签名:
Result[] get(List<Get> gets) throws IOException
用户需要创建一个列表,并把准备好的 Get 实例添加到列表中,然后将列表传给 get(), 返回一个与 Get 列表数量相同的 Result 数组。
示例:
// Example of retrieving data from HBase using lists of Get instances
// Prepare commonly used byte arrays.
byte[] cf1 = Bytes.toBytes("colfam1");
byte[] qf1 = Bytes.toBytes("qual1");
byte[] qf2 = Bytes.toBytes("qual2");
byte[] row1 = Bytes.toBytes("row1");
byte[] row2 = Bytes.toBytes("row2");
// Create a list that holds the Get instances.
List<Get> gets = new ArrayList<Get>();
// Add the Get instances to the list.
Get get1 = new Get(row1);
get1.addColumn(cf1, qf1);
gets.add(get1);
Get get2 = new Get(row2);
get2.addColumn(cf1, qf1);
gets.add(get2);
Get get3 = new Get(row2);
get3.addColumn(cf1, qf2);
gets.add(get3);
// Retrieve rows with selected columns from HBase.
Result[] results = table.get(gets);
System.out.println("First iteration...");
// Iterate over results and check what values are available.
for (Result result : results) {
String row = Bytes.toString(result.getRow());
System.out.print("Row: " + row + " ");
byte[] val = null;
if (result.containsColumn(cf1, qf1)) {
val = result.getValue(cf1, qf1);
System.out.println("Value: " + Bytes.toString(val));
}
if (result.containsColumn(cf1, qf2)) {
val = result.getValue(cf1, qf2);
System.out.println("Value: " + Bytes.toString(val));
}
}
System.out.println("Second iteration...");
// Iterate over results again, printing out all values.
for (Result result : results) {
// Two different ways to access the cell data.
for (Cell cell : result.listCells()) {
System.out.println(
"Row: " + Bytes.toString(
cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())
+
" Value: " + Bytes.toString(CellUtil.cloneValue(cell)));
}
}
System.out.println("Third iteration...");
for (Result result : results) {
System.out.println(result);
}
运行代码,将看到显示类似如下的输出:
First iteration...
Row: row1 Value: val1
Row: row2 Value: val2
Row: row2 Value: val3
Second iteration...
Row: row1 Value: val1
Row: row2 Value: val2
Row: row2 Value: val3
Third iteration...
keyvalues={row1/colfam1:qual1/1426678215864/Put/vlen=4/seqid=0}
keyvalues={row2/colfam1:qual1/1426678215864/Put/vlen=4/seqid=0}
keyvalues={row2/colfam1:qual2/1426678215864/Put/vlen=4/seqid=0}
两次遍历返回了同样的值,说明从服务器端得到结果之后,用户可以有多种方式访问结果。
Get 列表 get() 调用返回异常的方法与 Put 列表 put() 调用返回异常不同,get() 方法要么返回与给定的 Get 列表大小相同的 Result 数组,要么抛出
异常。下面示例展示了这种行为:
// Example trying to read an erroneous column family
List<Get> gets = new ArrayList<Get>();
// Add the Get instances to the list.
Get get1 = new Get(row1);
get1.addColumn(cf1, qf1);
gets.add(get1);
Get get2 = new Get(row2);
get2.addColumn(cf1, qf1);
gets.add(get2);
Get get3 = new Get(row2);
get3.addColumn(cf1, qf2);
gets.add(get3);
Get get4 = new Get(row2);
// Add the bogus column family get.
get4.addColumn(Bytes.toBytes("BOGUS"), qf2);
gets.add(get4);
// An exception is thrown and the process is aborted.
Result[] results = table.get(gets);
// This line will never reached!
System.out.println("Result count: " + results.length);
执行这个例子会导致整个 get() 操作终止,程序会抛出类似下面这样的异常,并且没有返回值:
org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException:
Failed 1 action: NoSuchColumnFamilyException: 1 time,
servers with issues: 10.0.0.57:51640,
Exception in thread "main" \
org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException:
\
Failed 1 action: \
org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException:
\
Column family BOGUS does not exist in region \
testtable,,1426678215640.de657eebc8e3422376e918ed77fc33ba. \
in table 'testtable', {NAME => 'colfam1', ...}
at org.apache.hadoop.hbase.regionserver.HRegion.checkFamily(...)
at org.apache.hadoop.hbase.regionserver.HRegion.get(...)
...
对于批量操作中的局部错误,有一种更精细的处理方法。即使用 batch() 方法。
获取多行Scan
Scan对象可以返回满足给定条件的多行数据。 如果希望获取所有的行,直接初始化一个Scan对象即可。 如果希望限制扫描的行范围,可以使用以下方法:
如果希望获取指定列族的所有列,可使用 addFamily 方法来添加所有希望获取的列族
如果希望获取指定列,使用 addColumn 方法来添加所有列
通过 setTimeRange 方法设定获取列的时间范围
通过 setTimestamp 方法指定具体的时间戳,只返回该时间戳的数据
通过 setMaxVersions 方法设定最大返回的版本数
通过 setBatch 方法设定返回数据的最大行数
通过 setFilter 方法为Scan对象添加过滤器,过滤器详解请参见:http://blog.csdn.net/u010967382/article/details/37653177
Scan的结果数据是可以缓存在内存中的,可以通过 getCaching ()方法来查看当前设定的缓存条数,也可以通过 setCaching (int caching)来设定缓存在内存中的行数,缓存得越多,以后查询结果越快,同时也消耗更多内存。此外, 通过setCacheBlocks 方法设置是否缓存Scan的结果数据块,默认为true
我们可以通过 setMaxResultSize(long)方法来设定Scan返回的结果行数。
下面是官网文档中的一个入门示例:假设表有几行键值为 “row1”, “row2”, “row3”,还有一些行有键值 “abc1”, “abc2”, 和 “abc3”,目标是返回"row"打头的行:
HTable htable = ... // instantiate HTable
Scan scan = new Scan();
scan.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("attr"));
scan.setStartRow( Bytes.toBytes("row")); // start key is inclusive
scan.setStopRow( Bytes.toBytes("row" + (char)0)); // stop key is exclusive
ResultScanner rs = htable.getScanner(scan);
try {
for (Result r = rs.next(); r != null; r = rs.next()) {
// process result...
} finally {
rs.close(); // always close the ResultScanner!
}
常用构造函数
(1)创建扫描所有行的Scan
Scan()
(2)创建Scan,从指定行开始扫描 ,
Scan(byte[] startRow)
参数: startRow 行键
注意 :如果指定行不存在,从下一个最近的行开始
(3)创建Scan,指定起止行
Scan(byte[] startRow, byte[] stopRow)
参数: startRow起始行, stopRow终止行
注意 : startRow <= 结果集 < stopRow
(4)创建Scan,指定起始行和过滤器
Scan(byte[] startRow, Filter filter)
参数: startRow 起始行, filter 过滤器
注意:过滤器的功能和构造参见http://blog.csdn.net/u010967382/article/details/37653177
常用方法
Scan setStartRow (byte[] startRow) 设置Scan的开始行, 默认 结果集 包含 该行。 如果希望结果集不包含该行,可以在行键末尾加上0。
Scan setStopRow (byte[] stopRow) 设置Scan的结束行, 默认 结果集 不包含该行。 如果希望结果集包含该行,可以在行键末尾加上0。
Scan setTimeRange (long minStamp, long maxStamp) 扫描指定 时间范围 的数据
Scan setTimeStamp (long timestamp) 扫描指定 时间 的数据
Scan addColumn (byte[] family, byte[] qualifier) 指定扫描的列
Scan addFamily (byte[] family) 指定扫描的列族
Scan setFilter (Filter filter) 为Scan设置过滤器
Scan setReversed (boolean reversed) 设置Scan的扫描顺序,默认是正向扫描(false),可以设置为逆向扫描(true)。注意:该方法0.98版本以后才可用!!
Scan setMaxVersions () 获取所有版本的数据
Scan setMaxVersions (int maxVersions) 设置获取的最大版本数
void setCaching (int caching) 设定缓存在内存中的行数,缓存得越多,以后查询结果越快,同时也消耗更多内存
void setRaw (boolean raw) 激活或者禁用raw模式。如果raw模式被激活,Scan将返回 所有已经被打上删除标记但尚未被真正删除 的数据。该功能仅用于激活了KEEP_DELETED_ROWS的列族,即列族开启了 hcd.setKeepDeletedCells(true)
。Scan激活raw模式后,就不能指定任意的列,否则会报错
Enable/disable “raw” mode for this scan. If “raw” is enabled the scan will return all delete marker and deleted rows that have not been collected, yet. This is mostly useful for Scan on column families that have KEEP_DELETED_ROWS enabled. It is an error to specify any column when “raw” is set.
hcd.setKeepDeletedCells(true);
注意:
HBase对列族、列名大小写敏感