1. Einführung
In diesem Codelab lernen Sie die Verwendung von Cloud Bigtable mit dem Java HBase-Client kennen.
In diesem Kurs lernen Sie, wie Sie
- Häufige Fehler beim Schemadesign vermeiden
- Daten in einer Sequenzdatei importieren
- Daten abfragen
Wenn Sie fertig sind, haben Sie mehrere Karten mit Busdaten für New York City. Sie erstellen beispielsweise diese Heatmap von Busfahrten in Manhattan:

Wie würden Sie Ihre Erfahrungen mit der Google Cloud Platform bewerten?
Wie werden Sie diese Anleitung verwenden?
2. Über das Dataset
Sie sehen sich einen Datensatz zu Bussen in New York City an. Es gibt mehr als 300 Buslinien und 5.800 Fahrzeuge,die diese Linien bedienen. Unser Dataset ist ein Log mit Zielname, Fahrzeug-ID, Breiten- und Längengrad, voraussichtlicher Ankunftszeit und planmäßiger Ankunftszeit. Das Dataset besteht aus Snapshots, die im Juni 2017 etwa alle 10 Minuten aufgenommen wurden.
3. Schemadesign
Damit Sie die beste Leistung mit Cloud Bigtable erzielen, müssen Sie beim Entwerfen Ihres Schemas sorgfältig vorgehen. Daten in Cloud Bigtable werden automatisch lexikografisch sortiert. Wenn Sie Ihr Schema also gut gestalten, ist das Abfragen von zugehörigen Daten sehr effizient. Cloud Bigtable ermöglicht Abfragen mit Punkt-Lookups nach Zeilenschlüssel oder Zeilenbereichsscans, die einen zusammenhängenden Satz von Zeilen zurückgeben. Wenn Ihr Schema jedoch nicht gut durchdacht ist, müssen Sie möglicherweise mehrere Zeilen nachschlagen oder, schlimmer noch, vollständige Tabellenscans durchführen, was extrem langsame Vorgänge sind.
Abfragen planen
Unsere Daten enthalten eine Vielzahl von Informationen. In diesem Codelab verwenden Sie jedoch nur den Standort und das Ziel des Busses.
Mit diesen Informationen können Sie die folgenden Abfragen ausführen:
- Rufen Sie den Standort eines einzelnen Busses innerhalb einer bestimmten Stunde ab.
- Tagesdaten für eine Buslinie oder einen bestimmten Bus abrufen
- Alle Busse in einem Rechteck auf einer Karte finden
- Die aktuellen Standorte aller Busse abrufen (wenn Sie diese Daten in Echtzeit erfassen).
Diese Abfragen können nicht alle zusammen optimal ausgeführt werden. Wenn Sie beispielsweise nach Zeit sortieren, können Sie keinen Scan basierend auf einem Standort durchführen, ohne einen vollständigen Tabellenscan auszuführen. Sie müssen die Priorisierung anhand der Abfragen vornehmen, die Sie am häufigsten ausführen.
In diesem Codelab konzentrieren Sie sich auf die Optimierung und Ausführung der folgenden Abfragen:
- Rufen Sie die Standorte eines bestimmten Fahrzeugs über eine Stunde ab.
- Rufen Sie die Standorte einer gesamten Buslinie über eine Stunde hinweg ab.
- Zeige mir die Standorte aller Busse in Manhattan in einer Stunde.
- Rufe die letzten Standorte aller Busse in Manhattan innerhalb einer Stunde ab.
- Standorte einer gesamten Buslinie im Laufe des Monats abrufen
- Die Standorte einer ganzen Buslinie mit einem bestimmten Ziel über eine Stunde hinweg abrufen.
Zeilenschlüssel entwerfen
In diesem Codelab arbeiten Sie mit einem statischen Dataset, entwerfen aber ein Schema für die Skalierbarkeit. Sie entwerfen ein Schema, mit dem Sie mehr Busdaten in die Tabelle streamen können, ohne dass die Leistung beeinträchtigt wird.
Hier ist das vorgeschlagene Schema für den Zeilenschlüssel:
[Busunternehmen/Buslinie/Zeitstempel, abgerundet auf die Stunde/Fahrzeug-ID]. Jede Zeile enthält Daten für eine Stunde und jede Zelle mehrere Versionen der Daten mit Zeitstempel.
In diesem Codelab verwenden Sie der Einfachheit halber nur eine Spaltenfamilie. Hier sehen Sie ein Beispiel dafür, wie die Daten aussehen. Die Daten sind nach Zeilenschlüssel sortiert.
Zeilenschlüssel | 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. Instanz, Tabelle und Familie erstellen
Als Nächstes erstellen Sie eine Cloud Bigtable-Tabelle.
Erstellen Sie zuerst ein neues Projekt. Verwenden Sie die integrierte Cloud Shell, die Sie durch Klicken auf die Schaltfläche „Cloud Shell aktivieren“ rechts oben öffnen können.

