Filter
ScanやGetには、Filterを指定することができます。Filterを使用することで、よりきめ細かく取得するデータを指定できます。
ScanやGetに、以下のような設定することができます。
// ColumnPrefixFilterの指定
get.setFilter(new ColumnPrefixFilter(Bytes.toBytes("col")));
// PrefixFilterの指定
scan.setFilter(new PrefixFilter(Bytes.toBytes("row")));
Filterは、基本的なものはもともと用意されています。また、カスタムFilterも作成することができます。
Increment
次は、Incrementについて説明します。Incrementを用いることで簡単にカウンターを作ることが可能です。
Incrementの例は以下のようになります。
byte[] row = Bytes.toBytes("row");
byte[] fam = Bytes.toBytes("fam");
byte[] col = Bytes.toBytes("col");
// インクリメント
long counter = table.incrementColumnValue(row, fam, col, 1L);
// デクリメント
counter = table.incrementColumnValue(row, fam, col, -1L);
HTableのincrementColumnValueによって、RowKeyが"row"でColumnFamilyが"fam"、Columnが"col"のValueをインクリメントしてその後にデクリメントしている例です。
incrementColumnValueの戻り値としては、加算された後のValueが返ってきます。
また、以下のように同じRow内のColumnであれば一度に行うことができます。
byte[] row = Bytes.toBytes("row");
byte[] fam = Bytes.toBytes("fam");
byte[] col1 = Bytes.toBytes("col1");
byte[] col2 = Bytes.toBytes("col2");
Increment increment = new Increment(row);
increment.addColumn(fam, col1, 1L);
increment.addColumn(fam, col2, -1L);
// まとめてインクリメント・デクリメント
Result result = table.increment(increment);
ただし、この処理は読み込みに対してはアトミックではありません。一部は更新済みで、一部は更新されていない状態が起こりうるので、注意が必要です。
incrementの戻り値としては、加算後のResultオブジェクトが返ってきます。
CAS
CASの例は以下にようになります。
byte[] row = Bytes.toBytes("row");
byte[] fam = Bytes.toBytes("fam");
byte[] col = Bytes.toBytes("col");
byte[] expect = Bytes.toBytes("expect");
byte[] update = Bytes.toBytes("update");
// 更新後のPut
Put put = new Put(row);
put.add(fam, col, update);
// 更新が成功すればtrueが返ってくる
boolean success = table.checkAndPut(row, fam, col, expect, put);
RowKeyが"row"で、ColumnFamilyが"fam"、Columnが"col"のValueが"expect"であれば、"update"に変更するという例です。
更新が成功した場合は、checkAndPutの戻り値としてtrueが返ってきます。また、Delete版も用意されています。
byte[] row = Bytes.toBytes("row");
byte[] fam = Bytes.toBytes("fam");
byte[] col = Bytes.toBytes("col");
byte[] expect = Bytes.toBytes("val1");
// 削除
Delete delete = new Delete(row);
delete.deleteColumns(fam, col);
// 削除が成功すればtrueが返ってくる
boolean success = table.checkAndDelete(row, fam, col, expect, delete);
RowKeyが"row"で、ColumnFamilyが"fam"、Columnが"col"のValueが"expect"であれば削除するという例です。
CASを使用することで、ロックを持つ必要がなくなるため、クライアント側の処理をシンプルにすることができます。
HTablePool
HTableオブジェクトは生成コストが高く、さらにスレッドセーフには作られていません。そこで、HTablePoolというHTableをプーリングする機構が用意されています。
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "localhost");
HTablePool hTablePool = new HTablePool(conf, Integer.MAX_VALUE);
// HTableじゃなくてHTableInterface
HTableInterface table = hTablePool.getTable("tbl");
// tableをcloseするとpoolに戻される
table.close();
// 使い終わったらcloseする
hTablePool.close();
HTablePoolのgetTableで返ってくるのは、HTableではなくHTableInterfaceであることに注意ですが、基本的なメソッドは同じなのであまり意識する必要はありません。
