Введение в Cloud Bigtable

1. Введение

В этой лабораторной работе вы познакомитесь с использованием Cloud Bigtable с клиентом Java HBase .

Вы узнаете, как

  • Избегайте распространенных ошибок при проектировании схемы
  • Импортировать данные в файл последовательности
  • Запросите свои данные

Когда вы закончите, у вас будет несколько карт, на которых показаны данные об автобусах Нью-Йорка. Например, вы создадите следующую тепловую карту автобусных поездок по Манхэттену:

7349d94f7d41f1d1.png

Как бы вы оценили свой опыт использования Google Cloud Platform?

Новичок Средний Опытный

Как вы будете использовать этот урок?

Прочтите только до конца Прочитайте его и выполните упражнения.

2. О наборе данных

Вы будете просматривать набор данных об автобусах Нью-Йорка. По этим маршрутам проложено более 300 автобусных маршрутов и 5800 транспортных средств. Наш набор данных представляет собой журнал, который включает название пункта назначения, идентификатор транспортного средства, широту, долготу, ожидаемое время прибытия и запланированное время прибытия. Набор данных состоит из снимков, сделанных примерно каждые 10 минут в июне 2017 года.

3. Разработка схемы

Чтобы добиться максимальной производительности от Cloud Bigtable, необходимо тщательно подходить к разработке схемы . Данные в Cloud Bigtable автоматически сортируются лексикографически, поэтому, если вы хорошо спроектируете свою схему, запросы связанных данных будут очень эффективными. Cloud Bigtable позволяет выполнять запросы с использованием точечного поиска по ключу строки или сканирования диапазона строк , которые возвращают непрерывный набор строк. Однако, если ваша схема недостаточно продумана, вы можете выполнить поиск по нескольким строкам или, что еще хуже, выполнить полное сканирование таблицы, что является чрезвычайно медленной операцией.

Планируйте запросы

Наши данные содержат разнообразную информацию, но для этой кодовой лаборатории вы будете использовать местоположение и пункт назначения автобуса.

Имея эту информацию, вы можете выполнить следующие запросы:

  • Получите местоположение одного автобуса за определенный час.
  • Получите данные за день по автобусной линии или конкретному автобусу.
  • Найдите все автобусы в прямоугольнике на карте.
  • Получите текущие местоположения всех автобусов (если вы получали эти данные в режиме реального времени).

Этот набор запросов не может быть оптимально выполнен вместе. Например, если вы сортируете по времени, вы не сможете выполнить сканирование по местоположению без полного сканирования таблицы. Вам необходимо расставить приоритеты на основе запросов, которые вы чаще всего выполняете.

В этой лаборатории кода вы сосредоточитесь на оптимизации и выполнении следующего набора запросов:

  • Получите местоположение конкретного автомобиля в течение часа.
  • Получите местоположение всей автобусной линии за час.
  • Получите расположение всех автобусов на Манхэттене за час.
  • Получите самые последние местоположения всех автобусов на Манхэттене за час.
  • Получите расположение всей автобусной линии за месяц.
  • Получите местоположение всей автобусной линии с определенным пунктом назначения за час.

Создайте ключ строки

В этой лаборатории кода вы будете работать со статическим набором данных, но разработаете схему для масштабируемости. Вы разработаете схему, которая позволит вам передавать в таблицу больше данных шины и при этом работать хорошо.

Вот предлагаемая схема для ключа строки:

[Автобусная компания/Автобусная линия/Метка времени, округленная до часа/Идентификатор автомобиля]. Каждая строка содержит данные за час, а каждая ячейка содержит несколько версий данных с отметкой времени.

Для этой лаборатории кода вы будете использовать одно семейство столбцов, чтобы упростить задачу. Вот пример того, как выглядят данные. Данные сортируются по ключу строки.

Ключ строки

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

...

...

...

...

...

4. Создайте экземпляр, таблицу и семейство.

Далее вы создадите таблицу Cloud Bigtable.

Сначала создайте новый проект. Используйте встроенную Cloud Shell, которую можно открыть, нажав кнопку «Активировать Cloud Shell» в правом верхнем углу.

a74d156ca7862b28.png

Установите следующие переменные среды, чтобы упростить копирование и вставку команд codelab:

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

Cloud Shell поставляется с уже установленными инструментами, которые вы будете использовать в этой лаборатории: инструмент командной строки gcloud , интерфейс командной строки cbt и Maven .

Включите API Cloud Bigtable, выполнив эту команду.

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

Создайте экземпляр, выполнив следующую команду:

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

После создания экземпляра заполните файл конфигурации cbt, а затем создайте семейство таблиц и столбцов, выполнив следующие команды:

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

cbt createtable $TABLE_ID
cbt createfamily $TABLE_ID cf

