本文介紹如何使用SQL語句訪問HBase表。
前提條件
背景信息
Lindorm寬表引擎支持直接訪問通過Lindorm Shell或HBase Java API創建的數據表。但由于HBase是Schema-free的,因此HBase中的列會被當做動態列處理,類型為VARBINARY,即Byte。關于動態列的詳細信息,請參見動態列。為了能夠在基于HBase API寫入的列上使用Lindorm SQL,同時使用豐富的數據類型和二級索引,云數據庫HBase提供了HBase列映射功能以及HBase兼容類型。
語法
在Lindorm SQL中,對HBase表中自定義Column Family中的Qualifier添加映射,方便后續使用SQL進行查詢。
添加和移除映射的語法如下:
dynamic_column_mapping_statement := ALTER TABLE table_name MAP DYNAMIC COLUMN
qualifer_definition hbase_type;
dynamic_column_unmapping_statement := ALTER TABLE table_name UNMAP DYNAMIC COLUMN
qualifer_definition_list;
qualifer_definition_list := qualifer_definition
(',' qualifer_definition)*
qualifer_definition := [ family_name ':' ] qualifier_name
hbase_type := HLONG | HINTEGER | HSHORT | HFLOAT |
HDOUBLE | HSTRING | HBOOLEAN
其中,hbase_type可指定的映射數據類型如下表所示:
數據類型 | 對應的Java類型 | 描述 |
HLONG | java.lang.Long | 使用Bytes.toBytes(long)方式寫入HBase的列。 |
HINTEGER | java.lang.Integer | 使用Bytes.toBytes(int)方式寫入HBase的列。 |
HSHORT | java.lang.Short | 使用Bytes.toBytes(short)方式寫入HBase的列。 |
HFLOAT | java.lang.Float | 使用Bytes.toBytes(float)方式寫入HBase的列。 |
HDOUBLE | java.lang.Double | 使用Bytes.toBytes(double)方式寫入HBase的列。 |
HSTRING | java.lang.String | 使用Bytes.toBytes(String)方式寫入HBase的列。 |
HBOOLEAN | java.lang.Boolean | 使用Bytes.toBytes(boolean)方式寫入HBase的列. |
寬表引擎版本2.5.1及以上版本支持對Rowkey的映射,映射方法與其他Qualifier相同。映射對象固定為ROW且ROW關鍵字需要用反引號(``)引用。
如果使用其他語言,您可以參考Java類org.apache.hadoop.hbase.util.Bytes中的toBytes方法對數據進行編碼寫入。
Java中Bytes.toBytes(String)采用UTF-8編碼,其他語言利用toBytes將String轉成Bytes時,也需要使用UTF-8編碼。
數據準備
以HBase Java API為例,具體操作,請參見基于HBase Java API的應用開發。
其他的建表方式及數據寫入方式,請參見通過Lindorm Shell訪問寬表引擎。
//創建名為dt,family名為f1的HBase示例表
try (Admin admin = connection.getAdmin()) {
Table table = connection.getTable(TableName.valueOf("dt"));
HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("dt"));
htd.addFamily(new HColumnDescriptor(Bytes.toBytes("f1")));
admin.createTable(htd);
}
//寫入數據
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
String name = "Some one";
put.addColumn(family, Bytes.toBytes("name"), Bytes.toBytes(name));
//寫入Int類型,列名為age
int age = 25;
put.addColumn(family, Bytes.toBytes("age"), Bytes.toBytes(age));
//寫入Long類型,列名為time
long timestamp = 1656675491000L;
put.addColumn(family, Bytes.toBytes("time"), Bytes.toBytes(timestamp));
//寫入Short類型,列名為buycode
short buycode = 123;
put.addColumn(family, Bytes.toBytes("buycode"), Bytes.toBytes(buycode));
//寫入Float類型,列名為price
float price = 12.3f;
put.addColumn(family, Bytes.toBytes("price"), Bytes.toBytes(price));
//寫入Double類型,列名為price2
double price2 = 12.33333;
put.addColumn(family, Bytes.toBytes("price2"), Bytes.toBytes(price2));
//寫入Boolean類型,列名為isMale
boolean isMale = true;
put.addColumn(family, Bytes.toBytes("isMale"), Bytes.toBytes(isMale));
//寫入null值,所有類型寫入空值null都表達為
//put.addColumn(family, qualifier, null);
table.put(put);
}
操作步驟
以訪問示例表dt為例,介紹如何使用SQL訪問HBase表。
獲取連接地址。
登錄HBase控制臺。
在集群列表頁面,單擊目標集群ID,進入集群詳情頁面。
在左側導航欄,選擇數據庫連接。
獲取Java API訪問地址。
將Java API訪問地址修改為SQL訪問HBase表的連接地址。修改方法如下:
在Java API訪問地址前添加
jdbc:lindorm:table:url=http://
前綴。將Java API訪問地址的端口號由30020修改為30060 。
說明假設在控制臺上獲取的連接地址為
ld-bp1ietqp4fby3****-proxy-hbaseue.hbaseue.rds.aliyuncs.com:30020
,則實際用于SQL訪問HBase表的連接串應是jdbc:lindorm:table:url=http://ld-bp1ietqp4fby3****-proxy-hbaseue.hbaseue.rds.aliyuncs.com:30060
。
通過Lindorm-cli連接并使用寬表引擎。具體操作,請參見通過Lindorm-cli連接并使用寬表引擎。
使用
ALTER TABLE
語句對寫入dt表的數據添加列映射。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;
說明添加列映射是指定列的數據類型,與是否寫入數據無關。
系統會根據Schema從Bytes中反解出原始數值,因此映射到Lindorm SQL時必須使用正確的數據類型。
以下示例中,如果用戶把f:age2列的數據類型寫為HINTEGER,系統調用Bytes.toInt()方法會反解出錯誤的原始值。
int age = 25; byte[] ageValue = Bytes.toBytes(age); put.addColumn(Bytes.toBytes("f"), Bytes.toBytes("age"), ageValue);//f:age列的數據類型為INT,映射到Lindorm SQL為HINTEGER類型。 String age2 = "25"; byte[] age2Value = Bytes.toBytes(age2); put.addColumn(Bytes.toBytes("f"), Bytes.toBytes("age2"), age2Value);//f:age2列的數據類型為STRING,映射到Lindorm SQL為HSTRING類型。
通過DESCRIBE語句查看當前Schema的映射關系。
DESCRIBE dt;
說明DESCRIBE TABLE語法的詳細信息,請參見DESCRIBE/SHOW/USE。
通過SQL語句查詢dt表中的數據。
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;
創建二級索引。
二級索引是一種空間換時間的解決方案,它有利于提升非主鍵查詢模式的查詢效率,但需要占用一些存儲空間。關于二級索引的語法使用限制,請參見CREATE INDEX和二級索引。
修改主表dt的屬性。
ALTER TABLE dt SET 'MUTABILITY' = 'MUTABLE_LATEST';
說明如果使用了自定義時間戳,主表屬性需要設置為MUTABLE_ALL。
創建二級索引。
CREATE INDEX idx ON dt(f1:age) 'INDEX_COVERED_TYPE'='COVERED_DYNAMIC_COLUMNS';
如果創建二級索引時使用了async參數,您需要手動將主表中的歷史數據構建到索引表中。構建完成后,才能通過二級索引查詢歷史數據。如果創建時沒有使用async參數,可跳過此步驟。
BUILD INDEX idx ON dt;
查看索引。
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時,說明數據構建完成。
返回值中PINDEX_PROGRESS的值表示索引構建的進度。
可選:使用EXPLAIN語句查看執行計劃,可以查看是否命中二級索引。
EXPLAIN SELECT * FROM dt WHERE f1:age=23 LIMIT 1;
可選:刪除列映射。
移除一個列映射。示例代碼如下:
ALTER TABLE dt UNMAP DYNAMIC COLUMN f1:isMale;
移除多個列映射。示例代碼如下:
ALTER TABLE dt UNMAP DYNAMIC COLUMN f1:price2, f1:price2;