Wprowadzenie do Cloud Bigtable

1. Wprowadzenie

Z tego ćwiczenia w Codelabs dowiesz się, jak korzystać z Cloud Bigtable za pomocą klienta Java HBase.

Dowiesz się,

  • Unikaj częstych błędów projektowania schematów
  • Importuj dane do pliku sekwencji
  • Tworzenie zapytania o dane

Gdy skończysz, zobaczysz kilka map z danymi autobusów z Nowego Jorku. Na przykład możesz utworzyć tę mapę termiczną podróży autobusem na Manhattanie:

7349d94f7d41f1d1.png

Jak oceniasz swoje doświadczenia z korzystaniem z Google Cloud Platform?

Początkujący Poziom średnio zaawansowany Biegły

Jak wykorzystasz ten samouczek?

Tylko do przeczytania Przeczytaj go i wykonaj ćwiczenia
.

2. Informacje o zbiorze danych

Oglądasz zbiór danych o autobusach z Nowego Jorku. Ponad 300 tras autobusowych i 5800 pojazdów odbywa się tymi trasami. Nasz zbiór danych zawiera dziennik, który zawiera nazwę miejsca docelowego, identyfikator pojazdu, szerokość i długość geograficzną, spodziewaną godzinę przyjazdu i zaplanowaną godzinę przyjazdu. Zbiór danych składa się z migawek z czerwca 2017 roku wykonywanych mniej więcej co 10 minut.

3. Projekt schematu

Aby uzyskać najlepszą wydajność Cloud Bigtable, musisz przemyśleć projektowanie schematu. Dane w Cloud Bigtable są automatycznie sortowane leksykograficznie, więc jeśli dobrze zaprojektujesz schemat, zapytania o powiązane dane będą bardzo skuteczne. Cloud Bigtable umożliwia wykonywanie zapytań z wykorzystaniem wyszukiwania punktowego według klucza wiersza lub skanowania zakresu wierszy, które zwracają sąsiadujący zestaw wierszy. Jeśli jednak schemat nie jest dobrze przemyślany, możesz łączyć wiele wyszukiwań wierszy lub, co gorsza, przeprowadzać pełne skanowanie tabel, co jest bardzo powolnym działaniem.

Planowanie zapytań

Nasze dane zawierają różne informacje, ale w tym ćwiczeniach z programowania należy użyć lokalizacji i miejsca docelowego autobusu.

Na podstawie tych informacji możesz wykonać te zapytania:

  • Sprawdź lokalizację pojedynczego autobusu w danej godzinie.
  • Pobierz dane z całego dnia dla linii autobusowej lub konkretnego autobusu.
  • Wyszukaj wszystkie autobusy w prostokątnym widoku na mapie.
  • Pobierz aktualne lokalizacje wszystkich autobusów (jeśli te dane były pozyskiwane w czasie rzeczywistym).

Nie można w optymalny sposób wykonać tego zbioru zapytań razem. Jeśli na przykład sortujesz dane według czasu, nie możesz przeprowadzić skanowania na podstawie lokalizacji bez pełnego skanowania tabeli. Ustalenie priorytetów na podstawie zapytań, które wykonujesz najczęściej,

W ramach tego ćwiczenia w Codelabs dowiesz się, jak zoptymalizować i wykonywać następujący zestaw zapytań:

  • Uzyskiwanie informacji o lokalizacji konkretnego pojazdu w ciągu godziny.
  • Uzyskaj informacje o lokalizacji całej linii autobusowej w ciągu godziny.
  • Sprawdź lokalizacje wszystkich autobusów na Manhattanie w ciągu godziny.
  • Sprawdź najnowsze lokalizacje wszystkich autobusów na Manhattanie w ciągu godziny.
  • Pobierz lokalizację całej linii autobusowej w ciągu miesiąca.
  • Uzyskiwanie lokalizacji całej linii autobusowej z danym miejscem docelowym w ciągu godziny.

Projektowanie klucza wiersza

W ramach tych ćwiczeń w Codelabs będziesz pracować ze statycznym zbiorem danych, ale zaprojektujesz schemat zapewniający skalowalność. Zaprojektujesz schemat, który pozwoli przesyłać do tabeli więcej danych magistrali, zachowując przy tym dobrą wydajność.

Oto proponowany schemat klucza wiersza:

[Firma autobusowa/linia autobusu/sygnatura czasowa zaokrąglona w dół do godziny/identyfikatora pojazdu]. Każdy wiersz zawiera godzinę danych, a każda komórka zawiera wiele wersji danych z sygnaturami czasowymi.

W tym ćwiczeniu w Codelabs wykorzystasz 1 grupę kolumn. Oto przykładowy widok danych. Dane są sortowane według klucza wiersza.

Klucz wiersza

cf:VehicleLocation.Współrzędne

cf:LocationLocation.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. Utwórz instancję, tabelę i rodzinę

Następnie utwórz tabelę Cloud Bigtable.

Najpierw utwórz nowy projekt. Użyj wbudowanej usługi Cloud Shell, którą możesz otworzyć, klikając „Aktywuj Cloud Shell”. w prawym górnym rogu.

a74d156ca7862b28.png

Aby ułatwić sobie kopiowanie i wklejanie poleceń ćwiczenia w programie, ustaw następujące zmienne środowiskowe:

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

Cloud Shell zawiera narzędzia, których użyjesz w tym ćwiczeniu z programowania, narzędzie wiersza poleceń gcloud, interfejs wiersza poleceń cbt i Maven.

Włącz interfejsy Cloud Bigtable API, uruchamiając to polecenie.

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

Utwórz instancję, uruchamiając to polecenie:

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