5. Импортируйте данные

Импортируйте набор файлов последовательностей для этой лаборатории кода из gs://cloud-bigtable-public-datasets/bus-data выполнив следующие действия:

Включите Cloud Dataflow API, выполнив эту команду.

gcloud services enable dataflow.googleapis.com

Выполните следующие команды, чтобы импортировать таблицу.

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

Контролируйте импорт

Вы можете отслеживать задание в пользовательском интерфейсе Cloud Dataflow . Кроме того, вы можете просмотреть нагрузку на свой экземпляр Cloud Bigtable с помощью пользовательского интерфейса мониторинга . Весь импорт займет 5 минут.

6. Получите код

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

Перейдите на Java 11, выполнив следующие команды:

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

7. Выполните поиск

Первый запрос, который вы выполните, — это простой поиск строки. Данные по автобусу линии М86-СБС вы получите 1 июня 2017 года с 12:00 до 1:00. В это время на автобусной линии находится транспортное средство с идентификатором NYCT_5824 .

Имея эту информацию и зная структуру схемы (автобусная компания/автобусная линия/временная метка, округленная до часа/идентификатор транспортного средства), вы можете сделать вывод, что ключ строки:

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

Результат должен содержать самое последнее местоположение автобуса в течение этого часа. Но вы хотите видеть все местоположения, поэтому установите максимальное количество версий в запросе на получение.

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

В Cloud Shell выполните следующую команду, чтобы получить список широт и долгот для этой шины за час:

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

Вы можете скопировать и вставить значения широты и долготы в приложение MapMaker, чтобы визуализировать результаты. После нескольких слоев вам будет предложено создать бесплатную учетную запись. Вы можете создать учетную запись или просто удалить существующие слои. Эта лаборатория кода включает визуализацию каждого шага, если вы просто хотите следовать инструкциям. Вот результат этого первого запроса:

f1a1fac6051c6210.png

8. Выполните сканирование

Теперь давайте просмотрим все данные по автобусной линии за этот час. Код сканирования очень похож на код получения. Вы указываете сканеру начальную позицию, а затем указываете, что вам нужны только строки для линии шины M86-SBS в течение часа, обозначенного меткой времени 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);

Запустите следующую команду, чтобы получить результаты.

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

c18a4ac6522d08a2.png

Приложение Map Maker может отображать несколько списков одновременно, поэтому вы можете увидеть, какой из автобусов является транспортным средством из первого запущенного вами запроса.

234c1b51e3b201e.png

Интересная модификация этого запроса заключается в просмотре данных по автобусной линии M86-SBS за весь месяц, и это очень легко сделать. Удалите временную метку из начальной строки и фильтр префикса, чтобы получить результат.

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

Запустите следующую команду, чтобы получить результаты. (Будет длинный список результатов.)

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

Если скопировать результаты в MapMaker, можно просмотреть тепловую карту автобусного маршрута. Оранжевые точки обозначают остановки, а ярко-красные — начало и конец маршрута.

346f52e61b3d8902.png

9. Внедряйте фильтры

Далее вы отфильтруете автобусы, идущие на восток, и автобусы, идущие на запад, и создадите для каждого отдельную тепловую карту.

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

Запустите следующую команду, чтобы получить результаты для автобусов, идущих на восток.

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

Чтобы автобусы шли на запад, измените строку в valueFilter:

BusQueries.java

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

Запустите следующую команду, чтобы получить результаты для автобусов, идущих на запад.

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

Автобусы едут на восток

76f6f62096a6847a.png

Автобусы едут на запад

2b5771ee9046399f.png

Сравнивая две тепловые карты, вы можете увидеть различия в маршрутах, а также заметить разницу в темпе. Одна из интерпретаций данных заключается в том, что на маршруте, идущем на запад, автобусы останавливаются чаще, особенно при въезде в Центральный парк. А в автобусах, идущих на восток, вы не увидите много узких мест.

10. Выполните сканирование нескольких диапазонов.

В последнем запросе вы рассмотрите случай, когда вас интересует множество автобусных линий в определенной области:

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

Запустите следующую команду, чтобы получить результаты.

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

7349d94f7d41f1d1.png

11. Завершить

Наведите порядок, чтобы избежать обвинений

Чтобы избежать взимания платы с вашей учетной записи Google Cloud Platform за ресурсы, используемые в этой лаборатории кода, вам следует удалить свой экземпляр.

gcloud bigtable instances delete $INSTANCE_ID

Что мы рассмотрели

  • Проектирование схемы
  • Настройка экземпляра, таблицы и семейства
  • Импорт файлов последовательностей с потоком данных
  • Запрос с поиском, сканированием, сканированием с фильтром и многодиапазонным сканированием

Следующие шаги