LindormTable を使用すると、データの書き込み方法を変更することなく、既存の HBase テーブルを SQL でクエリできます。カラム修飾子を型付き SQL カラムにマップし、SELECT クエリを実行したり、セカンダリインデックスおよび検索インデックスを作成したりできます。
前提条件
開始する前に、以下の条件を満たしていることを確認してください。
LindormTable バージョン 2.6.4 以降。バージョンの確認またはアップグレードについては、「LindormTable のリリースノート」および「Lindorm インスタンスのマイナーエンジンバージョンをスペックアップする」をご参照ください。
カラムマッピングの仕組み
HBase テーブルはスキーマレスです。カラムには生のバイト列(VARBINARY)が格納され、カラム名は動的です。LindormTable のカラムマッピング機能はこのギャップを埋めます:各修飾子の書き込み時に使用される Java シリアル化型を宣言すると、Lindorm SQL がバイト列をデコードし、カラムを型付き SQL カラムとして公開します。これにより、WHERE フィルター、セカンダリインデックス、および HBase データに対する検索インデックスが可能になります。
動的カラムの詳細については、「動的カラム」をご参照ください。
カラムマッピング構文
ALTER TABLE を使用して、カラムマッピングを追加または削除します。
-- マッピングを追加
ALTER TABLE <table_name> MAP DYNAMIC COLUMN [<family>:]<qualifier> <hbase_type>;
-- 1 つ以上のマッピングを削除
ALTER TABLE <table_name> UNMAP DYNAMIC COLUMN [<family>:]<qualifier> [, ...];サポートされる hbase_type の値
| 型 | Java 型 | 関数の作成 | 使用タイミング |
|---|---|---|---|
| HLONG | java.lang.Long | Bytes.toBytes(long) | Java long |
| HINTEGER | java.lang.Integer | Bytes.toBytes(int) | Java int |
| HSHORT | java.lang.Short | Bytes.toBytes(short) | Java short |
| HFLOAT | java.lang.Float | Bytes.toBytes(float) | Java float |
| HDOUBLE | java.lang.Double | Bytes.toBytes(double) | Java double |
| HSTRING | java.lang.String | Bytes.toBytes(String) — UTF-8 | Java String |
| HBOOLEAN | java.lang.Boolean | Bytes.toBytes(boolean) | Java boolean |
マッピング型は、書き込み時に使用された Java シリアル化メソッドと完全に一致させる必要があります。不一致があると、Lindorm SQL が誤ったバイト列を読み取り、不正な結果を返す可能性があります。詳しくは、下記の「よくあるミス」をご参照ください。
使用上の注意点
マッピングを追加すると、対象カラムの型が宣言されます。ただし、そのカラムに既にデータが存在する必要はありません。
行キーのマッピングは LindormTable 2.5.1 以降でサポートされています。行キー識別子はバックティックで囲んでください:
ROW。Java 以外の言語では、
toBytesメソッドをorg.apache.hadoop.hbase.util.Bytesから使用してください。文字列は常に UTF-8 でエンコードされます。
よくあるミス
マッピング型と書き込みパスが一致しない
これは最も重大な正確性リスクです。f:age カラムが Bytes.toBytes(int) で書き込まれている場合、マッピングは HINTEGER とする必要があります。誤って HSTRING としてマッピングすると、Lindorm SQL は 4 バイトの整数データに対して Bytes.toString() を呼び出し、無意味な出力を返します。
正しいマッピングの例を以下に示します。
int age = 25;
put.addColumn(Bytes.toBytes("f"), Bytes.toBytes("age"), Bytes.toBytes(age));
// HINTEGER としてマッピング
String age2 = "25";
put.addColumn(Bytes.toBytes("f"), Bytes.toBytes("age2"), Bytes.toBytes(age2));
// HSTRING としてマッピングこれらの混同は、クエリ結果が不正になる最も一般的な原因です。
サンプルデータの準備
以下の手順では、次の HBase テーブルおよびデータを使用します。すでに HBase テーブルをお持ちの場合は、「カラム修飾子のマッピング」に進んでください。
サンプルでは、カラムファミリー f1 を持つテーブル dt を作成し、ApsaraDB for HBase Java API を使用して 1 行のデータを書き込みます。HBase Shell を使用する場合は、「Lindorm Shell を使用した LindormTable への接続」をご参照ください。
// カラムファミリー f1 を持つテーブル dt を作成
try (Admin admin = connection.getAdmin()) {
HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("dt"));
htd.addFamily(new HColumnDescriptor(Bytes.toBytes("f1")));
admin.createTable(htd);
}
// 1 行を書き込み
try (Table table = connection.getTable(TableName.valueOf("dt"))) {
byte[] rowkey = Bytes.toBytes("row1");
byte[] family = Bytes.toBytes("f1");
Put put = new Put(rowkey);
String name = "Some one";
put.addColumn(family, Bytes.toBytes("name"), Bytes.toBytes(name)); // HSTRING
int age = 25;
put.addColumn(family, Bytes.toBytes("age"), Bytes.toBytes(age)); // HINTEGER
long timestamp = 1656675491000L;
put.addColumn(family, Bytes.toBytes("time"), Bytes.toBytes(timestamp)); // HLONG
short buycode = 123;
put.addColumn(family, Bytes.toBytes("buycode"), Bytes.toBytes(buycode)); // HSHORT
float price = 12.3f;
put.addColumn(family, Bytes.toBytes("price"), Bytes.toBytes(price)); // HFLOAT
double price2 = 12.33333;
put.addColumn(family, Bytes.toBytes("price2"), Bytes.toBytes(price2)); // HDOUBLE
boolean isMale = true;
put.addColumn(family, Bytes.toBytes("isMale"), Bytes.toBytes(isMale)); // HBOOLEAN
table.put(put);
}カラム修飾子のマッピング
Lindorm-cli を使用して LindormTable に接続します。手順については、「Lindorm-cli を使用した LindormTable への接続および利用」をご参照ください。
ApsaraDB for HBase Performance-enhanced Edition の HBase テーブルにアクセスする場合、Java API の URL 形式を
jdbc:lindorm:table:url=http://<API URL for Java>に変更し、ポートを 30020 から 30060 に変更してください。たとえば、ld-bp1ietqp4fby3****-proxy-hbaseue.hbaseue.rds.aliyuncs.com:30020はjdbc:lindorm:table:url=http://ld-bp1ietqp4fby3****-proxy-hbaseue.hbaseue.rds.aliyuncs.com:30060に変更します。行キーおよびすべての修飾子を対応する Lindorm SQL 型にマップします。
ALTER TABLE dt MAP DYNAMIC COLUMN `ROW` HSTRING, f1:name HSTRING, f1:age HINTEGER, f1:time HLONG, f1:buycode HSHORT, f1:price HFLOAT, f1:price2 HDOUBLE, f1:isMale HBOOLEAN;DESCRIBE コマンドを実行してマッピングを確認します。
DESCRIBE dt;DESCRIBE 構文の詳細については、「DESCRIBE/SHOW/USE」をご参照ください。
テーブルをクエリします。
SELECT * FROM dt LIMIT 1; SELECT * FROM dt WHERE f1:isMale=true LIMIT 1; SELECT * FROM dt WHERE f1:name='Some one' LIMIT 1; SELECT * FROM dt WHERE f1:time>1656675490000 AND f1:time<1656675492000 LIMIT 1;
インデックスの作成(任意)
インデックスを追加するとクエリパフォーマンスが向上しますが、追加のストレージが必要になります。クエリパターンに応じてインデックスの種類を選択してください。
| インデックスの種類 | 推奨用途 | トレードオフ |
|---|---|---|
| セカンダリインデックス | 標準的な書き込み量におけるプライマリキー以外のカラムに対するクエリ | 読み取り速度の向上、ストレージの増加、書き込み時のわずかなオーバーヘッド |
| 検索インデックス | 全文検索または複雑な多条件クエリ | 柔軟なクエリ、より高いストレージコスト |
セカンダリインデックスの作成
テーブルの MUTABILITY 属性を設定します。
カスタムタイムスタンプでデータを書き込む場合は、
MUTABLE_ALLを使用し、MUTABLE_LATESTは使用しないでください。ALTER TABLE dt SET 'MUTABILITY' = 'MUTABLE_LATEST';インデックスを作成します。
CREATE INDEX idx ON dt(f1:age) WITH (INDEX_COVERED_TYPE ='COVERED_DYNAMIC_COLUMNS');`async` パラメーターを指定し、かつ LindormTable のバージョンが 2.6.3 より前の場合、既存データをインデックステーブルにビルドします。
BUILD INDEX idx ON dt;この手順は、
asyncを使用しなかった場合にスキップしてください。インデックスを確認します。
SHOW INDEX FROM dt;期待される出力:
+---------------+-------------+-------------+--------------+------------------+---------------+-----------------+----------------+-------------+ | TABLE_SCHEMA | DATA_TABLE | INDEX_NAME | INDEX_STATE | INDEX_PROGRESS | INDEX_TYPE | INDEX_COVERED | INDEX_COLUMN | INDEX_TTL | +---------------+-------------+-------------+--------------+------------------+---------------+-----------------+----------------+-------------+ | default | dt | idx | ACTIVE | 100% | SECONDARY | TRUE | f1:age,ROW | | +---------------+-------------+-------------+--------------+------------------+---------------+-----------------+----------------+-------------+INDEX_STATEがACTIVEのとき、インデックスは利用可能になります。INDEX_PROGRESSはビルドの進行状況を示します。(任意)クエリでセカンダリインデックスが使用されているかを確認します。
EXPLAIN SELECT * FROM dt WHERE f1:age=23 LIMIT 1;詳細については、「CREATE INDEX」および「セカンダリインデックス」をご参照ください。
検索インデックスの作成
検索インデックスを作成します。
CREATE INDEX search_idx USING SEARCH ON dt(f1:age, f1:name);HBase テーブル上で検索インデックスを作成する前に、以下の点にご注意ください。
検索インデックスに含めるすべてのカラムについて、あらかじめカラムマッピングが定義済みである必要があります。
カラムのデータ型は、「カラムマッピング構文」でリストされているサポート対象のマッピング型と一致している必要があります。
検索インデックスを作成した後は、カラムマッピングを削除しないでください。削除すると、クエリ結果が不正になる可能性があります。
カスタムタイムスタンプでデータを書き込む場合は、インデックス作成前に
MUTABILITYをMUTABLE_ALLに設定してください。
インデックスのステータスを確認します。
SHOW INDEX FROM dt;期待される出力:
+--------------+------------+------------+-------------+----------------+------------+---------------+----------------+-----------+-------------------+ | TABLE_SCHEMA | DATA_TABLE | INDEX_NAME | INDEX_STATE | INDEX_PROGRESS | INDEX_TYPE | INDEX_COVERED | INDEX_COLUMN | INDEX_TTL | INDEX_DESCRIPTION | +--------------+------------+------------+-------------+----------------+------------+---------------+----------------+-----------+-------------------+ | default | dt | idx | ACTIVE | DONE | SECONDARY | DYNAMIC | f1:age,ROW | | | | default | dt | search_idx | BUILDING | N/A | SEARCH | NA | f1:age,f1:name | 0 | | +--------------+------------+------------+-------------+----------------+------------+---------------+----------------+-----------+-------------------+
カラムマッピングの削除(任意)
単一のマッピングを削除する場合:
ALTER TABLE dt UNMAP DYNAMIC COLUMN f1:isMale;1 つのステートメントで複数のマッピングを削除する場合:
ALTER TABLE dt UNMAP DYNAMIC COLUMN f1:price, f1:price2;