1. Introdução
Neste codelab, você vai aprender a usar o Cloud Bigtable com o cliente HBase Java.
Você aprenderá como realizar as seguintes tarefas:
- Evitar erros comuns no design de esquema
- Importar dados em um arquivo sequencial
- Consultar dados
Quando terminar, você terá vários mapas que mostram os dados de ônibus da cidade de Nova York. Por exemplo, você vai criar este mapa de calor de viagens de ônibus em Manhattan:

Como você classificaria sua experiência com o uso do Google Cloud Platform?
Como você usará este tutorial?
2. Sobre o conjunto de dados
Você vai analisar um conjunto de dados sobre os ônibus da cidade de Nova York. Há mais de 300 rotas de ônibus e 5.800 veículos seguindo essas rotas. Nosso conjunto de dados é um registro que inclui nome do destino, ID do veículo, latitude, longitude, horário de chegada esperado e horário de chegada programado. O conjunto de dados é composto por snapshots tirados a cada 10 minutos em junho de 2017.
3. Design de esquema
Para conseguir o melhor desempenho do Cloud Bigtable, é preciso ter cuidado ao projetar o esquema. Os dados no Cloud Bigtable são classificados automaticamente em ordem lexicográfica. Portanto, se você projetar bem o esquema, a consulta de dados relacionados será muito eficiente. O Cloud Bigtable permite consultas usando pesquisas pontuais por chave de linha ou verificações de intervalo de linhas que retornam um conjunto contíguo de linhas. No entanto, se o esquema não for bem elaborado, você pode precisar juntar várias pesquisas de linha ou, pior, fazer verificações completas da tabela, que são operações extremamente lentas.
Planejar as consultas
Nossos dados têm várias informações, mas, para este codelab, você vai usar o local e o destino do ônibus.
Com essas informações, você pode executar estas consultas:
- Confira a localização de um único ônibus em uma determinada hora.
- Receba dados de um dia para uma linha de ônibus ou um ônibus específico.
- Encontra todos os ônibus em um retângulo em um mapa.
- Receba os locais atuais de todos os ônibus (se você estiver ingerindo esses dados em tempo real).
Não é possível executar todas essas consultas juntas de maneira ideal. Por exemplo, se você estiver classificando por tempo, não será possível fazer uma verificação com base em um local sem fazer uma verificação completa da tabela. Priorize com base nas consultas que você executa com mais frequência.
Neste codelab, você vai se concentrar em otimizar e executar o seguinte conjunto de consultas:
- Receba os locais de um veículo específico em uma hora.
- Confira os locais de uma linha de ônibus inteira em uma hora.
- Encontre os locais de todos os ônibus em Manhattan em uma hora.
- Receba os locais mais recentes de todos os ônibus em Manhattan em uma hora.
- Receba os locais de uma linha de ônibus inteira ao longo do mês.
- Receba os locais de uma linha de ônibus inteira com um determinado destino em uma hora.
Projetar a chave de linha
Neste codelab, você vai trabalhar com um conjunto de dados estático, mas vai criar um esquema para escalonabilidade. Você vai criar um esquema que permite transmitir mais dados de ônibus para a tabela e ainda ter um bom desempenho.
Este é o esquema proposto para a chave de linha:
[Empresa de ônibus/Linha de ônibus/Carimbo de data/hora arredondado para a hora/ID do veículo]. Cada linha tem uma hora de dados, e cada célula contém várias versões dos dados com carimbo de data/hora.
Neste codelab, você vai usar um grupo de colunas para simplificar. Confira um exemplo de como os dados aparecem. Os dados são classificados por chave de linha.
Chave de linha | cf:VehicleLocation.Latitude | cf:VehicleLocation.Longitude | … |
MTA/M86-SBS/1496275200000/NYCT_5824 | 40.781212 @20:52:54.0040.776163 @20:43:19.0040.778714 @20:33:46.00 | -73.961942 @20:52:54.00-73.946949 @20:43:19.00-73.953731 @20:33:46.00 | … |
MTA/M86-SBS/1496275200000/NYCT_5840 | 40.780664 @20:13:51.0040.788416 @20:03:40.00 | -73.958357 @20:13:51.00 -73.976748 @20:03:40.00 | … |
MTA/M86-SBS/1496275200000/NYCT_5867 | 40.780281 @20:51:45.0040.779961 @20:43:15.0040.788416 @20:33:44.00 | -73.946890 @20:51:45.00-73.959465 @20:43:15.00-73.976748 @20:33:44.00 | … |
... | ... | ... | … |
4. Criar instância, tabela e família
Em seguida, você vai criar uma tabela do Cloud Bigtable.
Primeiro, crie um projeto. Use o Cloud Shell integrado, que pode ser aberto clicando no botão "Ativar o Cloud Shell" no canto superior direito.

