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であることに注意ですが、基本的なメソッドは同じなのであまり意識する必要はありません。