Введение в Cloud Bigtable

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

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

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

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

7349d94f7d41f1d1.png

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

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

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

Только прочтите это Прочтите и выполните упражнения

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

Чтобы получить максимальную производительность от 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

...

...

...

...

...

Затем вы создадите таблицу 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"

Облако Shell поставляется с инструментами , которые вы будете использовать в этом codelab, в gcloud инструмент командной строки , в интерфейсе командной строки ТОС и 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

Импортируйте набор файлов последовательности для этой кодовой лаборатории из 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 минут.

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/

Первый запрос, который вы выполните, - это простой поиск по строке. Вы получите данные для автобуса на линии M86-SBS 1 июня 2017 года с 12:00 до 01:00. NYCT_5824 на автобусной линии будет транспортное средство с идентификатором 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

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

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

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

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

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

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

Убирать, чтобы избежать обвинений

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

gcloud bigtable instances delete $INSTANCE_ID

Что мы покрыли

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

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