Defina as seguintes variáveis de ambiente para facilitar a cópia e colagem dos comandos do codelab:
INSTANCE_ID="bus-instance" CLUSTER_ID="bus-cluster" TABLE_ID="bus-data" CLUSTER_NUM_NODES=3 CLUSTER_ZONE="us-central1-c"
O Cloud Shell já vem com as ferramentas que você vai usar neste codelab: a ferramenta de linha de comando gcloud, a interface de linha de comando cbt e o Maven.
Ative as APIs do Cloud Bigtable executando este comando.
gcloud services enable bigtable.googleapis.com bigtableadmin.googleapis.com
Crie uma instância executando o seguinte comando:
gcloud bigtable instances create $INSTANCE_ID \
--cluster=$CLUSTER_ID \
--cluster-zone=$CLUSTER_ZONE \
--cluster-num-nodes=$CLUSTER_NUM_NODES \
--display-name=$INSTANCE_ID
Depois de criar a instância, preencha o arquivo de configuração do cbt e crie uma tabela e um grupo de colunas executando os seguintes comandos:
echo project = $GOOGLE_CLOUD_PROJECT > ~/.cbtrc echo instance = $INSTANCE_ID >> ~/.cbtrc cbt createtable $TABLE_ID cbt createfamily $TABLE_ID cf
5. Importar dados
Importe um conjunto de arquivos de sequência para este codelab de gs://cloud-bigtable-public-datasets/bus-data seguindo estas etapas:
Ative a API Dataflow executando este comando.
gcloud services enable dataflow.googleapis.com
Execute os comandos a seguir para importar a tabela.
NUM_WORKERS=$(expr 3 \* $CLUSTER_NUM_NODES) gcloud beta dataflow jobs run import-bus-data-$(date +%s) \ --gcs-location gs://dataflow-templates/latest/GCS_SequenceFile_to_Cloud_Bigtable \ --num-workers=$NUM_WORKERS --max-workers=$NUM_WORKERS \ --parameters bigtableProject=$GOOGLE_CLOUD_PROJECT,bigtableInstanceId=$INSTANCE_ID,bigtableTableId=$TABLE_ID,sourcePattern=gs://cloud-bigtable-public-datasets/bus-data/*
Monitorar a importação
É possível monitorar o job na interface do Cloud Dataflow. Também é possível conferir a carga na sua instância do Cloud Bigtable com a interface de monitoramento. A importação completa leva cerca de 5 minutos.
6. Acessar o código
git clone https://github.com/googlecodelabs/cbt-intro-java.git cd cbt-intro-java
Mude para o Java 11 executando os seguintes comandos:
sudo update-java-alternatives -s java-1.11.0-openjdk-amd64 && export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/
7. Fazer uma pesquisa
A primeira consulta que você vai fazer é uma simples pesquisa de linha. Você vai receber os dados de um ônibus da linha M86-SBS em 1º de junho de 2017, das 0h às 1h. Um veículo com o ID NYCT_5824 está na linha de ônibus nesse horário.
Com essas informações e sabendo o design do esquema (empresa de ônibus/linha de ônibus/carimbo de data/hora arredondado para a hora/ID do veículo), é possível deduzir que a chave de linha é:
MTA/M86-SBS/1496275200000/NYCT_5824
BusQueries.java
private static final byte[] COLUMN_FAMILY_NAME = Bytes.toBytes("cf");
private static final byte[] LAT_COLUMN_NAME = Bytes.toBytes("VehicleLocation.Latitude");
private static final byte[] LONG_COLUMN_NAME = Bytes.toBytes("VehicleLocation.Longitude");
String rowKey = "MTA/M86-SBS/1496275200000/NYCT_5824";
Result getResult =
table.get(
new Get(Bytes.toBytes(rowKey))
.addColumn(COLUMN_FAMILY_NAME, LAT_COLUMN_NAME)
.addColumn(COLUMN_FAMILY_NAME, LONG_COLUMN_NAME));
O resultado deve conter a localização mais recente do ônibus dentro dessa hora. Mas você quer ver todos os locais, então defina o número máximo de versões na solicitação GET.
BusQueries.java
Result getResult =
table.get(
new Get(Bytes.toBytes(rowKey))
.setMaxVersions(Integer.MAX_VALUE)
.addColumn(COLUMN_FAMILY_NAME, LAT_COLUMN_NAME)
.addColumn(COLUMN_FAMILY_NAME, LONG_COLUMN_NAME));
No Cloud Shell, execute o comando a seguir para receber uma lista de latitudes e longitudes do ônibus ao longo da hora:
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=lookupVehicleInGivenHour
É possível copiar e colar as latitudes e longitudes no app MapMaker para visualizar os resultados. Depois de algumas camadas, ele vai pedir para você criar uma conta sem custo financeiro. Você pode criar uma conta ou apenas excluir as camadas atuais. Este codelab inclui uma visualização para cada etapa, caso você queira apenas acompanhar. Este é o resultado da primeira consulta:

