Giới thiệu về Cloud Bigtable

1. Giới thiệu

Trong lớp học lập trình này, bạn sẽ được giới thiệu về cách sử dụng Cloud Bigtable với Java HBase client.

Bạn sẽ tìm hiểu cách

  • Tránh các lỗi phổ biến khi thiết kế giản đồ
  • Nhập dữ liệu trong tệp chuỗi
  • Truy vấn dữ liệu của bạn

Khi hoàn tất, bạn sẽ có một số bản đồ cho thấy dữ liệu về xe buýt ở Thành phố New York. Ví dụ: bạn sẽ tạo bản đồ nhiệt này về các chuyến xe buýt ở Manhattan:

7349d94f7d41f1d1.png

Bạn đánh giá thế nào về trải nghiệm sử dụng Google Cloud Platform?

Người mới bắt đầu Trung cấp Thành thạo

Bạn sẽ sử dụng hướng dẫn này như thế nào?

Chỉ đọc Đọc và hoàn thành bài tập

2. Giới thiệu về tập dữ liệu

Bạn sẽ xem một tập dữ liệu về xe buýt ở Thành phố New York. Có hơn 300 tuyến xe buýt và 5.800 chiếc xe chạy trên các tuyến đó. Tập dữ liệu của chúng tôi là một nhật ký bao gồm tên điểm đến, mã nhận dạng xe, vĩ độ, kinh độ, thời gian dự kiến đến và thời gian đến theo lịch. Tập dữ liệu này bao gồm các ảnh chụp nhanh được thực hiện khoảng 10 phút một lần trong tháng 6 năm 2017.

3. Thiết kế giản đồ

Để Cloud Bigtable hoạt động hiệu quả nhất, bạn phải cân nhắc kỹ lưỡng khi thiết kế giản đồ. Dữ liệu trong Cloud Bigtable được tự động sắp xếp theo từ điển học, vì vậy, nếu bạn thiết kế giản đồ một cách hợp lý, việc truy vấn dữ liệu liên quan sẽ rất hiệu quả. Cloud Bigtable cho phép thực hiện các truy vấn bằng cách sử dụng tra cứu điểm theo khoá hàng hoặc quét dải ô để trả về một tập hợp các hàng liền kề. Tuy nhiên, nếu lược đồ của bạn không được thiết kế kỹ lưỡng, bạn có thể phải ghép nhiều lượt tìm kiếm hàng hoặc tệ hơn là thực hiện quét toàn bộ bảng, đây là những thao tác cực kỳ chậm.

Lập kế hoạch cho các truy vấn

Dữ liệu của chúng tôi có nhiều thông tin, nhưng đối với lớp học lập trình này, bạn sẽ sử dụng vị tríđích đến của xe buýt.

Với thông tin đó, bạn có thể thực hiện các truy vấn sau:

  • Lấy vị trí của một chiếc xe buýt trong một giờ nhất định.
  • Nhận dữ liệu trong một ngày cho một tuyến xe buýt hoặc xe buýt cụ thể.
  • Tìm tất cả xe buýt trong một hình chữ nhật trên bản đồ.
  • Lấy vị trí hiện tại của tất cả các xe buýt (nếu bạn đang nhập dữ liệu này theo thời gian thực).

Bạn không thể thực hiện tối ưu tất cả các truy vấn này cùng một lúc. Ví dụ: nếu đang sắp xếp theo thời gian, bạn không thể quét dựa trên vị trí mà không cần quét toàn bộ bảng. Bạn cần ưu tiên dựa trên những truy vấn mà bạn thường chạy nhất.

Trong lớp học lập trình này, bạn sẽ tập trung vào việc tối ưu hoá và thực thi tập hợp truy vấn sau:

  • Lấy vị trí của một phương tiện cụ thể trong vòng một giờ.
  • Lấy vị trí của toàn bộ tuyến xe buýt trong vòng một giờ.
  • Lấy vị trí của tất cả xe buýt ở Manhattan trong vòng một giờ.
  • Nhận thông tin về vị trí gần đây nhất của tất cả các xe buýt ở Manhattan trong vòng một giờ.
  • Nhận thông tin về vị trí của toàn bộ tuyến xe buýt trong tháng.
  • Nhận thông tin về vị trí của toàn bộ tuyến xe buýt có một điểm đến nhất định trong vòng một giờ.

