3.3 数据模型的操作

HBase对数据模型的4个主要操作包括Get、Put、Scan和Delete。通过HTable实例进行操作,用户可以完成向HBase存储和检索数据,以及删除无效数据之类的操作。
所有修改数据的操作都保证行级别的原子性,多个客户端或线程对同一行的读写操作都不会影响该行数据的原子性,要么读到最新的数据,要么等待系统允许写入该行的修改。
创建HTable实例是有代价的。每个实例都需要扫描.META.表,以检查该表是否存在,是否可用。此外还有一些其他操作,这些检查和操作导致实例调用非常耗时。因此,推荐用户只创建一次HTable实例,而且是每个线程创建一个,如果用户需要使用多个HTable实例,应考虑使用HTablePool类,它可以复用多个HTable实例。

3.3.1 读Get

Get操作是指从客户端API中获取已存储数据的方法。HTable类中提供了get()方法,同时还有与之对应的Get类,Get操作返回一行或多行数据。
get()方法默认一次取回该行全部列的数据,我们可以限定只取回某个列族对应的列的数据,或者进一步限定只取回某些列的数据,之前也说过HBase的列的数据是多版本的,我们可以限定取回该列全部版本的数据或者限定只取回最新的一个或几个版本的数据。
当用户使用get()方法获取数据时,HBase返回的结果包含所有匹配的单元格数据,这些数据将被封装在一个Result实例中返回给用户。用Result类提供的方法,可以从服务器端获取匹配指定行的特定返回值,这些值包括列族、列限定符和时间戳等。

3.3.2 写Put

Put操作要么向表增加新行(如果Key是新的)或更新行(如果Key已经存在)。可以一次向表中插入一行数据,也可以一次操作一个集合,同时向表中写入多行数据。如果要频繁修改某些行的数据,用户应该创建一个RowLock实例来防止其他用户对该行数据进行修改。
Put操作每次都会发起一次到服务器的RPC操作,如果有大量的数据要写入表中,就会有数千次RPC操作,这样效率很低。HBase客户端有一个缓冲区,负责将数据批量地仅通过一次RPC操作发送到服务端,这样可大大提高写入性能,默认客户端写缓冲区是关闭的,需要显式打开该选项。
当将一个Put集合提交到服务端的时候,可能会出现部分成功部分失败的情况,失败的数据会被保存到缓存区中进行重试。
HBase还提供了一个compare-and-set操作,这个操作先进行检查,条件满足后再执行,这个操作对于行是原子性的。
HBase没有Update操作,是通过Put操作完成对数据的修改的。

3.3.3 扫描Scan

Scan操作允许多行特定属性迭代,其使用与get()方法非常类似。工作方式类似于迭代器,可以指定startRow参数来定义扫描读取HBase表的起始行键,同时可选stopRow参数来限定读取到何处停止。
在创建Scan实例之后,用户可以增加更多的限定条件,没有参数将扫描整个表,包括所有列族以及所有列,可以用多种方法限定读取的数据。
扫描操作执行后将得到执行结果,此结果被封装在一个ResultScanner实例中。下面是一个基于HTable表实例的示例:假设表有几个行键值为“row1”、“row2”、“row3”,还有一些行键值为“abc1”、“abc2”和“abc3”。下面的代码展示了startRow和stopRow可以应用到一个Scan实例,以返回“row”开头的行。

Configuration conf = HBaseConfiguration.create();
HTable htable = new HTable(conf,”table1”);        // 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!
}
3.3.4 删除Delete

Delete用于从表中删除数据。HTable除了提供删除方法delete()外,还有一个与之对应的类Delete,用户可以通过多种方法限定要删除的列。
与关系型数据库的Delete操作不同,HBase的Delete操作可以指定删除某个列族或者某个列,或者指定某个时间戳,删除比这个时间早的数据。
HBase的Delete操作并不是真正地从磁盘删除数据。而是通过创建墓碑(tombstones)标志进行处理。这些墓碑标记的值和小于该时间版本的单元格在大合并(major compact)时被清除。关于这一点可以参考9.2.4节,该节详细阐述了大合并操作时HBase发生的行为。