8. Fazer uma verificação
Agora vamos conferir todos os dados da linha de ônibus para esse horário. O código de verificação é muito parecido com o código de recebimento. Você informa ao scanner uma posição inicial e indica que quer apenas as linhas da linha de ônibus M86-SBS dentro da hora indicada pelo carimbo de data/hora 1496275200000.
BusQueries.java
Scan scan;
scan = new Scan();
scan.setMaxVersions(Integer.MAX_VALUE)
.addColumn(COLUMN_FAMILY_NAME, LAT_COLUMN_NAME)
.addColumn(COLUMN_FAMILY_NAME, LONG_COLUMN_NAME)
.withStartRow(Bytes.toBytes("MTA/M86-SBS/1496275200000"))
.setRowPrefixFilter(Bytes.toBytes("MTA/M86-SBS/1496275200000"));
ResultScanner scanner = table.getScanner(scan);
Execute o comando a seguir para receber os resultados.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=scanBusLineInGivenHour

O app Map Maker pode mostrar várias listas ao mesmo tempo. Assim, você pode ver qual dos ônibus é o veículo da primeira consulta que você fez.

Uma modificação interessante nessa consulta é conferir o mês inteiro de dados da linha de ônibus M86-SBS, o que é muito fácil de fazer. Remova o carimbo de data/hora da linha inicial e o filtro de prefixo para receber o resultado.
BusQueries.java
scan.withStartRow(Bytes.toBytes("MTA/M86-SBS/"))
.setRowPrefixFilter(Bytes.toBytes("MTA/M86-SBS/"));
// Optionally, reduce the results to receive one version per column
// since there are so many data points.
scan.setMaxVersions(1);
Execute o comando a seguir para receber os resultados. (Vai aparecer uma longa lista de resultados.)
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=scanEntireBusLine
Se você copiar os resultados para o Map Maker, poderá ver um mapa de calor do trajeto do ônibus. As manchas laranjas indicam as paradas, e as manchas vermelhas brilhantes são o início e o fim do trajeto.