Thiết kế khoá hàng

Trong lớp học lập trình này, bạn sẽ làm việc với một tập dữ liệu tĩnh, nhưng bạn sẽ thiết kế một giản đồ để có thể mở rộng. Bạn sẽ thiết kế một giản đồ cho phép bạn truyền trực tuyến nhiều dữ liệu xe buýt hơn vào bảng mà vẫn hoạt động hiệu quả.

Sau đây là giản đồ được đề xuất cho khoá hàng:

[Công ty xe buýt/Tuyến xe buýt/Dấu thời gian được làm tròn xuống đến giờ/Mã nhận dạng phương tiện]. Mỗi hàng có dữ liệu của một giờ và mỗi ô chứa nhiều phiên bản dữ liệu có dấu thời gian.

Trong lớp học lập trình này, bạn sẽ sử dụng một nhóm cột để đơn giản hoá mọi thứ. Sau đây là ví dụ về giao diện của dữ liệu. Dữ liệu được sắp xếp theo khoá hàng.

Khoá hàng

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. Tạo thực thể, bảng và họ

Tiếp theo, bạn sẽ tạo một bảng Cloud Bigtable.

Trước tiên, hãy tạo một dự án mới. Sử dụng Cloud Shell tích hợp. Bạn có thể mở Cloud Shell bằng cách nhấp vào nút "Kích hoạt Cloud Shell" ở góc trên bên phải.

a74d156ca7862b28.png

Thiết lập các biến môi trường sau để dễ dàng sao chép và dán các lệnh trong lớp học lập trình:

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

Cloud Shell đi kèm với các công cụ mà bạn sẽ sử dụng trong lớp học lập trình này, công cụ dòng lệnh gcloud, giao diện dòng lệnh cbtMaven, đã được cài đặt.

Bật Cloud Bigtable API bằng cách chạy lệnh này.

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

Tạo một phiên bản bằng cách chạy lệnh sau:

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

Sau khi bạn tạo phiên bản, hãy điền vào tệp cấu hình cbt, sau đó tạo một bảng và họ cột bằng cách chạy các lệnh sau:

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

cbt createtable $TABLE_ID
cbt createfamily $TABLE_ID cf

5. Nhập dữ liệu

Nhập một nhóm tệp trình tự cho lớp học lập trình này từ gs://cloud-bigtable-public-datasets/bus-data theo các bước sau:

Bật Cloud Dataflow API bằng cách chạy lệnh này.

gcloud services enable dataflow.googleapis.com

Chạy các lệnh sau để nhập bảng.

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

Theo dõi quá trình nhập

Bạn có thể theo dõi công việc trong giao diện người dùng Cloud Dataflow. Ngoài ra, bạn có thể xem mức tải trên thực thể Cloud Bigtable bằng giao diện người dùng giám sát. Toàn bộ quá trình nhập sẽ mất 5 phút.

6. Lấy mã

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

Chuyển sang Java 11 bằng cách chạy các lệnh sau:

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

7. Thực hiện tra cứu

Truy vấn đầu tiên bạn sẽ thực hiện là một thao tác tra cứu hàng đơn giản. Bạn sẽ nhận được dữ liệu cho một chiếc xe buýt trên tuyến M86-SBS vào ngày 1 tháng 6 năm 2017 từ 00:00 đến 01:00. Khi đó, một chiếc xe có mã nhận dạng NYCT_5824 đang hoạt động trên tuyến xe buýt này.

Với thông tin đó và biết được thiết kế giản đồ (Công ty xe buýt/Tuyến xe buýt/Dấu thời gian được làm tròn xuống đến giờ/Mã nhận dạng phương tiện), bạn có thể suy ra rằng khoá hàng là:

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

Kết quả phải chứa vị trí gần đây nhất của xe buýt trong khoảng thời gian đó. Nhưng bạn muốn xem tất cả các vị trí, vì vậy hãy đặt số lượng phiên bản tối đa cho yêu cầu 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));

Trong Cloud Shell, hãy chạy lệnh sau để lấy danh sách vĩ độ và kinh độ của xe buýt đó trong vòng một giờ:

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

