Introdução ao Cloud Bigtable

Neste codelab, você conhecerá o uso do Cloud Bigtable com o cliente Java HBase .

Você aprenderá como

  • Evite erros comuns com design de esquema
  • Importar dados em um arquivo de sequência
  • Consultar seus dados

Quando terminar, você terá vários mapas que mostram os dados dos ônibus da cidade de Nova York. Por exemplo, você criará este mapa de calor de viagens de ônibus em Manhattan:

7349d94f7d41f1d1.png

Como você avaliaria sua experiência com o uso do Google Cloud Platform?

Novato Intermediário Proficiente

Como você usará este tutorial?

Leia apenas na íntegra Leia e complete os exercícios

Você verá um conjunto de dados sobre os ônibus da cidade de Nova York. Existem mais de 300 rotas de ônibus e 5.800 veículos seguindo essas rotas. Nosso conjunto de dados é um registro que inclui o nome do destino, a identificação do veículo, a latitude, a longitude, a hora de chegada prevista e a hora de chegada programada. O conjunto de dados é composto de instantâneos tirados a cada 10 minutos em junho de 2017.

Para obter o melhor desempenho do Cloud Bigtable, você deve ser cuidadoso ao projetar seu esquema . Os dados no Cloud Bigtable são classificados automaticamente lexicograficamente, portanto, se você projetar bem o seu esquema, consultar os dados relacionados é muito eficiente. O Cloud Bigtable permite consultas usando pesquisas de ponto por chave de linha ou varreduras de intervalo de linha que retornam um conjunto contíguo de linhas. No entanto, se o seu esquema não for bem pensado, você pode se pegar juntando várias pesquisas de linha ou, pior, fazendo varreduras completas de tabela, que são operações extremamente lentas.

Planeje as consultas

Nossos dados possuem uma variedade de informações, mas para este codelab, você usará a localização e o destino do ônibus.

Com essas informações, você pode realizar estas consultas:

  • Obtenha a localização de um único ônibus em uma determinada hora.
  • Obtenha os dados de um dia para uma linha de ônibus ou ônibus específico.
  • Encontre todos os ônibus em um retângulo em um mapa.
  • Obtenha as localizações atuais de todos os ônibus (se você estiver ingerindo esses dados em tempo real).

Este conjunto de consultas não pode ser feito em conjunto de maneira ideal. Por exemplo, se você estiver classificando por tempo, não poderá fazer uma varredura com base em um local sem fazer uma varredura completa da tabela. Você precisa priorizar com base nas consultas que executa com mais frequência.

Para este codelab, você se concentrará em otimizar e executar o seguinte conjunto de consultas:

  • Obtenha as localizações de um veículo específico ao longo de uma hora.
  • Obtenha a localização de uma linha inteira de ônibus ao longo de uma hora.
  • Obtenha a localização de todos os ônibus em Manhattan em uma hora.
  • Obtenha as localizações mais recentes de todos os ônibus em Manhattan em uma hora.
  • Obtenha a localização de uma linha inteira de ônibus ao longo do mês.
  • Obtenha as localizações de uma linha inteira de ônibus com um determinado destino ao longo de uma hora.

Projete a chave de linha

Para este codelab, você trabalhará com um conjunto de dados estático, mas projetará um esquema para escalabilidade. Você projetará um esquema que permite transmitir mais dados de barramento na tabela e ainda ter um bom desempenho.

Aqui está o esquema proposto para a chave de linha:

[Empresa de ônibus / Linha de ônibus / Registro de data e 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.

Para este codelab, você usará uma família de colunas para manter as coisas simples. Aqui está um exemplo de exibição de como os dados se parecem. 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,00 40,776163 @ 20: 43: 19,00 40,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,00 40,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,00 40,779961 @ 20: 43: 15,00 40,788416 @ 20: 33: 44,00

-73,946890 @ 20: 51: 45,00 -73,959465 @ 20: 43: 15,00 -73,976748 @ 20: 33: 44,00

...

...

...

...

...

Em seguida, você criará uma tabela do Cloud Bigtable.

Primeiro, crie um novo projeto. Use o Cloud Shell integrado, que você pode abrir clicando no botão "Ativar Cloud Shell" no canto superior direito.

a74d156ca7862b28.png

Defina as seguintes variáveis ​​de ambiente para tornar mais fácil copiar e colar os 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 vem com as ferramentas que você usará neste codelab, a ferramenta de linha de comando gcloud , a interface de linha de comando cbt e o Maven , já instalado.

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 cbt e crie uma tabela e família 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

Importe um conjunto de arquivos de sequência para este codelab de gs://cloud-bigtable-public-datasets/bus-data com as seguintes etapas:

Ative a API Cloud Dataflow executando este comando.

gcloud services enable dataflow.googleapis.com

Execute os seguintes comandos 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/*

Monitore a importação

Você pode monitorar o trabalho na IU do Cloud Dataflow . Além disso, você pode visualizar a carga em sua instância do Cloud Bigtable com sua IU de monitoramento . Deve levar 5 minutos para toda a importação.

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/

A primeira consulta que você realizará é uma pesquisa de linha simples. Você obterá os dados de um ônibus na linha M86-SBS em 1º de junho de 2017, das 12h00 à 1h00. NYCT_5824 um veículo com id NYCT_5824 está na linha de ônibus.

Com essas informações e conhecendo o projeto do esquema (empresa de ônibus / linha de ônibus / carimbo de data / hora arredondado para a hora / ID do veículo), você pode 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 naquela hora. Mas você deseja 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 seguinte comando para obter uma lista de latitudes e longitudes para esse ônibus ao longo da hora:

mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \
-Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \
-Dquery=lookupVehicleInGivenHour

Você pode copiar e colar as latitudes e longitudes no MapMaker App para visualizar os resultados. Depois de algumas camadas, ele dirá para você criar uma conta gratuita. Você pode criar uma conta ou apenas excluir as camadas existentes que você possui. Este codelab inclui uma visualização para cada etapa, se você quiser apenas acompanhar. Aqui está o resultado desta primeira consulta:

f1a1fac6051c6210.png

Agora, vamos ver todos os dados da linha de ônibus para aquela hora. O código de verificação é muito semelhante ao código de obtenção. Você fornece ao scanner uma posição inicial e indica que deseja apenas linhas para a 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 seguinte comando para obter os resultados.

mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \
-Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \
-Dquery=scanBusLineInGivenHour

c18a4ac6522d08a2.png

O aplicativo Map Maker pode exibir várias listas de uma vez, para que você possa ver qual dos ônibus é o veículo desde a primeira consulta realizada.

234c1b51e3b201e.png

Uma modificação interessante nessa consulta é visualizar os dados do mês inteiro para a linha de ônibus M86-SBS, e isso é muito fácil de fazer. Remova o carimbo de data / hora da linha inicial e o filtro de prefixo para obter 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 seguinte comando para obter os resultados. (Haverá 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 MapMaker, poderá visualizar um mapa de calor da rota do ônibus. As manchas laranja indicam as paradas e as manchas vermelhas brilhantes são o início e o fim da rota.

346f52e61b3d8902.png

Em seguida, você filtrará os ônibus indo para o leste e os ônibus indo para o 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 seguinte comando para obter 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 fazer os ônibus seguirem para o oeste, altere a string no 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 seguinte comando para obter 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 indo para o leste

76f6f62096a6847a.png

Ônibus indo para oeste

2b5771ee9046399f.png

Ao comparar os dois mapas de calor, você pode ver as diferenças nas rotas, bem como notar as diferenças no ritmo. Uma interpretação dos dados é que na rota rumo ao oeste, os ônibus estão ficando mais parados, principalmente ao entrar no Central Park. E nos ônibus que seguem para o leste, você realmente não vê muitos pontos de estrangulamento.

Para a consulta final, você abordará o caso quando se preocupa 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 seguinte comando para obter os resultados.

mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \
-Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \
-Dquery=scanManhattanBusesInGivenHour

7349d94f7d41f1d1.png

Limpe para evitar cobranças

Para evitar a incidência de cobranças em sua conta do Google Cloud Platform pelos recursos usados ​​neste codelab, você deve excluir sua instância.

gcloud bigtable instances delete $INSTANCE_ID

O que cobrimos

  • Projeto de esquema
  • Configurando uma instância, mesa e família
  • Importando arquivos de sequência com fluxo de dados
  • Consulta com uma pesquisa, uma varredura, uma varredura com um filtro e uma varredura de vários intervalos

Próximos passos