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 liées à la conception de schémas
- Importer des données dans un fichier séquentiel
- Interroger les données
Une fois terminé, vous disposerez de plusieurs cartes affichant les données des bus de New York. Par exemple, vous allez créer cette carte de densité des trajets en bus à Manhattan :

Quel est votre niveau d'expérience avec Google Cloud Platform ?
Comment allez-vous utiliser ce tutoriel ?
2. À propos de l'ensemble de données
Vous allez examiner un ensemble de données sur les bus de New York. Il existe plus de 300 lignes de bus et 5 800 véhicules qui les empruntent. Notre ensemble de données est un journal qui inclut le nom de la destination, l'ID du véhicule, la latitude, la longitude, l'heure d'arrivée prévue et l'heure d'arrivée programmée. L'ensemble de données est constitué d'instantanés pris environ toutes les 10 minutes en juin 2017.
3. Conception de schémas
Pour optimiser les performances de Cloud Bigtable, vous devez réfléchir attentivement à la conception de votre schéma. Les données de Cloud Bigtable sont triées automatiquement par ordre lexicographique. Par conséquent, si vous concevez bien votre schéma, les requêtes de données associées sont très efficaces. Cloud Bigtable permet d'effectuer des requêtes à l'aide de recherches ponctuelles par clé de ligne ou d'analyses de plages de lignes qui renvoient un ensemble contigu de lignes. Toutefois, si votre schéma n'est pas bien pensé, vous risquez de devoir assembler plusieurs recherches de lignes ou, pire encore, effectuer des analyses complètes de tables, qui sont des opérations extrêmement lentes.
Planifier les requêtes
Nos données contiennent diverses informations, mais pour cet atelier de programmation, vous utiliserez l'emplacement et la destination du bus.
Grâce à ces informations, vous pouvez effectuer les requêtes suivantes :
- Obtenez l'emplacement d'un bus spécifique au cours d'une heure donnée.
- Obtenez les données d'une journée pour une ligne de bus ou un bus spécifique.
- Trouve tous les bus dans un rectangle sur une carte.
- Obtenez la position actuelle de tous les bus (si vous ingérez ces données en temps réel).
Il est impossible d'exécuter de manière optimale cet ensemble de requêtes. Par exemple, si vous triez les données par heure, vous ne pouvez pas effectuer d'analyse basée sur un lieu sans effectuer une analyse complète de la table. Vous devez les hiérarchiser en fonction des requêtes que vous exécutez le plus souvent.
Dans cet atelier de programmation, vous vous concentrerez sur l'optimisation et l'exécution de l'ensemble de requêtes suivant :
- Obtenez les positions d'un véhicule spécifique sur une heure.
- Obtenez les positions d'une ligne de bus entière sur une heure.
- Obtiens la position de tous les bus à Manhattan dans une heure.
- Obtiens les positions les plus récentes de tous les bus de Manhattan dans une heure.
- Obtenez les positions d'une ligne de bus entière au cours du mois.
- Obtenez les positions d'une ligne de bus entière avec une certaine destination sur une heure.
Concevoir la clé de ligne
Pour cet atelier de programmation, vous allez travailler avec un ensemble de données statiques, mais vous allez concevoir un schéma pour l'évolutivité. Vous allez concevoir un schéma qui vous permettra de diffuser davantage de données de bus dans la table tout en conservant de bonnes performances.
Voici le schéma proposé pour la clé de ligne :
[Compagnie de bus/Ligne de bus/Code temporel arrondi à l'heure inférieure/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 utiliserez une seule famille de colonnes pour simplifier les choses. Voici un exemple de vue 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 ensuite créer une table Cloud Bigtable.
Commencez par créer un projet. Utilisez Cloud Shell intégré, que vous pouvez ouvrir en cliquant sur le bouton "Activer Cloud Shell" en haut à droite.

Définissez les variables d'environnement suivantes pour faciliter le copier-coller 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, 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
Après avoir créé l'instance, 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 de séquence pour cet atelier de programmation à partir de gs://cloud-bigtable-public-datasets/bus-data 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 le job dans l'interface utilisateur Cloud Dataflow. Vous pouvez également afficher la charge sur votre instance Cloud Bigtable avec son interface utilisateur de surveillance. L'importation complète 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 ligne. Vous obtiendrez les données d'un bus de la ligne M86-SBS le 1er juin 2017 de 0h00 à 1h00. Un véhicule avec l'ID NYCT_5824 se trouve alors sur la ligne de bus.
Grâce à ces informations et en connaissant la conception du schéma (Compagnie de bus/Ligne de bus/Code temporel arrondi à l'heure inférieure/ID du véhicule), vous pouvez déduire que la clé de ligne est la suivante :
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 doit contenir la position la plus récente du bus au cours de cette heure. Toutefois, vous souhaitez afficher tous les lieux. Définissez donc 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 des longitudes de ce bus au cours de l'heure :
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 MapMaker pour visualiser les résultats. Au bout de quelques calques, il vous demandera de créer un compte sans frais. Vous pouvez créer un compte ou simplement supprimer les calques existants. Cet atelier de programmation inclut une visualisation pour chaque étape, si vous souhaitez simplement suivre le tutoriel. Voici le résultat de cette première requête :

8. Effectuer une analyse
Maintenant, affichons toutes les données de la ligne de bus pour cette heure. Le code à scanner ressemble beaucoup au code à saisir. Vous indiquez au scanner une position de départ, puis vous précisez que vous ne souhaitez 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

L'application Map Maker peut afficher plusieurs listes à la fois. Vous pouvez ainsi identifier les bus qui correspondent au véhicule de la première requête que vous avez exécutée.

Une modification intéressante de cette requête consiste à afficher les données de l'ensemble du mois pour la ligne de bus M86-SBS. Pour ce faire, il vous suffit de supprimer le code temporel du filtre de préfixe et de la ligne de début.
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 MapMaker, vous pouvez afficher une carte de densité de la ligne de bus. Les blobs orange indiquent les arrêts, et les blobs rouge vif indiquent le début et la fin de l'itinéraire.

9. Présenter les filtres
Vous allez ensuite filtrer les bus se dirigeant vers l'est et ceux se dirigeant vers l'ouest, et créer 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 allant vers l'est.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=filterBusesGoingEast
Pour que les bus se dirigent vers l'ouest, modifiez la chaîne dans le filtre de valeur :
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 des 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 en direction de l'est

Bus en direction de l'ouest

En comparant les deux cartes thermiques, vous pouvez voir les différences entre les itinéraires et les différences de rythme. Une interprétation des données est que sur l'itinéraire en direction de l'ouest, les bus sont plus souvent arrêtés, en particulier lorsqu'ils entrent dans Central Park. Et dans les bus en direction de l'est, on ne voit pas vraiment beaucoup de points d'étranglement.
10. Effectuer une analyse multizone
Pour la dernière requête, vous allez traiter le cas où vous vous intéressez à 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

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, supprimez 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 multizone
Étapes suivantes
- Pour en savoir plus sur Cloud Bigtable, consultez la documentation.
- Testez d'autres fonctionnalités de Google Cloud Platform. en consultant nos tutoriels.
- Découvrez comment surveiller les données de séries temporelles avec l'intégration OpenTSDB.