Bạn có thể sao chép và dán vĩ độ và kinh độ vào Ứng dụng MapMaker để hình dung kết quả. Sau một vài lớp, ứng dụng sẽ yêu cầu bạn tạo một tài khoản miễn phí. Bạn có thể tạo tài khoản hoặc chỉ cần xoá các lớp hiện có. Lớp học lập trình này có hình ảnh minh hoạ cho từng bước, nếu bạn chỉ muốn làm theo. Sau đây là kết quả cho truy vấn đầu tiên này:

f1a1fac6051c6210.png

8. Quét

Bây giờ, hãy xem tất cả dữ liệu cho tuyến xe buýt trong giờ đó. Mã quét trông khá giống với mã nhận. Bạn cung cấp cho trình quét một vị trí bắt đầu, sau đó cho biết bạn chỉ muốn các hàng cho tuyến xe buýt M86-SBS trong giờ được biểu thị bằng dấu thời gian 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);

Chạy lệnh sau để nhận kết quả.

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

c18a4ac6522d08a2.png

Ứng dụng Map Maker có thể hiển thị nhiều danh sách cùng lúc, nhờ đó, bạn có thể biết chiếc xe buýt nào là xe của truy vấn đầu tiên mà bạn đã chạy.

234c1b51e3b201e.png

Một điểm sửa đổi thú vị cho truy vấn này là xem toàn bộ dữ liệu của tháng cho tuyến xe buýt M86-SBS. Bạn có thể dễ dàng thực hiện việc này bằng cách xoá dấu thời gian khỏi bộ lọc tiền tố và hàng bắt đầu để nhận được kết quả.

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

Chạy lệnh sau để nhận kết quả. (Sẽ có một danh sách dài các kết quả.)

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

Nếu sao chép kết quả vào MapMaker, bạn có thể xem bản đồ nhiệt của tuyến xe buýt. Các đốm màu cam cho biết các điểm dừng, còn các đốm màu đỏ tươi là điểm bắt đầu và kết thúc của tuyến đường.

346f52e61b3d8902.png

9. Giới thiệu bộ lọc

Tiếp theo, bạn sẽ lọc các xe buýt đi về hướng đông và xe buýt đi về hướng tây, đồng thời tạo một bản đồ nhiệt riêng cho mỗi hướng.

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

Chạy lệnh sau để nhận kết quả cho các xe buýt đi về hướng đông.

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

Để lấy các xe buýt đi về hướng tây, hãy thay đổi chuỗi trong valueFilter:

BusQueries.java

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

Chạy lệnh sau để nhận kết quả cho các xe buýt đi về hướng tây.

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

Xe buýt đi về phía đông

76f6f62096a6847a.png

Xe buýt đi về phía tây

2b5771ee9046399f.png

Bằng cách so sánh hai bản đồ nhiệt, bạn có thể thấy sự khác biệt về tuyến đường cũng như nhận thấy sự khác biệt về tốc độ. Một cách diễn giải dữ liệu là trên tuyến đường đi về phía tây, xe buýt dừng nhiều hơn, đặc biệt là khi đi vào Công viên Trung tâm. Và trên những chiếc xe buýt đi về phía đông, bạn không thực sự thấy nhiều điểm tắc nghẽn.

10. Thực hiện quét nhiều dải

Đối với truy vấn cuối cùng, bạn sẽ giải quyết trường hợp khi bạn quan tâm đến nhiều tuyến xe buýt trong một khu vực:

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

Chạy lệnh sau để nhận kết quả.

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

7349d94f7d41f1d1.png

11. Hoàn tất

Dọn dẹp để tránh bị tính phí

Để tránh bị tính phí cho tài khoản Google Cloud Platform đối với các tài nguyên được dùng trong lớp học lập trình này, bạn nên xoá phiên bản của mình.

gcloud bigtable instances delete $INSTANCE_ID

Nội dung đã đề cập

  • Thiết kế giản đồ
  • Thiết lập một thực thể, bảng và họ
  • Nhập tệp chuỗi bằng quy trình dữ liệu
  • Truy vấn bằng một thao tác tra cứu, một thao tác quét, một thao tác quét có bộ lọc và một thao tác quét nhiều dải

Các bước tiếp theo