全部产品
Search
文档中心

云数据库 HBase:使用SQL访问HBase表

更新时间:Nov 16, 2023

本文介绍如何使用SQL语句访问HBase表。

前提条件

宽表引擎为2.4.3.2及以上版本。如何查看或升级当前版本,请参见宽表引擎版本说明升级小版本

背景信息

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表。

  1. 获取连接地址。

    1. 登录HBase控制台

    2. 集群列表页面,单击目标集群ID,进入集群详情页面。

    3. 在左侧导航栏,选择数据库连接

    4. 获取Java API访问地址

  2. Java API访问地址修改为SQL访问HBase表的连接地址。修改方法如下:

    1. Java API访问地址前添加jdbc:lindorm:table:url=http://前缀。

    2. 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

  3. 通过Lindorm-cli连接并使用宽表引擎。具体操作,请参见通过Lindorm-cli连接并使用宽表引擎

  4. 使用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类型。
  5. 通过DESCRIBE语句查看当前Schema的映射关系。

    DESCRIBE dt;
    说明

    DESCRIBE TABLE语法的详细信息,请参见DESCRIBE/SHOW/USE

  6. 通过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;
  7. 创建二级索引。

    二级索引是一种空间换时间的解决方案,它有利于提升非主键查询模式的查询效率,但需要占用一些存储空间。关于二级索引的语法使用限制,请参见CREATE INDEX二级索引

    1. 修改主表dt的属性。

      ALTER TABLE dt SET 'MUTABILITY' = 'MUTABLE_LATEST';
      说明

      如果使用了自定义时间戳,主表属性需要设置为MUTABLE_ALL

    2. 创建二级索引。

      CREATE INDEX idx ON dt(f1:age) 'INDEX_COVERED_TYPE'='COVERED_DYNAMIC_COLUMNS';
    3. 如果创建二级索引时使用了async参数,您需要手动将主表中的历史数据构建到索引表中。构建完成后,才能通过二级索引查询历史数据。如果创建时没有使用async参数,可跳过此步骤。

      BUILD INDEX idx ON dt;
    4. 查看索引。

      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的值表示索引构建的进度。

    5. 可选:使用EXPLAIN语句查看执行计划,可以查看是否命中二级索引。

      EXPLAIN SELECT * FROM dt WHERE f1:age=23 LIMIT 1;
  8. 可选:删除列映射。

    • 移除一个列映射。示例代码如下:

      ALTER TABLE dt UNMAP DYNAMIC COLUMN f1:isMale;
    • 移除多个列映射。示例代码如下:

      ALTER TABLE dt UNMAP DYNAMIC COLUMN f1:price2, f1:price2;