Présentation de Cloud Bigtable

1. Introduction

Dans cet atelier de programmation, vous allez découvrir comment utiliser Cloud Bigtable avec le client Java HBase.

Vous apprendrez à effectuer les tâches suivantes :

  • Éviter les erreurs courantes lors de la conception de schémas
  • Importer des données dans un fichier séquentiel
  • Interroger les données

Lorsque vous aurez terminé, vous aurez plusieurs cartes affichant des données sur les bus à New York. Par exemple, vous allez créer cette carte de densité des trajets en bus à Manhattan:

7349d94f7d41f1d1.png

Comment évalueriez-vous votre expérience de l'utilisation de Google Cloud Platform ?

Débutant Intermédiaire Expert

Comment allez-vous utiliser ce tutoriel ?

<ph type="x-smartling-placeholder"></ph> Je vais seulement le lire Je vais le lire et effectuer les exercices
.

2. À propos de l'ensemble de données

Vous allez voir un jeu de données sur les bus de la ville de New York. Ils comptent plus de 300 lignes de bus et 5 800 véhicules. Notre ensemble de données est un journal qui inclut le nom de la destination, l'identifiant du véhicule, la latitude, la longitude, l'heure d'arrivée prévue et l'heure d'arrivée prévue. L'ensemble de données est composé d'instantanés réalisés environ toutes les 10 minutes pour juin 2017.

3. Conception de schémas

Pour tirer le meilleur parti de Cloud Bigtable, vous devez concevoir votre schéma de manière réfléchie. Dans Cloud Bigtable, les données sont triées automatiquement de manière lexicographique. Par conséquent, si vous concevez bien votre schéma, l'interrogation des données associées s'avère très efficace. Cloud Bigtable permet d'effectuer des requêtes à l'aide de recherches de points par clé de ligne ou d'analyses de plages de lignes qui renvoient un ensemble de lignes contiguës. Toutefois, si votre schéma n'est pas bien conçu, vous pourriez vous retrouver à assembler plusieurs recherches de lignes ou, pire, à effectuer des analyses complètes de table, qui sont des opérations extrêmement lentes.

Planifier les requêtes

Nos données sont diverses, mais pour cet atelier de programmation, vous utiliserez la position et la destination du bus.

Avec ces informations, vous pouvez effectuer les requêtes suivantes:

  • Obtenez la position d'un bus sur une heure donnée.
  • Obtenez l'équivalent des données d'une journée pour une ligne de bus ou un bus spécifique.
  • Trouvez tous les bus dans un rectangle sur une carte.
  • Obtenez la position actuelle de tous les bus (si vous avez ingéré ces données en temps réel).

Cet ensemble de requêtes ne peut pas être effectué ensemble de manière optimale. Par exemple, si vous effectuez un tri par heure, vous ne pouvez pas effectuer d'analyse basée sur un lieu sans effectuer une analyse complète du tableau. Vous devez établir des priorités en fonction des requêtes que vous exécutez le plus souvent.

Dans cet atelier de programmation, vous allez vous concentrer sur l'optimisation et l'exécution de l'ensemble de requêtes suivant:

  • Obtenez la position d'un véhicule spécifique sur une heure.
  • Obtenez l'emplacement d'une ligne de bus complète sur une heure.
  • Obtenez la position de tous les bus de Manhattan en une heure.
  • Obtenez la position la plus récente de tous les bus à Manhattan en une heure.
  • Obtenez la position géographique d'une ligne de bus complète au cours du mois.
  • Obtenez l'emplacement d'une ligne de bus complète avec une destination spécifique en une heure.

Concevoir la clé de ligne

Pour cet atelier de programmation, vous travaillerez avec un ensemble de données statique, mais vous concevrez un schéma évolutif. Vous allez concevoir un schéma qui vous permettra de diffuser davantage de données de bus dans la table tout en continuant de fonctionner correctement.

Voici le schéma proposé pour la clé de ligne:

[Entreprise de bus/Ligne de bus/Code temporel arrondi à l'heure/ID du véhicule]. Chaque ligne contient une heure de données et chaque cellule contient plusieurs versions horodatées des données.

Pour cet atelier de programmation, vous allez utiliser une famille de colonnes pour simplifier les choses. Voici un exemple d'affichage des données. Les données sont triées par clé de ligne.

Clé de ligne

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. Créer une instance, une table et une famille

Vous allez maintenant créer une table Cloud Bigtable.

Commencez par créer un projet. Utiliser la fenêtre Cloud Shell intégrée, que vous pouvez ouvrir en cliquant sur "Activer Cloud Shell" dans le coin supérieur droit.

a74d156ca7862b28.png

Définissez les variables d'environnement suivantes pour faciliter la copie et le collage des commandes de l'atelier de programmation:

INSTANCE_ID="bus-instance"
CLUSTER_ID="bus-cluster"
TABLE_ID="bus-data"
CLUSTER_NUM_NODES=3
CLUSTER_ZONE="us-central1-c"

Cloud Shell est fourni avec les outils que vous utiliserez dans cet atelier de programmation : l'outil de ligne de commande gcloud, l'interface de ligne de commande cbt et Maven, qui sont déjà installés.

Activez les API Cloud Bigtable en exécutant cette commande.

gcloud services enable bigtable.googleapis.com bigtableadmin.googleapis.com

Créez une instance en exécutant la commande suivante:

gcloud bigtable instances create $INSTANCE_ID \
    --cluster=$CLUSTER_ID \
    --cluster-zone=$CLUSTER_ZONE \
    --cluster-num-nodes=$CLUSTER_NUM_NODES \
    --display-name=$INSTANCE_ID

Une fois l'instance créée, remplissez le fichier de configuration cbt, puis créez une table et une famille de colonnes en exécutant les commandes suivantes:

echo project = $GOOGLE_CLOUD_PROJECT > ~/.cbtrc
echo instance = $INSTANCE_ID >> ~/.cbtrc

cbt createtable $TABLE_ID
cbt createfamily $TABLE_ID cf

5. Importer des données

Importez un ensemble de fichiers séquentiels à partir de gs://cloud-bigtable-public-datasets/bus-data pour cet atelier de programmation en procédant comme suit:

Activez l'API Cloud Dataflow en exécutant cette commande.

gcloud services enable dataflow.googleapis.com

Exécutez les commandes suivantes pour importer la table.

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/*

Surveiller l'importation

Vous pouvez surveiller la tâche dans l'interface utilisateur de Cloud Dataflow. Vous pouvez également afficher la charge sur votre instance Cloud Bigtable avec son UI de surveillance. L'ensemble de l'importation devrait prendre cinq minutes.

6. Obtenir le code

git clone https://github.com/googlecodelabs/cbt-intro-java.git
cd cbt-intro-java

Passez à Java 11 en exécutant les commandes suivantes:

sudo update-java-alternatives -s java-1.11.0-openjdk-amd64 && export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/

7. Effectuer une recherche

La première requête que vous allez exécuter est une simple recherche de lignes. Vous obtiendrez les données concernant un bus sur la ligne M86-SBS le 1er juin 2017 de minuit à 1h du matin. Un véhicule associé à l'identifiant NYCT_5824 se trouve sur la ligne de bus à cette date.

Avec ces informations et la conception du schéma (entreprise de bus/ligne de bus/horodatage arrondi à l'heure/ID du véhicule), vous pouvez en déduire que la clé de ligne est:

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));

Le résultat devrait contenir la position la plus récente du bus pour cette heure. Mais comme vous souhaitez voir tous les emplacements, définissez le nombre maximal de versions dans la requête 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));

Dans Cloud Shell, exécutez la commande suivante pour obtenir la liste des latitudes et longitudes de ce bus sur une heure donnée:

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

Vous pouvez copier et coller les latitudes et les longitudes dans l'application Map Maker pour visualiser les résultats. Après quelques couches, vous serez invité à créer un compte sans frais. Vous pouvez créer un compte ou simplement supprimer les calques existants. Cet atelier de programmation comprend une visualisation pour chaque étape, si vous souhaitez simplement suivre la procédure. Voici le résultat de cette première requête:

f1a1fac6051c6210.png

8. Effectuer une analyse

Examinons maintenant toutes les données de la ligne de bus pour cette heure. Le code de numérisation ressemble beaucoup à celui du code GET. Vous indiquez une position de départ au scanner, puis vous indiquez que vous ne voulez que les lignes de la ligne de bus M86-SBS dans l'heure indiquée par le code temporel 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);

Exécutez la commande suivante pour obtenir les résultats.

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

c18a4ac6522d08a2.png

L'application Map Maker peut afficher plusieurs listes à la fois, ce qui vous permet de voir quel bus est le véhicule de la première requête que vous avez exécutée.

234c1b51e3b201e.png

Une modification intéressante de cette requête consiste à afficher le mois entier de données pour la ligne de bus M86-SBS, ce qui est très facile à faire. Supprimez l'horodatage de la ligne de début et du filtre de préfixe pour obtenir le résultat.

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);

Exécutez la commande suivante pour obtenir les résultats. (Une longue liste de résultats s'affiche.)

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

Si vous copiez les résultats dans Map Maker, vous pouvez afficher une carte de densité de l'itinéraire de bus. Les blobs orange indiquent les arrêts, tandis que les blobs rouge vif indiquent le début et la fin de l'itinéraire.

346f52e61b3d8902.png

9. Intégrer des filtres

Ensuite, vous filtrerez les bus allant vers l'est et les bus vers l'ouest et créerez une carte de densité distincte pour chacun d'eux.

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);

Exécutez la commande suivante pour obtenir les résultats des bus qui vont vers l'est.

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

Pour faire en sorte que les bus aillent vers l'ouest, modifiez la chaîne dans le paramètre valueFilter:

BusQueries.java

SingleColumnValueFilter valueFilter =
    new SingleColumnValueFilter(
        COLUMN_FAMILY_NAME,
        Bytes.toBytes("DestinationName"),
        CompareOp.EQUAL,
        Bytes.toBytes("Select Bus Service Westside West End AV"));

Exécutez la commande suivante pour obtenir les résultats pour les bus allant vers l'ouest.

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

Bus allant vers l'est

76f6f62096a6847a.png

Bus allant vers l'ouest

2b5771ee9046399f.png

En comparant les deux cartes de densité, vous pouvez observer les différences entre les itinéraires et le rythme. L'une des interprétations des données est que sur l'itinéraire allant vers l'ouest, les bus s'arrêtent davantage, surtout à l'entrée de Central Park. Et dans les bus en direction de l'est, il n'y a pas beaucoup d'étranglements.

10. Effectuer une analyse multiplage

Pour la dernière requête, vous répondrez au cas où vous vous souciez de nombreuses lignes de bus dans une zone:

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);

Exécutez la commande suivante pour obtenir les résultats.

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

7349d94f7d41f1d1.png

11. Finaliser

Effectuer un nettoyage pour éviter que des frais ne vous soient facturés

Pour éviter que les ressources utilisées dans cet atelier de programmation soient facturées sur votre compte Google Cloud Platform, vous devez supprimer votre instance.

gcloud bigtable instances delete $INSTANCE_ID

Points abordés

  • Conception de schémas
  • Configurer une instance, une table et une famille
  • Importer des fichiers séquentiels avec Dataflow
  • Interroger avec une recherche, une analyse, une analyse avec un filtre et une analyse multiplage

Étapes suivantes