9. Apresentar filtros
Em seguida, você vai filtrar os ônibus que seguem para leste e para oeste e criar um mapa de calor separado para cada um.
BusQueries.java
Scan scan;
ResultScanner scanner;
scan = new Scan();
SingleColumnValueFilter valueFilter =
new SingleColumnValueFilter(
COLUMN_FAMILY_NAME,
Bytes.toBytes("DestinationName"),
CompareOp.EQUAL,
Bytes.toBytes("Select Bus Service Yorkville East End AV"));
scan.setMaxVersions(1)
.addColumn(COLUMN_FAMILY_NAME, LAT_COLUMN_NAME)
.addColumn(COLUMN_FAMILY_NAME, LONG_COLUMN_NAME);
scan.withStartRow(Bytes.toBytes("MTA/M86-SBS/"))
.setRowPrefixFilter(Bytes.toBytes("MTA/M86-SBS/"));
scan.setFilter(valueFilter);
scanner = table.getScanner(scan);
Execute o comando a seguir para receber os resultados dos ônibus que vão para o leste.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=filterBusesGoingEast
Para que os ônibus sigam para o oeste, mude a string em valueFilter:
BusQueries.java
SingleColumnValueFilter valueFilter =
new SingleColumnValueFilter(
COLUMN_FAMILY_NAME,
Bytes.toBytes("DestinationName"),
CompareOp.EQUAL,
Bytes.toBytes("Select Bus Service Westside West End AV"));
Execute o comando a seguir para receber os resultados dos ônibus que vão para o oeste.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=filterBusesGoingWest
Ônibus na direção leste

Ônibus na direção oeste

Ao comparar os dois mapas de calor, você pode ver as diferenças nos trajetos e no ritmo. Uma interpretação dos dados é que, na rota em direção ao oeste, os ônibus estão sendo parados com mais frequência, principalmente ao entrar no Central Park. E nos ônibus que seguem para o leste, não há muitos pontos de estrangulamento.
10. Fazer uma verificação de vários intervalos
Para a consulta final, você vai abordar o caso em que se importa com muitas linhas de ônibus em uma área:
BusQueries.java
private static final String[] MANHATTAN_BUS_LINES = {"M1","M2","M3",...
Scan scan;
ResultScanner scanner;
List<RowRange> ranges = new ArrayList<>();
for (String busLine : MANHATTAN_BUS_LINES) {
ranges.add(
new RowRange(
Bytes.toBytes("MTA/" + busLine + "/1496275200000"), true,
Bytes.toBytes("MTA/" + busLine + "/1496275200001"), false));
}
Filter filter = new MultiRowRangeFilter(ranges);
scan = new Scan();
scan.setFilter(filter);
scan.setMaxVersions(Integer.MAX_VALUE)
.addColumn(COLUMN_FAMILY_NAME, LAT_COLUMN_NAME)
.addColumn(COLUMN_FAMILY_NAME, LONG_COLUMN_NAME);
scan.withStartRow(Bytes.toBytes("MTA/M")).setRowPrefixFilter(Bytes.toBytes("MTA/M"));
scanner = table.getScanner(scan);
Execute o comando a seguir para receber os resultados.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=scanManhattanBusesInGivenHour

11. Concluir
Faça uma limpeza para evitar cobranças
Para evitar cobranças na sua conta do Google Cloud Platform pelos recursos usados neste codelab, exclua a instância.
gcloud bigtable instances delete $INSTANCE_ID
O que vimos
- Design de esquema
- Configurar uma instância, uma tabela e um grupo familiar
- Como importar arquivos sequenciais com o Dataflow
- Consultar com uma pesquisa, uma verificação, uma verificação com um filtro e uma verificação de vários intervalos
Próximas etapas
- Saiba mais sobre o Cloud Bigtable na documentação.
- Teste outros recursos do Google Cloud Platform. Confira nossos tutoriais.
- Saiba como monitorar dados de série temporal com a integração do OpenTSDB