Po utworzeniu instancji wypełnij plik konfiguracji cbt, a następnie utwórz tabelę i grupę kolumn, uruchamiając te polecenia:

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

cbt createtable $TABLE_ID
cbt createfamily $TABLE_ID cf

5. Importuj dane

Zaimportuj zbiór plików sekwencji na potrzeby tego ćwiczenia z programowania z gs://cloud-bigtable-public-datasets/bus-data, wykonując te czynności:

Włącz Cloud Dataflow API, uruchamiając to polecenie.

gcloud services enable dataflow.googleapis.com

Uruchom następujące polecenia, aby zaimportować tabelę.

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

Monitorowanie importu

Zadanie możesz monitorować w interfejsie użytkownika Cloud Dataflow. Możesz też wyświetlić obciążenie instancji Cloud Bigtable za pomocą jej interfejsu monitorowania. Cały import powinien potrwać 5 minut.

6. Pobierz kod

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

Przejdź na Java 11, uruchamiając następujące polecenia:

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

7. Przeprowadź wyszukiwanie

Pierwsze zapytanie, które wykonasz, to proste wyszukiwanie wierszy. Dane dotyczące autobusu będą dostępne na linii M86-SBS 1 czerwca 2017 roku od 00:00 do 1:00. Pojazd o identyfikatorze NYCT_5824 znajduje się wtedy na linii autobusowej.

Mając te informacje i znając strukturę schematu (firma autobusowa/linia autobusu/sygnatura czasowa zaokrąglona w dół do godziny/identyfikatora pojazdu) możesz wywnioskować, że kluczem wiersza jest:

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

Wynik powinien zawierać najnowszą lokalizację autobusu z danej godziny. Jeśli jednak chcesz zobaczyć wszystkie lokalizacje, ustaw maksymalną liczbę wersji w żądaniu pobrania.

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

W Cloud Shell uruchom następujące polecenie, aby uzyskać listę szerokości i długości geograficznej tego autobusu w ciągu godziny:

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

Możesz skopiować i wkleić długości i szerokości geograficzne do aplikacji MapMaker, aby zwizualizować wyniki. Po kilku warstwach zobaczysz komunikat, że musisz utworzyć bezpłatne konto. Możesz utworzyć konto lub po prostu usunąć istniejące warstwy. To ćwiczenie w Codelabs zawiera wizualizację każdego kroku, jeśli chcesz po prostu kontynuować naukę. Oto wynik pierwszego zapytania:

f1a1fac6051c6210.png

8. Skanuj

Przejrzyjmy teraz wszystkie dane dotyczące linii autobusowej z tej godziny. Kod skanowania wygląda bardzo podobnie do kodu get. Nadaj skanerowi pozycję początkową, a następnie wskazujesz, że chcesz otrzymywać wiersze z liniami autobusowymi M86-SBS tylko w ciągu godziny. Oznaczenie to sygnaturą czasową 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);

Aby je uzyskać, uruchom to polecenie.

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

c18a4ac6522d08a2.png

Aplikacja Kreator map może wyświetlać wiele list jednocześnie, dzięki czemu w pierwszym zapytaniu możesz sprawdzić, który z autobusów jest pojazdem.

234c1b51e3b201e.png

Ciekawą modyfikacją tego zapytania jest wyświetlenie danych z całego miesiąca dla linii magistrali M86-SBS. Jest to bardzo proste. Aby uzyskać wynik, usuń sygnaturę czasową z wiersza początkowego i filtra prefiksu.

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

Aby je uzyskać, uruchom to polecenie. (Wyświetli się długa lista wyników).

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

Po skopiowaniu wyników do Kreatora Map możesz wyświetlić mapę termiczną trasy autobusu. Pomarańczowe plamy wskazują przystanki, a jasnoczerwone plamy to początek i koniec trasy.

346f52e61b3d8902.png

9. Wprowadź filtry

Następnie zastosujesz filtrowanie według autobusów jadących na wschód i autobusy kierujące się na zachód, a potem utworzysz osobną mapę termiczną dla każdego z nich.

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

Uruchom poniższe polecenie, by uzyskać wyniki dla autobusów jadących na wschód.

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

Aby autobusy kierowały się na zachód, zmień ciąg znaków w filtrze valueFilter:

BusQueries.java

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

Uruchom poniższe polecenie, by otrzymać wyniki dla autobusów jadących na zachód.

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

Autobusy jadące na wschód

76f6f62096a6847a.png

Autobusy jadące na zachód

2b5771ee9046399f.png

Dzięki porównaniu obu map termicznych można zobaczyć różnice w trasach, a także tempo. Jedną z interpretacji danych jest to, że na trasie biegnącej w kierunku zachodnim autobusy zatrzymują się częściej, zwłaszcza gdy wjeżdżają do Central Parku. A w autobusach jadących na wschód nie widać wielu zacięć.

10. Skanuj wiele zakresów

Ostatnie zapytanie dotyczy przypadku, gdy w danym obszarze zależy Ci na wielu liniach autobusowych:

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

Aby je uzyskać, uruchom to polecenie.

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

7349d94f7d41f1d1.png

11. Zakończ

Czyszczenie danych w celu uniknięcia opłat

Aby uniknąć obciążenia konta Google Cloud Platform opłatami za zasoby zużyte w tym ćwiczeniu z programowania, usuń instancję.

gcloud bigtable instances delete $INSTANCE_ID

Omówione zagadnienia

  • Projekt schematu
  • Konfigurowanie instancji, tabeli i rodziny
  • Importowanie plików sekwencji za pomocą Dataflow
  • Tworzenie zapytań z użyciem wyszukiwania, skanowania, skanowania z filtrem i skanowania wielozakresowego

Dalsze kroki