1. Giới thiệu
Trong lớp học lập trình này, bạn sẽ làm quen với cách sử dụng Cloud Bigtable bằng ứng dụng Java HBase.
Bạn sẽ tìm hiểu cách
- Tránh những lỗi thường gặp khi thiết kế giản đồ
- Nhập dữ liệu trong một tệp trình tự
- Truy vấn dữ liệu của bạn
Khi hoàn tất, bạn sẽ có một số bản đồ hiển thị dữ liệu về xe buýt của Thành phố New York. Ví dụ: bạn sẽ tạo bản đồ nhiệt về các chuyến đi bằng xe buýt ở Manhattan:
Bạn đánh giá trải nghiệm sử dụng Google Cloud Platform như thế nào?
Bạn sẽ sử dụng hướng dẫn này như thế nào?
2. Giới thiệu về tập dữ liệu
Bạn sẽ đang xem một tập dữ liệu về xe buýt ở Thành phố New York. Hiện có hơn 300 tuyến xe buýt và 5.800 phương tiện đi theo các tuyến này. 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ã xe, vĩ độ, kinh độ, thời gian đến dự kiến và thời gian đến theo lịch. Tập dữ liệu này được tạo thành từ các ảnh chụp nhanh được chụp khoảng 10 phút một lần vào tháng 6 năm 2017.
3. Thiết kế giản đồ
Để Cloud Bigtable đạt được hiệu suất tốt nhất, bạn phải suy nghĩ kỹ khi thiết kế giản đồ. Dữ liệu trong Cloud Bigtable được tự động sắp xếp theo từ điển, vì vậy, nếu bạn thiết kế tốt giản đồ thì việc truy vấn dữ liệu liên quan sẽ rất hiệu quả. Cloud Bigtable hỗ trợ các truy vấn bằng cách sử dụng tính năng tra cứu điểm theo khoá hàng hoặc quét dải hàng để trả về một tập hợp các hàng liền nhau. Tuy nhiên, nếu giản đồ của bạn không được cân nhắc kỹ, bạn có thể phải ghép nhiều lần tra cứu hàng lại với nhau hoặc tệ hơn là thực hiện quét toàn bộ bảng, vốn là những thao tác cực kỳ chậm.
Lên kế hoạch cho truy vấn
Dữ liệu của chúng ta có rất nhiều thông tin, nhưng đối với lớp học lập trình này, bạn sẽ dùng vị trí và điểm đế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:
- Xem vị trí của một xe buýt trong một giờ nhất định.
- Lấy 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 theo hình chữ nhật trên bản đồ.
- Xem vị trí hiện tại của tất cả xe buýt (nếu bạn đang nhập dữ liệu này theo thời gian thực).
Tập hợp các truy vấn này không thể cùng nhau thực hiện một cách tối ưu. 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 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.
Đối với 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 nhóm truy vấn sau:
- Xem vị trí của một loại xe cụ thể trong hơn một giờ.
- Xem vị trí của toàn bộ tuyến xe buýt trong hơn một giờ.
- Xem vị trí của tất cả các xe buýt ở Manhattan trong một giờ.
- Xem vị trí mới nhất của tất cả xe buýt ở Manhattan trong một giờ.
- Xem vị trí của toàn bộ tuyến xe buýt trong tháng.
- Xem vị trí của toàn bộ tuyến xe buýt có một điểm đến nhất định trong hơn 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 truyền nhiều dữ liệu xe buýt hơn vào bảng mà vẫn hoạt động tốt.
Dưới đây là giản đồ được đề xuất cho khoá hàng:
[Công ty xe buýt/Dòng xe buýt/Dấu thời gian được làm tròn xuống giờ/Mã xe]. Mỗi hàng có một giờ dữ liệu và mỗi ô chứa nhiều phiên bản dữ liệu có dấu thời gian.
Đối với lớp học lập trình này, bạn sẽ sử dụng một nhóm cột để giúp mọi thứ trở nên đơn giản. Dưới đây là chế độ xem ví dụ về hình thức 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à nhóm gia đình
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 sẵn mà bạn có thể mở bằng cách nhấp vào liên kết "Kích hoạt Cloud Shell" ở góc trên bên phải.
Thiết lập các biến môi trường sau để giúp việc sao chép và dán các lệnh trong lớp học lập trình dễ dàng hơn:
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, bao gồm công cụ dòng lệnh gcloud, giao diện dòng lệnh cbt và Maven, đã đượ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 thực thể 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 rồi tạo một bảng và nhóm 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 tập hợp các 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ể giám sát công việc trong giao diện người dùng Cloud Dataflow. Ngoài ra, bạn có thể xem tải trên thực thể Cloud Bigtable bằng giao diện người dùng giám sát của thực thể đó. 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
Thay đổi 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. 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 về xe buýt trên tuyến M86-SBS vào ngày 1 tháng 6 năm 2017 từ 12:00 sáng đến 1:00 sáng. Khi đó, một phương tiện có mã NYCT_5824
đang ở trên tuyến xe buýt.
Với thông tin đó và biết được thiết kế giản đồ (Công ty xe buýt/Dòng xe buýt/Dấu thời gian được làm tròn xuống giờ/Mã xe), 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 giờ đó. Nhưng bạn muốn xem tất cả vị trí, vì vậy, hãy đặt số lượng phiên bản tối đa cho yêu cầu tải.
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 để nhận danh sách vĩ độ và kinh độ của xe buýt đó trong 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ĩ độ cũng như kinh độ vào Ứng dụng Bitmap để trực quan hoá kết quả. Sau vài lớp, hệ thố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 một tài khoản hoặc chỉ cần xoá các lớp hiện có bạn có. Lớp học lập trình này có một hình ảnh trực quan cho từng bước, nếu bạn chỉ muốn làm theo. Dưới đây là kết quả cho truy vấn đầu tiên này:
8. Quét
Bây giờ, hãy xem tất cả dữ liệu về 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 máy quét một vị trí bắt đầu và sau đó chỉ ra bạn chỉ muốn các hàng cho tuyến xe buýt M86-SBS trong phạm vi 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
Ứng dụng Map Maker có thể hiển thị nhiều danh sách cùng một lúc, vì vậy, bạn có thể thấy chiếc xe buýt nào là phương tiện của xe từ truy vấn đầu tiên bạn đã chạy.
Một sửa đổi thú vị đối với truy vấn này là xem toàn bộ dữ liệu trong tháng của tuyến xe buýt M86-SBS, và việc này rất dễ thực hiện. Hãy xoá dấu thời gian khỏi hàng bắt đầu và bộ lọc tiền tố để xem 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 MAPS, bạn có thể xem bản đồ nhiệt của tuyến đường xe buýt. Các vệt màu cam biểu thị các điểm dừng và các vệt màu đỏ tươi là điểm bắt đầu và kết thúc của tuyến đường.
9. Ra mắt bộ lọc
Tiếp theo, bạn sẽ lọc các xe buýt đi về hướng đông và các 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 xe.
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ả về xe buýt đi về phía đông.
mvn package exec:java -Dbigtable.projectID=$GOOGLE_CLOUD_PROJECT \ -Dbigtable.instanceID=$INSTANCE_ID -Dbigtable.table=$TABLE_ID \ -Dquery=filterBusesGoingEast
Để bắt 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ả về 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ề hướng đông
Xe buýt đi về hướng tây
Bằng cách so sánh hai bản đồ nhiệt, bạn có thể thấy sự khác biệt về các 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 lại 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ề hướng đông, bạn sẽ không thực sự nhìn thấy nhiều điểm nghẹt thở.
10. 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 bạn quan tâm về 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
11. Hoàn tất
Dọn dẹp để tránh bị tính phí
Để tránh làm phát sinh phí tài khoản Google Cloud Platform cho các tài nguyên sử 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à nhóm gia đình
- Nhập các tệp trình tự bằng dataflow
- Truy vấn bằng cách tra cứu, quét, quét với bộ lọc và quét đa phạm vi
Các bước tiếp theo
- Tìm hiểu thêm về Cloud Bigtable trong tài liệu này.
- Hãy dùng thử các tính năng khác của Google Cloud Platform. Hãy xem hướng dẫn của chúng tôi.
- Tìm hiểu cách theo dõi dữ liệu chuỗi thời gian bằng tính năng tích hợp OpenTSDB