Legen Sie die folgenden Umgebungsvariablen fest, um das Kopieren und Einfügen der Codelab-Befehle zu vereinfachen:
INSTANCE_ID="bus-instance" CLUSTER_ID="bus-cluster" TABLE_ID="bus-data" CLUSTER_NUM_NODES=3 CLUSTER_ZONE="us-central1-c"
In Cloud Shell sind die Tools, die Sie in diesem Codelab verwenden, bereits installiert: das gcloud-Befehlszeilentool, die cbt-Befehlszeile und Maven.
Aktivieren Sie die Cloud Bigtable APIs, indem Sie diesen Befehl ausführen.
gcloud services enable bigtable.googleapis.com bigtableadmin.googleapis.com
Erstellen Sie eine Instanz mit dem folgenden Befehl:
gcloud bigtable instances create $INSTANCE_ID \
--cluster=$CLUSTER_ID \
--cluster-zone=$CLUSTER_ZONE \
--cluster-num-nodes=$CLUSTER_NUM_NODES \
--display-name=$INSTANCE_ID
Nachdem Sie die Instanz erstellt haben, füllen Sie die cbt-Konfigurationsdatei aus und erstellen Sie dann eine Tabelle und eine Spaltenfamilie, indem Sie die folgenden Befehle ausführen:
echo project = $GOOGLE_CLOUD_PROJECT > ~/.cbtrc echo instance = $INSTANCE_ID >> ~/.cbtrc cbt createtable $TABLE_ID cbt createfamily $TABLE_ID cf
5. Daten importieren
Importieren Sie eine Reihe von Sequenzdateien für dieses Codelab aus gs://cloud-bigtable-public-datasets/bus-data. Gehen Sie dazu so vor:
Aktivieren Sie die Cloud Dataflow API, indem Sie diesen Befehl ausführen.
gcloud services enable dataflow.googleapis.com
Führen Sie die folgenden Befehle aus, um die Tabelle zu importieren.
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/*
Import überwachen
Sie können den Job in der Cloud Dataflow-UI überwachen. Außerdem können Sie die Auslastung Ihrer Cloud Bigtable-Instanz über die Monitoring-UI ansehen. Der gesamte Import sollte etwa 5 Minuten dauern.
6. Code abrufen
git clone https://github.com/googlecodelabs/cbt-intro-java.git cd cbt-intro-java
Führen Sie die folgenden Befehle aus, um zu Java 11 zu wechseln:
sudo update-java-alternatives -s java-1.11.0-openjdk-amd64 && export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/
7. Nachschlagen
Die erste Abfrage, die Sie ausführen, ist eine einfache Zeilensuche. Sie erhalten die Daten für einen Bus auf der Linie M86-SBS am 1. Juni 2017 von 00:00 bis 01:00 Uhr. Ein Fahrzeug mit der ID NYCT_5824 ist dann auf der Buslinie unterwegs.
Mit diesen Informationen und dem Wissen über das Schemadesign (Busunternehmen/Buslinie/Zeitstempel, abgerundet auf die Stunde/Fahrzeug-ID) können Sie den Zeilenschlüssel ableiten:
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));
Das Ergebnis sollte den letzten Standort des Busses innerhalb dieser Stunde enthalten. Sie möchten jedoch alle Standorte sehen. Legen Sie daher die maximale Anzahl von Versionen in der GET-Anfrage fest.
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));
Führen Sie in Cloud Shell den folgenden Befehl aus, um eine Liste der Breiten- und Längengrade für diesen Bus über die Stunde hinweg abzurufen:
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=lookupVehicleInGivenHour
Sie können die Breiten- und Längengrade kopieren und in die MapMaker App einfügen, um die Ergebnisse zu visualisieren. Nach einigen Ebenen werden Sie aufgefordert, ein kostenloses Konto zu erstellen. Sie können ein Konto erstellen oder einfach die vorhandenen Ebenen löschen. Dieses Codelab enthält für jeden Schritt eine Visualisierung, falls Sie nur mitlesen möchten. Hier ist das Ergebnis für diese erste Anfrage:

8. Scan durchführen
Sehen wir uns nun alle Daten für die Buslinie für diese Stunde an. Der Scan-Code sieht dem Abrufcode sehr ähnlich. Sie geben dem Scanner eine Startposition und geben dann an, dass Sie nur Zeilen für die Buslinie M86-SBS innerhalb der Stunde möchten, die durch den Zeitstempel 1496275200000 angegeben wird.
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);
Führen Sie den folgenden Befehl aus, um die Ergebnisse abzurufen.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=scanBusLineInGivenHour

In der Map Maker App können mehrere Listen gleichzeitig angezeigt werden. So können Sie sehen, welcher der Busse das Fahrzeug aus der ersten Abfrage ist.

Eine interessante Änderung dieser Abfrage besteht darin, sich die Daten für den gesamten Monat für die Buslinie M86-SBS anzusehen. Das ist ganz einfach: Entfernen Sie den Zeitstempel aus der Startzeile und dem Präfixfilter, um das Ergebnis zu erhalten.
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);
Führen Sie den folgenden Befehl aus, um die Ergebnisse abzurufen. (Es wird eine lange Liste mit Ergebnissen angezeigt.)
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=scanEntireBusLine
Wenn Sie die Ergebnisse in MapMaker kopieren, können Sie eine Heatmap der Buslinie aufrufen. Die orangefarbenen Punkte stehen für die Haltestellen und die hellroten Punkte für den Start und das Ende der Route.

9. Filter einführen
Als Nächstes filtern Sie nach Bussen, die in östlicher und westlicher Richtung fahren, und erstellen für jede Richtung eine separate Heatmap.
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);
Führen Sie den folgenden Befehl aus, um die Ergebnisse für Busse in Richtung Osten abzurufen.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=filterBusesGoingEast
Wenn Sie die Busse in Richtung Westen abrufen möchten, ändern Sie den String in „valueFilter“:
BusQueries.java
SingleColumnValueFilter valueFilter =
new SingleColumnValueFilter(
COLUMN_FAMILY_NAME,
Bytes.toBytes("DestinationName"),
CompareOp.EQUAL,
Bytes.toBytes("Select Bus Service Westside West End AV"));
Führen Sie den folgenden Befehl aus, um die Ergebnisse für Busse in Richtung Westen zu erhalten.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=filterBusesGoingWest
Busse in Richtung Osten

Busse in Richtung Westen

Wenn Sie die beiden Heatmaps vergleichen, können Sie die Unterschiede in den Routen und im Tempo erkennen. Eine Interpretation der Daten ist, dass die Busse auf der Route in Richtung Westen häufiger angehalten werden, insbesondere beim Einfahren in den Central Park. Und auf den Bussen in Richtung Osten gibt es nicht viele Engstellen.
10. Scan mit mehreren Bereichen durchführen
In der letzten Abfrage geht es um den Fall, in dem Sie sich für viele Buslinien in einem Gebiet interessieren:
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);
Führen Sie den folgenden Befehl aus, um die Ergebnisse abzurufen.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=scanManhattanBusesInGivenHour

11. Abschließen
Bereinigung durchführen, um Gebühren zu vermeiden
Löschen Sie die Instanz, um zu vermeiden, dass Ihrem Google Cloud Platform-Konto die in diesem Codelab verwendeten Ressourcen in Rechnung gestellt werden.
gcloud bigtable instances delete $INSTANCE_ID
Behandelte Themen
- Schemadesign
- Instanz, Tabelle und Familie einrichten
- Sequenzdateien mit Dataflow importieren
- Abfragen mit einer Suche, einem Scan, einem Scan mit Filter und einem Scan mit mehreren Bereichen
Weiteres Vorgehen
- Weitere Informationen zu Cloud Bigtable finden Sie in der Dokumentation.
- Weitere Google Cloud Platform-Funktionen testen: mit unseren Anleitungen ausprobieren
- Zeitachsendaten mit der OpenTSDB-Integration überwachen