O LindormTable permite executar consultas SQL diretamente em tabelas do HBase criadas com o HBase Shell ou a API do ApsaraDB for HBase para Java, sem necessidade de migração de dados. O mapeamento de colunas conecta o modelo de armazenamento sem esquema do HBase ao Lindorm SQL, permitindo filtrar, indexar e consultar seus dados existentes com sintaxe SQL padrão.
Pré-requisitos
A versão do mecanismo de tabela ampla deve ser 2.6.4 ou posterior. Para visualizar ou atualizar a versão atual, consulte LindormTable release notes e Upgrade the minor engine version of a Lindorm instance.
Informações de fundo
O mecanismo de tabela ampla do Lindorm acessa diretamente tabelas de dados criadas pelo Lindorm Shell ou pela API Java do HBase. No entanto, como o HBase não possui esquema, suas colunas são tratadas como colunas dinâmicas do tipo VARBINARY (Byte). Para mais detalhes sobre colunas dinâmicas, consulte Dynamic columns. Para utilizar o Lindorm SQL em colunas gravadas pela API do HBase e aproveitar tipos de dados avançados e índices secundários, o ApsaraDB for HBase oferece mapeamento de colunas do HBase e tipos compatíveis com o HBase.
Sintaxe
No Lindorm SQL, é possível adicionar mapeamentos a qualificadores em famílias de colunas personalizadas de uma tabela do HBase para facilitar consultas SQL.
A sintaxe para adicionar e remover mapeamentos é a seguinte:
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
A tabela a seguir descreve os tipos de dados de mapeamento que hbase_type pode especificar:
|
Tipo de dado |
Tipo Java correspondente |
Descrição |
|
HLONG |
java.lang.Long |
Grava uma coluna do HBase usando o método Bytes.toBytes(long). |
|
HINTEGER |
java.lang.Integer |
Grava uma coluna do HBase usando o método Bytes.toBytes(int). |
|
HSHORT |
java.lang.Short |
Grava uma coluna do HBase usando o método Bytes.toBytes(short). |
|
HFLOAT |
java.lang.Float |
Grava uma coluna do HBase usando o método Bytes.toBytes(float). |
|
HDOUBLE |
java.lang.Double |
Grava uma coluna do HBase usando o método Bytes.toBytes(double). |
|
HSTRING |
java.lang.String |
Grava uma coluna do HBase usando o método Bytes.toBytes(String). |
|
HBOOLEAN |
java.lang.Boolean |
Grava uma coluna do HBase usando o método Bytes.toBytes(boolean). |
A versão 2.5.1 ou posterior do mecanismo de tabela ampla suporta mapeamento para Rowkey. O método de mapeamento é o mesmo utilizado para outros qualificadores. O objeto de mapeamento deve ser ROW e a palavra-chave ROW deve estar entre crases (``).
Caso utilize outra linguagem, consulte o método toBytes na classe Java org.apache.hadoop.hbase.util.Bytes para codificar os dados antes da gravação.
O método Bytes.toBytes(String) em Java utiliza codificação UTF-8. Ao usar toBytes para converter String em Bytes em outra linguagem, a codificação UTF-8 também é obrigatória.
Preparação de dados
O exemplo a seguir utiliza a API Java do HBase. Para mais informações, consulte Use ApsaraDB for HBase API for Java to develop applications.
Para outros métodos de criação de tabelas e gravação de dados, consulte Connect to LindormTable with Lindorm Shell.
// Create the HBase sample table named "dt" with column family "f1"
try (Admin admin = connection.getAdmin()) {
HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("dt"));
htd.addFamily(new HColumnDescriptor(Bytes.toBytes("f1")));
admin.createTable(htd);
}
// Write data
try (Table table = connection.getTable(TableName.valueOf("dt"))) {
byte[] rowkey = Bytes.toBytes("row1");
byte[] family = Bytes.toBytes("f1");
Put put = new Put(rowkey);
// Write a String value, column name "name"
String name = "Some one";
put.addColumn(family, Bytes.toBytes("name"), Bytes.toBytes(name));
// Write an Int value, column name "age"
int age = 25;
put.addColumn(family, Bytes.toBytes("age"), Bytes.toBytes(age));
// Write a Long value, column name "time"
long timestamp = 1656675491000L;
put.addColumn(family, Bytes.toBytes("time"), Bytes.toBytes(timestamp));
// Write a Short value, column name "buycode"
short buycode = 123;
put.addColumn(family, Bytes.toBytes("buycode"), Bytes.toBytes(buycode));
// Write a Float value, column name "price"
float price = 12.3f;
put.addColumn(family, Bytes.toBytes("price"), Bytes.toBytes(price));
// Write a Double value, column name "price2"
double price2 = 12.33333;
put.addColumn(family, Bytes.toBytes("price2"), Bytes.toBytes(price2));
// Write a Boolean value, column name "isMale"
boolean isMale = true;
put.addColumn(family, Bytes.toBytes("isMale"), Bytes.toBytes(isMale));
// Write a null value. For all types, writing null is expressed as:
//put.addColumn(family, qualifier, null);
table.put(put);
}
Procedimento
O exemplo abaixo utiliza a tabela de amostra dt para demonstrar como acessar uma tabela do HBase por meio de SQL.
-
Conecte-se ao mecanismo de tabela ampla usando o Lindorm-cli. Para mais informações, consulte Connect to and use the wide table engine with Lindorm-cli.
NotaSe você usar SQL para acessar uma tabela do HBase no ApsaraDB for HBase Enhanced Edition, construa o endereço obtido no console no formato
jdbc:lindorm:table:url=http://Java API address obtained in the console. Altere a porta de 30020 para 30060.Por exemplo, se o endereço da string de conexão obtido no console for
ld-bp1ietqp4fby3****-proxy-hbaseue.hbaseue.rds.aliyuncs.com:30020, o endereço da string de conexão convertido serájdbc:lindorm:table:url=http://ld-bp1ietqp4fby3****-proxy-hbaseue.hbaseue.rds.aliyuncs.com:30060. -
Use a instrução
ALTER TABLEpara adicionar mapeamentos de colunas aos dados gravados na tabela 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;NotaAdicionar um mapeamento de coluna define o tipo de dado da coluna, independentemente de haver dados gravados.
O sistema decodifica o valor original de Bytes com base no esquema. Portanto, use o tipo de dado correto ao mapear para o Lindorm SQL.
No exemplo a seguir, se o tipo de dado da coluna f:age2 for definido como HINTEGER, o sistema chamará o método Bytes.toInt() e retornará um valor original incorreto.
int age = 25; byte[] ageValue = Bytes.toBytes(age); put.addColumn(Bytes.toBytes("f"), Bytes.toBytes("age"), ageValue);// The data type of column f:age is INT, and it is mapped to HINTEGER in Lindorm SQL. String age2 = "25"; byte[] age2Value = Bytes.toBytes(age2); put.addColumn(Bytes.toBytes("f"), Bytes.toBytes("age2"), age2Value);// The data type of column f:age2 is STRING, and it is mapped to HSTRING in Lindorm SQL. -
Use a instrução DESCRIBE para visualizar as relações de mapeamento do esquema atual.
DESCRIBE dt;NotaPara mais informações sobre a sintaxe DESCRIBE TABLE, consulte DESCRIBE/SHOW/USE.
-
Consulte os dados na tabela dt usando uma instrução SQL.
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; -
(Opcional) Crie um índice secundário.
Um índice secundário troca espaço por tempo. Ele melhora a eficiência de consultas em padrões que não usam chave primária, mas ocupa algum espaço de armazenamento. Para mais informações sobre a sintaxe e limites de uso de índices secundários, consulte CREATE INDEX e Secondary indexes.
-
Modifique as propriedades da tabela primária dt.
ALTER TABLE dt SET 'MUTABILITY' = 'MUTABLE_LATEST';NotaSe forem usados timestamps personalizados, defina a propriedade da tabela primária como MUTABLE_ALL.
-
Crie o índice secundário:
CREATE INDEX idx ON dt(f1:age) WITH (INDEX_COVERED_TYPE ='COVERED_DYNAMIC_COLUMNS'); -
Opcional: Se a versão do seu mecanismo de tabela ampla for anterior à 2.6.3 e você usar o parâmetro async (construção assíncrona de índice) ao criar um índice secundário, construa manualmente os dados históricos da tabela primária na tabela de índice. Após a conclusão da construção, será possível consultar os dados históricos usando o índice secundário. Caso o parâmetro async não tenha sido usado durante a criação, pule esta etapa.
BUILD INDEX idx ON dt; -
Visualize o índice.
SHOW INDEX FROM dt;Resultado:
+---------------+----------- -+-------------+--------------+------------------+---------------+-----------------+----------------+-------------+ | 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 | | +---------------+-------------+-------------+--------------+------------------+---------------+-----------------+----------------+-------------+NotaQuando INDEX_STATE no valor de retorno for Active, a construção dos dados estará concluída.
PINDEX_PROGRESS no valor de retorno indica o progresso da construção do índice.
-
Opcional: Use a instrução EXPLAIN para visualizar o plano de execução e verificar se um índice secundário foi utilizado.
EXPLAIN SELECT * FROM dt WHERE f1:age=23 LIMIT 1;
-
-
Opcional: Crie um índice de pesquisa.
-
Crie um índice de pesquisa.
CREATE INDEX search_idx USING SEARCH ON dt(f1:age,f1:name);NotaAo criar um índice de pesquisa em uma tabela do HBase usando SQL, observe os seguintes limites para cada coluna do índice de pesquisa:
Todas as colunas do índice de pesquisa devem estar definidas no mapeamento de colunas.
Os tipos de dados suportados são consistentes com os tipos de dados mapeáveis. Para mais informações, consulte Mapping data types.
Não é possível remover o mapeamento de uma coluna de índice de pesquisa. Caso contrário, os resultados da consulta estarão incorretos.
Se você usar timestamps personalizados para gravar na tabela do HBase e precisar criar um índice de pesquisa, defina a propriedade MUTABILITY da tabela como
MUTABLE_ALL.
-
Verifique se o índice foi criado com sucesso.
SHOW INDEX FROM dt;Resultado:
+--------------+------------+------------+-------------+----------------+------------+---------------+----------------+-----------+-------------------+ | 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 | | +--------------+------------+------------+-------------+----------------+------------+---------------+----------------+-----------+-------------------+
-
-
Opcional: Remova mapeamentos de colunas.
-
Remova um único mapeamento de coluna. Exemplo:
ALTER TABLE dt UNMAP DYNAMIC COLUMN f1:isMale; -
Remova vários mapeamentos de colunas. Exemplo:
ALTER TABLE dt UNMAP DYNAMIC COLUMN f1:price2, f1:price2;
-