1. Tổng quan
Bản đồ có thể là một công cụ rất hữu ích khi trực quan hoá các mẫu trong một tập dữ liệu có liên quan đến vị trí theo một cách nào đó. Mối quan hệ này có thể là tên của một địa điểm, một giá trị vĩ độ và kinh độ cụ thể hoặc tên của một khu vực có ranh giới cụ thể như khu vực thống kê hoặc mã bưu chính.
Khi các tập dữ liệu này có kích thước rất lớn, bạn sẽ khó truy vấn và trực quan hoá bằng các công cụ thông thường. Bằng cách sử dụng Google BigQuery để truy vấn dữ liệu và Google Maps API để tạo truy vấn cũng như trực quan hoá đầu ra, bạn có thể nhanh chóng khám phá các mẫu hình địa lý trong dữ liệu của mình mà không cần thiết lập hoặc lập trình nhiều, đồng thời không phải quản lý hệ thống để lưu trữ các tập dữ liệu rất lớn.
Sản phẩm bạn sẽ tạo ra
Trong lớp học lập trình này, bạn sẽ viết và chạy một số truy vấn minh hoạ cách cung cấp thông tin chi tiết dựa trên vị trí cho các tập dữ liệu công khai rất lớn bằng BigQuery. Bạn cũng sẽ tạo một trang web tải bản đồ bằng Google Maps Platform JavaScript API, sau đó chạy và trực quan hoá các truy vấn không gian dựa trên cùng một tập dữ liệu công khai rất lớn bằng cách sử dụng Thư viện ứng dụng Google API cho JavaScript và BigQuery API.
Kiến thức bạn sẽ học được
- Cách truy vấn tập dữ liệu vị trí có quy mô petabyte trong vài giây bằng BigQuery, sử dụng truy vấn SQL, Hàm do người dùng xác định và BigQuery API
- Cách sử dụng Nền tảng Google Maps để thêm Google Maps vào một trang web và cho phép người dùng vẽ hình dạng trên trang web đó
- Cách trực quan hoá các truy vấn dựa trên tập dữ liệu lớn trên Google Maps, chẳng hạn như trong hình ảnh ví dụ bên dưới. Hình ảnh này cho thấy mật độ của các vị trí trả khách đi taxi vào năm 2016 từ những chuyến đi bắt đầu từ khu vực xung quanh toà nhà Empire State.
Bạn cần có
- Kiến thức cơ bản về HTML, CSS, JavaScript, SQL và Chrome DevTools
- Một trình duyệt web hiện đại, chẳng hạn như các phiên bản gần đây của Chrome, Firefox, Safari hoặc Edge.
- Trình chỉnh sửa văn bản hoặc IDE mà bạn chọn
Công nghệ
BigQuery
BigQuery là dịch vụ phân tích dữ liệu của Google dành cho các tập dữ liệu rất lớn. Công cụ này có một API RESTful và hỗ trợ các truy vấn được viết bằng SQL. Nếu có dữ liệu chứa giá trị vĩ độ và kinh độ, bạn có thể dùng các giá trị này để truy vấn dữ liệu theo vị trí. Ưu điểm là bạn có thể khám phá trực quan các tập dữ liệu rất lớn để xem xét các mẫu mà không cần phải quản lý bất kỳ cơ sở hạ tầng máy chủ hoặc cơ sở dữ liệu nào. Bạn có thể nhận được câu trả lời cho các câu hỏi của mình trong vài giây, bất kể bảng của bạn có lớn đến đâu nhờ khả năng mở rộng quy mô lớn và cơ sở hạ tầng được quản lý của BigQuery.
Nền tảng Google Maps
Google Maps Platform cung cấp quyền truy cập theo phương pháp có lập trình vào dữ liệu bản đồ, địa điểm và tuyến đường của Google. Hiện có hơn 2 triệu trang web và ứng dụng sử dụng API này để cung cấp bản đồ được nhúng và các cụm từ tìm kiếm dựa trên vị trí cho người dùng.
Lớp vẽ API JavaScript của Nền tảng Google Maps cho phép bạn vẽ các hình dạng trên bản đồ. Bạn có thể chuyển đổi các giá trị này thành dữ liệu đầu vào để chạy truy vấn đối với các bảng BigQuery có giá trị vĩ độ và kinh độ được lưu trữ trong các cột.
Để bắt đầu, bạn cần có một dự án Google Cloud Platform đã bật BigQuery và Maps API.
2. Bắt đầu thiết lập
Tài khoản Google
Nếu chưa có Tài khoản Google (Gmail hoặc Google Apps), bạn phải tạo một tài khoản.
Tạo dự án
Đăng nhập vào bảng điều khiển Google Cloud Platform ( console.cloud.google.com) rồi tạo một dự án mới. Ở đầu màn hình, bạn sẽ thấy một trình đơn thả xuống Project (Dự án):
Sau khi nhấp vào trình đơn thả xuống dự án này, bạn sẽ thấy một mục trong trình đơn cho phép bạn tạo dự án mới:
Trong hộp có nội dung "Nhập tên mới cho dự án của bạn", hãy nhập tên cho dự án mới, ví dụ: "BigQuery Codelab":
Mã dự án sẽ được tạo cho bạn. Mã dự án là một tên riêng biệt cho tất cả các dự án trên Google Cloud. Hãy ghi nhớ mã dự án vì bạn sẽ sử dụng mã này sau. Tên ở trên đã được sử dụng và sẽ không hoạt động đối với bạn. Chèn mã nhận dạng dự án của riêng bạn bất cứ khi nào bạn thấy YOUR_PROJECT_ID trong lớp học lập trình này.
Bật thanh toán
Để đăng ký BigQuery, hãy sử dụng dự án bạn đã chọn hoặc tạo ở bước trước. Bạn phải bật tính năng thanh toán cho dự án này. Sau khi bật tính năng thanh toán, bạn có thể bật BigQuery API.
Cách bật tính năng thanh toán tuỳ thuộc vào việc bạn đang tạo dự án mới hay bật lại tính năng thanh toán cho một dự án hiện có.
Google cung cấp bản dùng thử miễn phí 12 tháng cho mức sử dụng Google Cloud Platform trị giá tối đa 300 USD. Bạn có thể sử dụng bản dùng thử này cho Codelab này. Hãy tìm hiểu thêm tại https://cloud.google.com/free/.
Dự án mới
Khi tạo một dự án mới, bạn sẽ được nhắc chọn tài khoản thanh toán mà bạn muốn liên kết với dự án. Nếu bạn chỉ có một tài khoản thanh toán, thì tài khoản đó sẽ tự động được liên kết với dự án của bạn.
Nếu chưa có tài khoản thanh toán, bạn phải tạo một tài khoản và bật tính năng thanh toán cho dự án của mình thì mới có thể sử dụng nhiều tính năng của Google Cloud Platform. Để tạo một tài khoản thanh toán mới và bật tính năng thanh toán cho dự án của bạn, hãy làm theo hướng dẫn trong phần Tạo tài khoản thanh toán mới.
Dự án hiện có
Nếu có một dự án mà bạn đã tạm thời tắt tính năng thanh toán, bạn có thể bật lại tính năng thanh toán:
- Chuyển đến Cloud Platform Console.
- Trong danh sách dự án, hãy chọn dự án mà bạn muốn bật lại tính năng thanh toán.
- Mở trình đơn bên trái của bảng điều khiển rồi chọn Thanh toán
. Bạn sẽ được nhắc chọn một tài khoản thanh toán.
- Nhấp vào Thiết lập tài khoản.
Tạo Tài khoản thanh toán mới
Cách tạo tài khoản thanh toán mới:
- Truy cập vào Cloud Platform Console rồi đăng nhập hoặc đăng ký nếu bạn chưa có tài khoản.
- Mở trình đơn bên trái của bảng điều khiển rồi chọn Thanh toán
- Nhấp vào nút Tài khoản thanh toán mới. (Xin lưu ý rằng nếu đây không phải là tài khoản thanh toán đầu tiên của bạn, thì trước tiên, bạn cần mở danh sách tài khoản thanh toán bằng cách nhấp vào tên tài khoản thanh toán hiện có ở gần đầu trang, rồi nhấp vào Quản lý tài khoản thanh toán.)
- Nhập tên tài khoản thanh toán và thông tin thanh toán của bạn. Các lựa chọn bạn thấy sẽ phụ thuộc vào quốc gia của địa chỉ thanh toán. Xin lưu ý rằng đối với tài khoản ở Hoa Kỳ, bạn không thể thay đổi trạng thái thuế sau khi tạo tài khoản.
- Nhấp vào Gửi và bật tính năng thanh toán.
Theo mặc định, người tạo tài khoản thanh toán là quản trị viên thanh toán của tài khoản đó.
Để biết thông tin về cách xác minh tài khoản ngân hàng và thêm phương thức thanh toán dự phòng, hãy xem bài viết Thêm, xoá hoặc cập nhật phương thức thanh toán.
Bật BigQuery API
Để bật BigQuery API trong dự án của bạn, hãy chuyển đến trang BigQuery API Marketplace trong bảng điều khiển rồi nhấp vào nút "Bật" màu xanh dương.
3. Truy vấn dữ liệu vị trí trong BigQuery
Có 3 cách để truy vấn dữ liệu vị trí được lưu trữ dưới dạng giá trị vĩ độ, kinh độ trong BigQuery.
- Truy vấn hình chữ nhật: chỉ định khu vực bạn quan tâm dưới dạng một truy vấn chọn tất cả các hàng trong phạm vi vĩ độ và kinh độ tối thiểu và tối đa.
- Truy vấn bán kính: chỉ định khu vực bạn quan tâm bằng cách tính toán một vòng tròn xung quanh một điểm bằng công thức Haversine và các hàm Toán học để mô hình hoá hình dạng của trái đất.
- Truy vấn đa giác: chỉ định một hình dạng tuỳ chỉnh và sử dụng Hàm do người dùng xác định để thể hiện logic điểm trong đa giác cần thiết để kiểm tra xem vĩ độ và kinh độ của mỗi hàng có nằm trong hình dạng đó hay không.
Để bắt đầu, hãy sử dụng Trình chỉnh sửa truy vấn trong phần BigQuery của bảng điều khiển Google Cloud Platform để chạy các truy vấn sau đối với dữ liệu taxi ở Thành phố New York.
SQL chuẩn so với SQL cũ
BigQuery hỗ trợ 2 phiên bản SQL: SQL cũ và SQL chuẩn. Tiêu chuẩn sau là tiêu chuẩn ANSI năm 2011. Trong hướng dẫn này, chúng ta sẽ sử dụng SQL chuẩn vì SQL chuẩn tuân thủ các tiêu chuẩn tốt hơn.
Nếu muốn thực thi SQL cũ trong trình chỉnh sửa BigQuery, bạn có thể làm như sau:
- Nhấp vào nút "Tuỳ chọn khác"
- Chọn "Cài đặt truy vấn" trong trình đơn thả xuống
- Trong phần "Phương ngữ SQL", hãy chọn nút "Cũ"
- Nhấp vào nút "Lưu"
Truy vấn hình chữ nhật
Bạn có thể dễ dàng tạo truy vấn hình chữ nhật trong BigQuery. Bạn chỉ cần thêm một mệnh đề WHERE
để giới hạn kết quả trả về cho những kết quả có vị trí nằm trong khoảng giá trị tối thiểu và tối đa của vĩ độ và kinh độ.
Hãy thử ví dụ bên dưới trong bảng điều khiển BigQuery. Truy vấn này tìm kiếm một số số liệu thống kê trung bình về chuyến đi cho những chuyến đi bắt đầu ở khu vực hình chữ nhật bao gồm khu vực giữa và hạ Manhattan. Bạn có thể thử hai vị trí khác nhau, hãy bỏ chú thích mệnh đề WHERE
thứ hai để chạy truy vấn về các chuyến đi bắt đầu tại sân bay JFK.
SELECT
ROUND(AVG(tip_amount),2) as avg_tip,
ROUND(AVG(fare_amount),2) as avg_fare,
ROUND(AVG(trip_distance),2) as avg_distance,
ROUND(AVG(tip_proportion),2) as avg_tip_pc,
ROUND(AVG(fare_per_mile),2) as avg_fare_mile FROM
(SELECT
pickup_latitude, pickup_longitude, tip_amount, fare_amount, trip_distance, (tip_amount / fare_amount)*100.0 as tip_proportion, fare_amount / trip_distance as fare_per_mile
FROM `bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2015`
WHERE trip_distance > 0.01 AND fare_amount <100 AND payment_type = "1" AND fare_amount > 0
)
--Manhattan
WHERE pickup_latitude < 40.7679 AND pickup_latitude > 40.7000 AND pickup_longitude < -73.97 and pickup_longitude > -74.01
--JFK
--WHERE pickup_latitude < 40.654626 AND pickup_latitude > 40.639547 AND pickup_longitude < -73.771497 and pickup_longitude > -73.793755
Kết quả của hai cụm từ tìm kiếm cho thấy có sự khác biệt lớn về khoảng cách trung bình của chuyến đi, giá vé và tiền boa cho các chuyến đón khách ở hai địa điểm.
Manhattan
avg_tip | avg_fare | avg_distance | avg_tip_pc | avg_fare_mile |
2,52 | 12.03 | 9,97 | 22,39 | 5,97 |
JFK
avg_tip | avg_fare | avg_distance | avg_tip_pc | avg_fare_mile |
9.22 | 48,49 | 41.19 | 22,48 | 4,36 |
Truy vấn theo bán kính
Bạn cũng có thể dễ dàng tạo truy vấn bán kính trong SQL nếu biết một chút về toán học. Khi sử dụng Hàm toán học trong SQL cũ của BigQuery, bạn có thể tạo một truy vấn SQL bằng cách sử dụng Công thức Haversine. Công thức này ước tính một vùng hình tròn hoặc nắp cầu trên bề mặt trái đất.
Sau đây là ví dụ về câu lệnh SQL BigQuery cho một truy vấn hình tròn có tâm tại 40.73943, -73.99585
và bán kính là 0,1 km.
Thư viện này sử dụng giá trị hằng số là 111,045 km để ước tính khoảng cách được biểu thị bằng một độ.
Đây là dựa trên một ví dụ có tại http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/:
SELECT pickup_latitude, pickup_longitude,
(111.045 * DEGREES(
ACOS(
COS( RADIANS(40.73943) ) *
COS( RADIANS( pickup_latitude ) ) *
COS(
RADIANS( -73.99585 ) -
RADIANS( pickup_longitude )
) +
SIN( RADIANS(40.73943) ) *
SIN( RADIANS( pickup_latitude ) )
)
)
) AS distance FROM `project.dataset.tableName`
HAVING distance < 0.1
SQL cho Công thức Haversine có vẻ phức tạp nhưng tất cả những gì bạn cần làm là cắm toạ độ tâm đường tròn, bán kính và tên dự án, tập dữ liệu và bảng cho BigQuery.
Sau đây là một ví dụ về truy vấn tính toán một số số liệu thống kê trung bình về chuyến đi cho các lượt đón trong phạm vi 100 m tính từ Toà nhà Empire State. Sao chép và dán nội dung này vào bảng điều khiển web BigQuery để xem kết quả. Thay đổi vĩ độ và kinh độ để so sánh với các khu vực khác, chẳng hạn như vị trí ở Bronx.
#standardSQL
CREATE TEMPORARY FUNCTION Degrees(radians FLOAT64) RETURNS FLOAT64 AS
(
(radians*180)/(22/7)
);
CREATE TEMPORARY FUNCTION Radians(degrees FLOAT64) AS (
(degrees*(22/7))/180
);
CREATE TEMPORARY FUNCTION DistanceKm(lat FLOAT64, lon FLOAT64, lat1 FLOAT64, lon1 FLOAT64) AS (
Degrees(
ACOS(
COS( Radians(lat1) ) *
COS( Radians(lat) ) *
COS( Radians(lon1 ) -
Radians( lon ) ) +
SIN( Radians(lat1) ) *
SIN( Radians( lat ) )
)
) * 111.045
);
SELECT
ROUND(AVG(tip_amount),2) as avg_tip,
ROUND(AVG(fare_amount),2) as avg_fare,
ROUND(AVG(trip_distance),2) as avg_distance,
ROUND(AVG(tip_proportion), 2) as avg_tip_pc,
ROUND(AVG(fare_per_mile),2) as avg_fare_mile
FROM
-- EMPIRE STATE BLDG 40.748459, -73.985731
-- BRONX 40.895597, -73.856085
(SELECT pickup_latitude, pickup_longitude, tip_amount, fare_amount, trip_distance, tip_amount/fare_amount*100 as tip_proportion, fare_amount / trip_distance as fare_per_mile, DistanceKm(pickup_latitude, pickup_longitude, 40.748459, -73.985731)
FROM `bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2015`
WHERE
DistanceKm(pickup_latitude, pickup_longitude, 40.748459, -73.985731) < 0.1
AND fare_amount > 0 and trip_distance > 0
)
WHERE fare_amount < 100
Kết quả của truy vấn nằm bên dưới. Bạn có thể thấy sự khác biệt lớn về tiền boa trung bình, giá vé, khoảng cách của chuyến đi, tỷ lệ tiền boa so với giá vé và giá vé trung bình trên mỗi dặm lái xe.
Toà nhà Empire State:
avg_tip | avg_fare | avg_distance | avg_tip_pc | avg_fare_mile |
1,17 | 11,08 | 45,28 | 10,53 | 6,42 |
The Bronx
avg_tip | avg_fare | avg_distance | avg_tip_pc | avg_fare_mile |
0,52 | 17,63 | 4,75 | 4,74 | 10.9 |
Truy vấn đa giác
SQL không hỗ trợ truy vấn bằng các hình dạng tuỳ ý ngoài hình chữ nhật và hình tròn. BigQuery không có kiểu dữ liệu hình học hoặc chỉ mục không gian gốc, vì vậy, để chạy các truy vấn bằng hình đa giác, bạn cần một phương pháp khác cho các truy vấn SQL đơn giản. Một cách là xác định hàm hình học trong JavaScript và thực thi hàm đó dưới dạng Hàm do người dùng xác định (UDF) trong BigQuery.
Bạn có thể viết nhiều thao tác hình học bằng JavaScript, vì vậy, bạn có thể dễ dàng lấy một thao tác và thực thi thao tác đó trên một bảng BigQuery chứa các giá trị vĩ độ và kinh độ. Bạn cần truyền đa giác tuỳ chỉnh thông qua một UDF và thực hiện kiểm thử đối với từng hàng, chỉ trả về những hàng có vĩ độ và kinh độ nằm trong đa giác. Tìm hiểu thêm về UDF trong tài liệu tham khảo BigQuery.
Thuật toán Điểm trong đa giác
Có nhiều cách để tính toán xem một điểm có nằm trong đa giác hay không bằng JavaScript. Đây là một cổng từ C của một cách triển khai nổi tiếng sử dụng thuật toán dò tia để xác định xem một điểm nằm bên trong hay bên ngoài đa giác bằng cách đếm số lần một đường thẳng dài vô tận cắt qua ranh giới của hình dạng. Chỉ cần một vài dòng mã:
function pointInPoly(nvert, vertx, verty, testx, testy){
var i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
Chuyển sang JavaScript
Phiên bản JavaScript của thuật toán này có dạng như sau:
/* This function includes a port of C code to calculate point in polygon
* see http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html for license
*/
function pointInPoly(polygon, point){
// Convert a JSON poly into two arrays and a vertex count.
let vertx = [],
verty = [],
nvert = 0,
testx = point[0],
testy = point[1];
for (let coord of polygon){
vertx[nvert] = coord[0];
verty[nvert] = coord[1];
nvert ++;
}
// The rest of this function is the ported implementation.
for (let i = 0, let j = nvert - 1; i < nvert; j = i++) {
if ( ((verty[i] > testy) != (verty[j] > testy)) &&
(testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
Khi sử dụng SQL chuẩn trong BigQuery, phương pháp UDF chỉ yêu cầu một câu lệnh duy nhất, nhưng UDF phải được xác định là một hàm tạm thời trong câu lệnh. Dưới đây là một ví dụ. Dán câu lệnh SQL bên dưới vào cửa sổ Trình chỉnh sửa truy vấn.
CREATE TEMPORARY FUNCTION pointInPolygon(latitude FLOAT64, longitude FLOAT64)
RETURNS BOOL LANGUAGE js AS """
let polygon=[[-73.98925602436066,40.743249676056955],[-73.98836016654968,40.74280666503313],[-73.98915946483612,40.741676770346295],[-73.98967981338501,40.74191656974406]];
let vertx = [],
verty = [],
nvert = 0,
testx = longitude,
testy = latitude,
c = false,
j = nvert - 1;
for (let coord of polygon){
vertx[nvert] = coord[0];
verty[nvert] = coord[1];
nvert ++;
}
// The rest of this function is the ported implementation.
for (let i = 0; i < nvert; j = i++) {
if ( ((verty[i] > testy) != (verty[j] > testy)) &&
(testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]) ) {
c = !c;
}
}
return c;
""";
SELECT pickup_latitude, pickup_longitude, dropoff_latitude, dropoff_longitude, pickup_datetime
FROM `bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2016`
WHERE pointInPolygon(pickup_latitude, pickup_longitude) = TRUE
AND (pickup_datetime BETWEEN CAST("2016-01-01 00:00:01" AS DATETIME) AND CAST("2016-02-28 23:59:59" AS DATETIME))
LIMIT 1000
Xin chúc mừng!
Giờ đây, bạn đã chạy 3 loại truy vấn không gian bằng BigQuery. Như bạn đã thấy, vị trí tạo ra sự khác biệt lớn cho dữ liệu kết quả của các truy vấn đối với tập dữ liệu này, nhưng trừ phi bạn đoán được vị trí để chạy các truy vấn, nếu không thì bạn khó có thể khám phá các mẫu không gian một cách đặc biệt chỉ bằng cách sử dụng các truy vấn SQL.
Nếu chúng ta có thể trực quan hoá dữ liệu trên bản đồ và khám phá dữ liệu bằng cách xác định các khu vực quan tâm tuỳ ý! Bạn có thể làm được điều đó bằng cách sử dụng Google Maps API. Trước tiên, bạn cần bật Maps API, thiết lập một trang web đơn giản chạy trên máy tính cục bộ và bắt đầu sử dụng BigQuery API để gửi truy vấn từ trang web của mình.
4. Làm việc với API Google Maps
Sau khi chạy một số truy vấn không gian đơn giản, bước tiếp theo là trực quan hoá đầu ra để xem các mẫu. Để làm việc này, bạn sẽ bật Maps API, tạo một trang web gửi truy vấn từ bản đồ đến BigQuery, sau đó vẽ kết quả trên bản đồ.
Bật Maps JavaScript API
Đối với Lớp học lập trình này, bạn cần bật Maps JavaScript API của Google Maps Platform trong dự án của mình. Để thực hiện việc này, hãy làm theo các bước sau:
- Trong bảng điều khiển Google Cloud Platform, hãy chuyển đến Marketplace (Trang web thương mại)
- Trong Marketplace, hãy tìm "Maps JavaScript API"
- Nhấp vào ô Maps JavaScript API trong kết quả tìm kiếm
- Nhấp vào nút "Bật"
Tạo khoá API
Để gửi yêu cầu đến Google Maps Platform, bạn cần tạo một khoá API và gửi khoá đó cùng với tất cả các yêu cầu. Để tạo khoá API, hãy làm như sau:
- Trong bảng điều khiển Google Cloud Platform, hãy nhấp vào trình đơn ba đường kẻ để mở trình đơn điều hướng bên trái
- Chọn "API và Dịch vụ" > "Thông tin xác thực"
- Nhấp vào nút "Tạo thông tin xác thực", rồi chọn "Khoá API"
- Sao chép khoá API mới
Tải mã xuống và thiết lập một máy chủ web
Nhấp vào nút sau đây để tải tất cả mã dành cho lớp học lập trình này:
Giải nén tệp zip đã tải xuống. Thao tác này sẽ giải nén một thư mục gốc (bigquery
), trong đó có một thư mục cho mỗi bước của lớp học lập trình này, cùng với tất cả tài nguyên bạn sẽ cần.
Các thư mục stepN
chứa trạng thái cuối cùng mong muốn của từng bước trong lớp học lập trình này. Các thông tin này chỉ mang tính tham khảo. Chúng ta sẽ thực hiện mọi công việc lập trình trong thư mục có tên là work
.
Thiết lập máy chủ web cục bộ
Mặc dù bạn có thể sử dụng máy chủ web của riêng mình, nhưng lớp học lập trình này được thiết kế để hoạt động hiệu quả với Máy chủ web Chrome. Nếu chưa cài đặt ứng dụng đó, bạn có thể cài đặt từ Cửa hàng Chrome trực tuyến.
Sau khi cài đặt, hãy mở ứng dụng. Trong Chrome, bạn có thể làm như sau:
- Mở Chrome
- Trong thanh địa chỉ ở trên cùng, hãy nhập chrome://apps
- Nhấn Enter
- Trong cửa sổ mở ra, hãy nhấp vào biểu tượng Máy chủ web. Bạn cũng có thể nhấp chuột phải vào một ứng dụng để mở ứng dụng đó trong một thẻ thông thường hoặc thẻ được ghim, ở chế độ toàn màn hình hoặc trong một cửa sổ mới
Tiếp theo, bạn sẽ thấy hộp thoại này. Hộp thoại này cho phép bạn định cấu hình máy chủ web cục bộ:
- Nhấp vào "CHỌN THƯ MỤC" rồi chọn vị trí mà bạn đã tải các tệp mẫu của lớp học lập trình xuống
- Trong mục "Tuỳ chọn", hãy đánh dấu vào hộp bên cạnh "Tự động hiện index.html":
- Trượt nút bật/tắt có nhãn "Web Server: STARTED" (Máy chủ web: ĐÃ BẬT) sang trái rồi quay lại bên phải để dừng rồi khởi động lại máy chủ web
5. Đang tải bản đồ và các công cụ vẽ
Tạo một trang bản đồ cơ bản
Bắt đầu bằng một trang HTML đơn giản tải Google Maps bằng Maps JavaScript API và một vài dòng JavaScript. Mã trong Mẫu bản đồ đơn giản của Nền tảng Google Maps là một lựa chọn phù hợp để bắt đầu. Bạn có thể sao chép và dán mã này vào trình chỉnh sửa văn bản hoặc IDE mà bạn chọn, hoặc bạn có thể tìm thấy mã này bằng cách mở index.html
trong kho lưu trữ mà bạn đã tải xuống.
- Sao chép
index.html
vào thư mụcwork
trong bản sao cục bộ của kho lưu trữ - Sao chép thư mục img/ vào thư mục work/ trong bản sao cục bộ của kho lưu trữ
- Mở work/
index.html
trong trình chỉnh sửa văn bản hoặc IDE - Thay thế
YOUR_API_KEY
bằng khoá API mà bạn đã tạo trước đó
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"
async defer></script>
- Trong trình duyệt, hãy mở
localhost:<port>/work
, trong đóport
là số cổng được chỉ định trong cấu hình máy chủ web cục bộ. Cổng mặc định là8887
. Bạn sẽ thấy bản đồ đầu tiên xuất hiện.
Nếu bạn nhận được thông báo lỗi trong trình duyệt, hãy kiểm tra để đảm bảo rằng khoá API của bạn chính xác và máy chủ web cục bộ đang hoạt động.
Thay đổi vị trí và mức thu phóng mặc định
Mã đặt vị trí và mức thu phóng nằm trên các dòng 27 và 28 của index.html, hiện đang tập trung vào Sydney, Úc:
<script>
let map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -34.397, lng: 150.644},
zoom: 8
});
}
</script>
Hướng dẫn này hoạt động với dữ liệu chuyến đi bằng taxi của BigQuery ở New York, vì vậy, tiếp theo, bạn sẽ thay đổi mã khởi tạo bản đồ để tập trung vào một vị trí ở Thành phố New York ở mức thu phóng thích hợp – 13 hoặc 14 sẽ hoạt động tốt.
Để thực hiện việc này, hãy cập nhật khối mã ở trên thành khối mã sau để đặt bản đồ vào giữa Tòa nhà Empire State và điều chỉnh mức thu phóng thành 14:
<script>
let map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 40.7484405, lng: -73.9878531},
zoom: 14
});
}
</script>
Tiếp theo, hãy tải lại bản đồ trong trình duyệt để xem kết quả.
Tải các thư viện vẽ và trực quan hoá
Để thêm các chức năng vẽ vào bản đồ, bạn sẽ thay đổi tập lệnh tải API JavaScript của Maps bằng cách thêm một tham số không bắt buộc để yêu cầu Nền tảng Google Maps bật thư viện vẽ.
Lớp học lập trình này cũng sử dụng HeatmapLayer
, vì vậy, bạn cũng sẽ cập nhật tập lệnh để yêu cầu thư viện trực quan hoá. Để làm việc này, hãy thêm tham số libraries
và chỉ định các thư viện visualization
và drawing
dưới dạng các giá trị phân tách bằng dấu phẩy, ví dụ: libraries=
visualization,drawing
Ứng dụng sẽ hiển thị như sau:
<script src='http://maps.googleapis.com/maps/api/js?libraries=visualization,drawing&callback=initMap&key=YOUR_API_KEY' async defer></script>
Thêm DrawingManager
Để sử dụng các hình do người dùng vẽ làm dữ liệu đầu vào cho một truy vấn, hãy thêm DrawingManager
vào bản đồ của bạn, với các công cụ Circle
, Rectangle
và Polygon
được bật.
Bạn nên đặt tất cả mã thiết lập DrawingManager
vào một hàm mới. Vì vậy, trong bản sao index.html, hãy làm như sau:
- Thêm một hàm có tên là
setUpDrawingTools()
bằng đoạn mã sau để tạoDrawingManager
và đặt thuộc tínhmap
của hàm này để tham chiếu đến đối tượng bản đồ trong trang.
Các lựa chọn được truyền đến google.maps.drawing.DrawingManager(options)
sẽ đặt loại hình dạng vẽ mặc định và các lựa chọn hiển thị cho các hình dạng được vẽ. Để chọn các khu vực trên bản đồ để gửi dưới dạng truy vấn, các hình dạng phải có độ mờ bằng 0. Để biết thêm thông tin về các lựa chọn có sẵn, hãy xem phần Tuỳ chọn DrawingManager.
function setUpDrawingTools() {
// Initialize drawing manager
drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.CIRCLE,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_LEFT,
drawingModes: [
google.maps.drawing.OverlayType.CIRCLE,
google.maps.drawing.OverlayType.POLYGON,
google.maps.drawing.OverlayType.RECTANGLE
]
},
circleOptions: {
fillOpacity: 0
},
polygonOptions: {
fillOpacity: 0
},
rectangleOptions: {
fillOpacity: 0
}
});
drawingManager.setMap(map);
}
- Gọi
setUpDrawingTools()
trong hàminitMap()
sau khi đối tượng bản đồ được tạo
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 40.744593, lng: -73.990370}, // Manhattan, New York.
zoom: 12
});
setUpDrawingTools();
}
- Tải lại index.html và kiểm tra để đảm bảo bạn thấy các công cụ vẽ. Ngoài ra, hãy kiểm tra xem bạn có thể dùng các công cụ này để vẽ hình tròn, hình chữ nhật và hình đa giác hay không.
Bạn có thể nhấp và kéo để vẽ hình tròn và hình chữ nhật, nhưng bạn cần vẽ đa giác bằng cách nhấp vào từng đỉnh và nhấp đúp để hoàn tất hình.
Xử lý sự kiện vẽ
Bạn cần một số mã để xử lý các sự kiện được kích hoạt khi người dùng vẽ xong một hình dạng, giống như bạn cần toạ độ của các hình dạng đã vẽ để tạo truy vấn SQL.
Chúng ta sẽ thêm mã cho việc này ở bước sau, nhưng hiện tại, chúng ta sẽ tạo 3 trình xử lý sự kiện trống để xử lý các sự kiện rectanglecomplete
, circlecomplete
và polygoncomplete
. Các trình xử lý không cần chạy bất kỳ mã nào ở giai đoạn này.
Thêm đoạn mã sau vào cuối hàm setUpDrawingTools()
:
drawingManager.addListener('rectanglecomplete', rectangle => {
// We will add code here in a later step.
});
drawingManager.addListener('circlecomplete', circle => {
// We will add code here in a later step.
});
drawingManager.addListener('polygoncomplete', polygon => {
// We will add code here in a later step.
});
Bạn có thể tìm thấy một ví dụ hoạt động của mã này trong bản sao cục bộ của kho lưu trữ, trong thư mục step2
: step2/map.html.
6. Sử dụng BigQuery Client API
Google BigQuery Client API sẽ giúp bạn tránh phải viết nhiều mã nguyên mẫu cần thiết để tạo yêu cầu, phân tích cú pháp phản hồi và xử lý quy trình xác thực. Lớp học lập trình này sử dụng BigQuery API thông qua Thư viện ứng dụng API của Google cho JavaScript vì chúng ta sẽ phát triển một ứng dụng dựa trên trình duyệt.
Tiếp theo, bạn sẽ thêm mã để tải API này trong một trang web và sử dụng mã đó để tương tác với BigQuery.
Thêm Google Client API cho JavaScript
Bạn sẽ sử dụng Google Client API cho Javascript để chạy các truy vấn đối với BigQuery. Trong bản sao index.html
(trong thư mục work
), hãy tải API bằng thẻ <script>
như thế này. Đặt thẻ này ngay bên dưới thẻ <script>
tải Maps API:
<script src='https://apis.google.com/js/client.js'></script>
Sau khi tải Google Client API, hãy uỷ quyền cho người dùng truy cập vào dữ liệu trong BigQuery. Để làm việc này, bạn có thể sử dụng OAuth 2.0. Trước tiên, bạn cần thiết lập một số thông tin đăng nhập trong Dự án trên Google Cloud Console.
Tạo thông tin đăng nhập OAuth 2.0
- Trong Google Cloud Console, trên Trình đơn điều hướng, hãy chọn API và dịch vụ > Thông tin xác thực.
Trước khi có thể thiết lập thông tin đăng nhập, bạn cần thêm một số cấu hình cho màn hình Uỷ quyền mà người dùng cuối của ứng dụng sẽ thấy khi họ uỷ quyền cho ứng dụng của bạn truy cập vào dữ liệu BigQuery thay cho họ.
Để làm việc này, hãy nhấp vào thẻ Màn hình đồng ý OAuth. 2. Bạn cần thêm Big Query API vào các phạm vi cho mã thông báo này. Nhấp vào nút Add Scope (Thêm phạm vi) trong phần Scopes for Google APIs (Phạm vi cho các API của Google). 3. Trong danh sách, hãy đánh dấu vào hộp bên cạnh mục Big Query API có phạm vi là ../auth/bigquery
. 4. Nhấp vào Thêm. 5. Nhập tên vào trường "Tên ứng dụng". 6. Nhấp vào Lưu để lưu chế độ cài đặt của bạn. 7. Tiếp theo, bạn sẽ tạo mã ứng dụng khách OAuth. Để thực hiện việc này, hãy nhấp vào Tạo thông tin xác thực:
- Trong trình đơn thả xuống, hãy nhấp vào Mã ứng dụng OAuth.
- Trong mục Loại ứng dụng, hãy chọn Ứng dụng web.
- Trong trường Tên ứng dụng, hãy nhập tên cho dự án của bạn. Ví dụ: "BigQuery và Maps".
- Trong mục Restrictions (Hạn chế), trong trường Authorized JavaScript Origins (Nguồn gốc JavaScript được uỷ quyền), hãy nhập URL của localhost, bao gồm cả số cổng. Ví dụ:
http://localhost:8887
- Nhấp vào nút Tạo.
Một cửa sổ bật lên sẽ cho bạn biết mã ứng dụng khách và mật khẩu ứng dụng khách. Bạn cần mã ứng dụng khách để thực hiện xác thực đối với BigQuery. Sao chép và dán vào work/index.html
dưới dạng một biến JavaScript toàn cầu mới có tên là clientId
.
let clientId = 'YOUR_CLIENT_ID';
7. Uỷ quyền và khởi tạo
Trang web của bạn sẽ cần uỷ quyền cho người dùng truy cập vào BigQuery trước khi khởi tạo bản đồ. Trong ví dụ này, chúng ta sử dụng OAuth 2.0 như mô tả trong phần uỷ quyền của tài liệu về JavaScript Client API. Bạn cần sử dụng mã ứng dụng OAuth và mã dự án để gửi truy vấn.
Khi Google Client API được tải trong trang web, bạn cần thực hiện các bước sau:
- Uỷ quyền cho người dùng.
- Nếu được uỷ quyền, hãy tải BigQuery API.
- Tải và khởi tạo bản đồ.
Hãy xem step3/map.html để biết ví dụ về giao diện của trang HTML hoàn chỉnh.
Uỷ quyền cho người dùng
Người dùng cuối của ứng dụng cần uỷ quyền cho ứng dụng truy cập dữ liệu trong BigQuery thay cho họ. Google Client API cho JavaScript xử lý logic OAuth để thực hiện việc này.
Trong một ứng dụng thực tế, bạn có nhiều lựa chọn về cách tích hợp bước uỷ quyền.
Ví dụ: bạn có thể gọi authorize()
từ một phần tử trên giao diện người dùng như nút hoặc thực hiện khi trang đã tải. Ở đây, chúng ta đã chọn uỷ quyền cho người dùng sau khi Google Client API for JavaScript được tải, bằng cách sử dụng một hàm gọi lại trong phương thức gapi.load()
.
Viết một đoạn mã ngay sau thẻ <script>
tải Google Client API cho Javascript để tải cả thư viện ứng dụng và mô-đun uỷ quyền để chúng ta có thể xác thực người dùng ngay lập tức.
<script src='https://apis.google.com/js/client.js'></script>
<script type='text/javascript'>
gapi.load('client:auth', authorize);
</script>
Khi uỷ quyền, hãy tải BigQuery API
Sau khi người dùng được uỷ quyền, hãy tải BigQuery API.
Trước tiên, hãy gọi gapi.auth.authorize()
bằng biến clientId
mà bạn đã thêm ở bước trước. Xử lý phản hồi trong một hàm gọi lại có tên là handleAuthResult
.
Tham số immediate
kiểm soát việc người dùng có thấy cửa sổ bật lên hay không. Đặt thành true
để ngăn chặn cửa sổ uỷ quyền bật lên nếu người dùng đã được uỷ quyền.
Thêm một hàm vào trang của bạn có tên là handleAuthResult()
. Hàm này cần nhận một tham số authresult
, cho phép bạn kiểm soát luồng logic tuỳ thuộc vào việc người dùng có được uỷ quyền thành công hay không.
Ngoài ra, hãy thêm một hàm có tên là loadApi
để tải BigQuery API nếu người dùng được uỷ quyền thành công.
Thêm logic vào hàm handleAuthResult()
để gọi loadApi()
nếu có một đối tượng authResult
được truyền vào hàm và nếu thuộc tính error
của đối tượng có giá trị là false
.
Thêm mã vào hàm loadApi()
để tải BigQuery API bằng phương thức gapi.client.load()
.
let clientId = 'your-client-id-here';
let scopes = 'https://www.googleapis.com/auth/bigquery';
// Check if the user is authorized.
function authorize(event) {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: false}, handleAuthResult);
return false;
}
// If authorized, load BigQuery API
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
loadApi();
return;
}
console.error('Not authorized.')
}
// Load BigQuery client API
function loadApi(){
gapi.client.load('bigquery', 'v2');
}
Tải bản đồ
Bước cuối cùng là khởi chạy bản đồ. Bạn cần thay đổi một chút thứ tự của logic để thực hiện việc này. Hiện tại, API này sẽ khởi chạy khi Maps API JavaScript đã tải.
Bạn có thể thực hiện việc này bằng cách gọi hàm initMap()
từ phương thức then()
sau phương thức load()
trên đối tượng gapi.client
.
// Load BigQuery client API
function loadApi(){
gapi.client.load('bigquery', 'v2').then(
() => initMap()
);
}
8. Các khái niệm về BigQuery API
Các lệnh gọi BigQuery API thường thực thi trong vài giây nhưng có thể không trả về phản hồi ngay lập tức. Bạn cần một số logic để thăm dò BigQuery nhằm tìm hiểu trạng thái của các công việc chạy trong thời gian dài và chỉ tìm nạp kết quả khi công việc hoàn tất.
Mã hoàn chỉnh cho bước này nằm trong step4/map.html.
Gửi yêu cầu
Thêm một hàm JavaScript vào work/index.html
để gửi một truy vấn bằng API, cùng một số biến để lưu trữ các giá trị của tập dữ liệu và dự án BigQuery chứa bảng cần truy vấn, cũng như mã dự án sẽ được tính mọi khoản phí.
let datasetId = 'your_dataset_id';
let billingProjectId = 'your_project_id';
let publicProjectId = 'bigquery-public-data';
function sendQuery(queryString){
let request = gapi.client.bigquery.jobs.query({
'query': queryString,
'timeoutMs': 30000,
'datasetId': datasetId,
'projectId': billingProjectId,
'useLegacySql':false
});
request.execute(response => {
//code to handle the query response goes here.
});
}
Kiểm tra trạng thái của một công việc
Hàm checkJobStatus
bên dưới cho biết cách kiểm tra trạng thái của một công việc theo định kỳ, bằng cách sử dụng phương thức API get
và jobId
do yêu cầu truy vấn ban đầu trả về. Sau đây là ví dụ chạy cứ 500 mili giây cho đến khi công việc hoàn tất.
let jobCheckTimer;
function checkJobStatus(jobId){
let request = gapi.client.bigquery.jobs.get({
'projectId': billingProjectId,
'jobId': jobId
});
request.execute(response =>{
if (response.status.errorResult){
// Handle any errors.
console.log(response.status.error);
return;
}
if (response.status.state == 'DONE'){
// Get the results.
clearTimeout(jobCheckTimer);
getQueryResults(jobId);
return;
}
// Not finished, check again in a moment.
jobCheckTimer = setTimeout(checkJobStatus, 500, [jobId]);
});
}
Sửa đổi phương thức sendQuery
để gọi phương thức checkJobStatus()
dưới dạng một lệnh gọi lại trong lệnh gọi request.execute()
. Truyền mã công việc đến checkJobStatus
. Thông tin này được đối tượng phản hồi hiển thị dưới dạng jobReference.jobId
.
function sendQuery(queryString){
let request = gapi.client.bigquery.jobs.query({
'query': queryString,
'timeoutMs': 30000,
'datasetId': datasetId,
'projectId': billingProjectId,
'useLegacySql':false
});
request.execute(response => checkJobStatus(response.jobReference.jobId));
}
Nhận kết quả của một truy vấn
Để nhận kết quả của một truy vấn khi truy vấn đó đã chạy xong, hãy sử dụng lệnh gọi API jobs.getQueryResults
. Thêm một hàm có tên là getQueryResults()
vào trang của bạn. Hàm này chấp nhận một tham số là jobId
:
function getQueryResults(jobId){
let request = gapi.client.bigquery.jobs.getQueryResults({
'projectId': billingProjectId,
'jobId': jobId
});
request.execute(response => {
// Do something with the results.
})
}
9. Truy vấn dữ liệu vị trí bằng BigQuery API
Có 3 cách để sử dụng SQL nhằm chạy các truy vấn không gian đối với dữ liệu trong BigQuery:
- chọn theo hình chữ nhật (còn gọi là hộp giới hạn),
- chọn theo bán kính và
- tính năng Hàm do người dùng xác định mạnh mẽ.
Bạn có thể xem ví dụ về truy vấn hộp giới hạn và bán kính trong phần Hàm toán học của tài liệu tham khảo về SQL cũ của BigQuery, trong mục "Ví dụ nâng cao".
Đối với các truy vấn về hộp giới hạn và bán kính, bạn có thể gọi phương thức BigQuery API query
. Tạo SQL cho mỗi truy vấn và truyền SQL đó vào hàm sendQuery
mà bạn đã tạo ở bước trước.
Ví dụ minh hoạ về mã cho bước này nằm trong step4/map.html.
Truy vấn hình chữ nhật
Cách đơn giản nhất để hiển thị dữ liệu BigQuery trên bản đồ là yêu cầu tất cả các hàng có vĩ độ và kinh độ nằm trong một hình chữ nhật, bằng cách sử dụng phép so sánh nhỏ hơn và lớn hơn. Đây có thể là chế độ xem bản đồ hiện tại hoặc một hình dạng được vẽ trên bản đồ.
Để sử dụng hình do người dùng vẽ, hãy thay đổi mã trong index.html
để xử lý sự kiện vẽ được kích hoạt khi một hình chữ nhật hoàn tất. Trong ví dụ này, mã sử dụng getBounds()
trên đối tượng hình chữ nhật để lấy một đối tượng biểu thị phạm vi của hình chữ nhật theo toạ độ trên bản đồ và truyền đối tượng đó đến một hàm có tên là rectangleQuery
:
drawingManager.addListener('rectanglecomplete', rectangle => rectangleQuery(rectangle.getBounds()));
Hàm rectangleQuery
chỉ cần sử dụng toạ độ trên cùng bên phải (đông bắc) và dưới cùng bên trái (tây nam) để tạo phép so sánh nhỏ hơn/lớn hơn với từng hàng trong bảng BigQuery. Sau đây là một ví dụ truy vấn một bảng có các cột tên là 'pickup_latitude'
và 'pickup_longitude'
lưu trữ các giá trị vị trí.
Chỉ định bảng BigQuery
Để truy vấn một bảng bằng BigQuery API, bạn cần cung cấp tên của bảng ở dạng đủ điều kiện trong truy vấn SQL. Định dạng trong SQL chuẩn là project.dataset.tablename
. Trong SQL cũ, đó là project.dataset.tablename
.
Có nhiều bảng về các chuyến đi bằng taxi ở Thành phố New York. Để xem các tập dữ liệu này, hãy chuyển đến bảng điều khiển web BigQuery rồi mở rộng mục "tập dữ liệu công khai". Tìm tập dữ liệu có tên new_york
rồi mở rộng tập dữ liệu đó để xem các bảng. Chọn bảng Chuyến đi bằng taxi màu vàng: bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2016
).
Chỉ định mã dự án
Trong lệnh gọi API, bạn cần chỉ định tên dự án Google Cloud Platform của mình cho mục đích thanh toán. Trong lớp học lập trình này, đây không phải là dự án chứa bảng. Nếu bạn đang làm việc với một bảng mà bạn đã tạo trong dự án của riêng mình bằng cách tải dữ liệu lên, thì mã dự án này sẽ giống với mã dự án trong câu lệnh SQL của bạn.
Thêm các biến JavaScript vào mã của bạn để lưu trữ thông tin tham chiếu đến dự án Tập dữ liệu công khai chứa bảng mà bạn đang truy vấn, cùng với tên bảng và tên tập dữ liệu. Bạn cũng cần một biến riêng để tham chiếu đến mã dự án thanh toán của riêng bạn.
Thêm các biến JavaScript toàn cục có tên là billingProjectId, publicProjectId, datasetId
và tableName
vào bản sao index.html.
Khởi chạy các biến 'publicProjectId'
, 'datasetId'
và 'tableName'
bằng thông tin chi tiết từ dự án Tập dữ liệu công khai của BigQuery. Khởi chạy billingProjectId
bằng Mã dự án của riêng bạn (mã dự án mà bạn đã tạo trong phần "Thiết lập" trước đó trong lớp học lập trình này).
let billingProjectId = 'YOUR_PROJECT_ID';
let publicProjectId = 'bigquery-public-data';
let datasetId = 'new_york_taxi_trips';
let tableName = 'tlc_yellow_trips_2016';
Bây giờ, hãy thêm 2 hàm vào mã của bạn để tạo SQL và gửi truy vấn đến BigQuery bằng hàm sendQuery
mà bạn đã tạo ở bước trước.
Hàm đầu tiên phải được gọi là rectangleSQL()
và cần chấp nhận 2 đối số, một cặp đối tượng google.Maps.LatLng
biểu thị các góc của hình chữ nhật theo toạ độ trên bản đồ.
Hàm thứ hai phải được gọi là rectangleQuery()
. Thao tác này sẽ truyền văn bản truy vấn đến hàm sendQuery
.
let billingProjectId = 'YOUR_PROJECT_ID';
let publicProjectId = 'bigquery-public-data';
let datasetId = 'new_york';
let tableName = 'tlc_yellow_trips_2016';
function rectangleQuery(latLngBounds){
let queryString = rectangleSQL(latLngBounds.getNorthEast(), latLngBounds.getSouthWest());
sendQuery(queryString);
}
function rectangleSQL(ne, sw){
let queryString = 'SELECT pickup_latitude, pickup_longitude '
queryString += 'FROM `' + publicProjectId +'.' + datasetId + '.' + tableName + '`'
queryString += ' WHERE pickup_latitude > ' + sw.lat();
queryString += ' AND pickup_latitude < ' + ne.lat();
queryString += ' AND pickup_longitude > ' + sw.lng();
queryString += ' AND pickup_longitude < ' + ne.lng();
return queryString;
}
Đến đây, bạn đã có đủ mã để gửi một truy vấn đến BigQuery cho tất cả các hàng có trong hình chữ nhật do người dùng vẽ. Trước khi thêm các phương thức truy vấn khác cho hình tròn và hình dạng vẽ tự do, hãy xem cách xử lý dữ liệu nhận được từ một truy vấn.
10. Trực quan hoá câu trả lời
Các bảng BigQuery có thể rất lớn (hàng Petabyte dữ liệu) và có thể tăng thêm hàng trăm nghìn hàng mỗi giây. Vì vậy, điều quan trọng là bạn phải cố gắng hạn chế lượng dữ liệu được trả về để có thể vẽ dữ liệu đó trên bản đồ. Việc vẽ vị trí của mọi hàng trong một tập kết quả rất lớn (hàng chục nghìn hàng trở lên) sẽ dẫn đến bản đồ không đọc được. Có nhiều kỹ thuật để tổng hợp các vị trí trong cả truy vấn SQL và trên bản đồ, đồng thời bạn có thể giới hạn số lượng kết quả mà một truy vấn sẽ trả về.
Bạn có thể xem toàn bộ mã cho bước này trong step5/map.html.
Để giữ lượng dữ liệu được chuyển đến trang web của bạn ở mức hợp lý cho lớp học lập trình này, hãy sửa đổi hàm rectangleSQL()
để thêm một câu lệnh giới hạn phản hồi ở 10.000 hàng. Trong ví dụ bên dưới, điều này được chỉ định trong một biến chung có tên là recordLimit
, để tất cả các hàm truy vấn có thể sử dụng cùng một giá trị.
let recordLimit = 10000;
function rectangleSQL(ne, sw){
var queryString = 'SELECT pickup_latitude, pickup_longitude '
queryString += 'FROM `' + publicProjectId +'.' + datasetId + '.' + tableName + '`'
queryString += ' WHERE pickup_latitude > ' + sw.lat();
queryString += ' AND pickup_latitude < ' + ne.lat();
queryString += ' AND pickup_longitude > ' + sw.lng();
queryString += ' AND pickup_longitude < ' + ne.lng();
queryString += ' LIMIT ' + recordLimit;
return queryString;
}
Để hình dung mật độ của các vị trí, bạn có thể sử dụng bản đồ nhiệt. Maps JavaScript API có một lớp HeatmapLayer cho mục đích này. HeatmapLayer lấy một mảng gồm các toạ độ vĩ độ, kinh độ nên bạn có thể dễ dàng chuyển đổi các hàng được trả về từ truy vấn thành bản đồ nhiệt.
Trong hàm getQueryResults
, hãy truyền mảng response.result.rows
đến một hàm Javascript mới có tên là doHeatMap()
. Hàm này sẽ tạo một bản đồ nhiệt.
Mỗi hàng sẽ có một thuộc tính có tên là f
, đây là một mảng gồm các cột. Mỗi cột sẽ có một thuộc tính v
chứa giá trị.
Mã của bạn cần lặp qua các cột trong mỗi hàng và trích xuất các giá trị.
Trong truy vấn SQL, bạn chỉ yêu cầu các giá trị Vĩ độ và Kinh độ của điểm đón taxi, vì vậy, sẽ chỉ có 2 cột trong phản hồi.
Đừng quên gọi setMap()
trên lớp bản đồ nhiệt khi bạn đã chỉ định mảng vị trí cho lớp đó. Việc này sẽ giúp bạn nhìn thấy vị trí đó trên bản đồ.
Ví dụ:
function getQueryResults(jobId){
let request = gapi.client.bigquery.jobs.getQueryResults({
'projectId': billingProjectId,
'jobId': jobId
});
request.execute(response => doHeatMap(response.result.rows))
}
let heatmap;
function doHeatMap(rows){
let heatmapData = [];
if (heatmap != null){
heatmap.setMap(null);
}
for (let i = 0; i < rows.length; i++) {
let f = rows[i].f;
let coords = { lat: parseFloat(f[0].v), lng: parseFloat(f[1].v) };
let latLng = new google.maps.LatLng(coords);
heatmapData.push(latLng);
}
heatmap = new google.maps.visualization.HeatmapLayer({
data: heatmapData
});
heatmap.setMap(map);
}
Đến đây, bạn sẽ có thể:
- Mở trang và uỷ quyền cho BigQuery
- Vẽ một hình chữ nhật ở đâu đó tại Thành phố New York
- Xem kết quả truy vấn được trực quan hoá dưới dạng biểu đồ nhiệt.
Dưới đây là ví dụ về kết quả của một truy vấn hình chữ nhật đối với dữ liệu của Taxi màu vàng ở Thành phố New York năm 2016, được vẽ dưới dạng bản đồ nhiệt. Hình ảnh này cho thấy sự phân bố của các lượt đón khách quanh toà nhà Empire State vào một ngày thứ Bảy trong tháng 7:
11. Truy vấn theo bán kính xung quanh một điểm
Các truy vấn theo bán kính rất giống nhau. Khi sử dụng Hàm toán học trong SQL cũ của BigQuery, bạn có thể tạo một truy vấn SQL bằng Công thức Haversine để ước tính một vùng hình tròn trên bề mặt trái đất.
Bằng cách sử dụng cùng một kỹ thuật cho hình chữ nhật, bạn có thể xử lý sự kiện OverlayComplete
để lấy tâm và bán kính của một hình tròn do người dùng vẽ, đồng thời tạo SQL cho truy vấn theo cách tương tự.
Một ví dụ hoạt động về mã cho bước này có trong kho lưu trữ mã dưới dạng step6/map.html.
drawingManager.addListener('circlecomplete', circle => circleQuery(circle));
Trong bản sao index.html, hãy thêm 2 hàm trống mới: circleQuery()
và haversineSQL()
.
Sau đó, hãy thêm một trình xử lý sự kiện circlecomplete
để truyền tâm và bán kính đến một hàm mới có tên là circleQuery().
Hàm circleQuery()
sẽ gọi haversineSQL()
để tạo SQL cho truy vấn, sau đó gửi truy vấn bằng cách gọi hàm sendQuery()
theo mã ví dụ sau.
function circleQuery(circle){
let queryString = haversineSQL(circle.getCenter(), circle.radius);
sendQuery(queryString);
}
// Calculate a circular area on the surface of a sphere based on a center and radius.
function haversineSQL(center, radius){
let queryString;
let centerLat = center.lat();
let centerLng = center.lng();
let kmPerDegree = 111.045;
queryString = 'CREATE TEMPORARY FUNCTION Degrees(radians FLOAT64) RETURNS FLOAT64 LANGUAGE js AS ';
queryString += '""" ';
queryString += 'return (radians*180)/(22/7);';
queryString += '"""; ';
queryString += 'CREATE TEMPORARY FUNCTION Radians(degrees FLOAT64) RETURNS FLOAT64 LANGUAGE js AS';
queryString += '""" ';
queryString += 'return (degrees*(22/7))/180;';
queryString += '"""; ';
queryString += 'SELECT pickup_latitude, pickup_longitude '
queryString += 'FROM `' + publicProjectId +'.' + datasetId + '.' + tableName + '` ';
queryString += 'WHERE '
queryString += '(' + kmPerDegree + ' * DEGREES( ACOS( COS( RADIANS('
queryString += centerLat;
queryString += ') ) * COS( RADIANS( pickup_latitude ) ) * COS( RADIANS( ' + centerLng + ' ) - RADIANS('
queryString += ' pickup_longitude ';
queryString += ') ) + SIN( RADIANS('
queryString += centerLat;
queryString += ') ) * SIN( RADIANS( pickup_latitude ) ) ) ) ) ';
queryString += ' < ' + radius/1000;
queryString += ' LIMIT ' + recordLimit;
return queryString;
}
Hãy dùng thử!
Thêm mã ở trên và thử công cụ "Khoanh tròn" để chọn một khu vực trên bản đồ. Kết quả sẽ có dạng như sau:
12. Truy vấn các hình dạng tuỳ ý
Tóm tắt: SQL không hỗ trợ truy vấn bằng các hình dạng tuỳ ý ngoài hình chữ nhật và hình tròn. BigQuery không có kiểu dữ liệu hình học gốc, vì vậy, để chạy các truy vấn bằng hình đa giác, bạn cần một phương pháp khác cho các truy vấn SQL đơn giản.
Một tính năng rất mạnh mẽ của BigQuery mà bạn có thể sử dụng cho việc này là Hàm do người dùng xác định (UDF). UDF thực thi mã Javascript bên trong một truy vấn SQL.
Đoạn mã hoạt động cho bước này nằm trong step7/map.html.
UDF trong BigQuery API
Phương pháp BigQuery API cho UDF hơi khác so với bảng điều khiển web: bạn cần gọi jobs.insert method
.
Đối với các truy vấn SQL chuẩn thông qua API, bạn chỉ cần một câu lệnh SQL duy nhất để sử dụng Hàm do người dùng xác định. Bạn phải đặt giá trị của useLegacySql
thành false
. Ví dụ về JavaScript bên dưới cho thấy một hàm tạo và gửi đối tượng yêu cầu để chèn một công việc mới, trong trường hợp này là một truy vấn có Hàm do người dùng xác định.
Bạn có thể xem một ví dụ minh hoạ về phương pháp này trong step7/map.html.
function polygonQuery(polygon) {
let request = gapi.client.bigquery.jobs.insert({
'projectId' : billingProjectId,
'resource' : {
'configuration':
{
'query':
{
'query': polygonSql(polygon),
'useLegacySql': false
}
}
}
});
request.execute(response => checkJobStatus(response.jobReference.jobId));
}
Truy vấn SQL được tạo như sau:
function polygonSql(poly){
let queryString = 'CREATE TEMPORARY FUNCTION pointInPolygon(latitude FLOAT64, longitude FLOAT64) ';
queryString += 'RETURNS BOOL LANGUAGE js AS """ ';
queryString += 'var polygon=' + JSON.stringify(poly) + ';';
queryString += 'var vertx = [];';
queryString += 'var verty = [];';
queryString += 'var nvert = 0;';
queryString += 'var testx = longitude;';
queryString += 'var testy = latitude;';
queryString += 'for(coord in polygon){';
queryString += ' vertx[nvert] = polygon[coord][0];';
queryString += ' verty[nvert] = polygon[coord][1];';
queryString += ' nvert ++;';
queryString += '}';
queryString += 'var i, j, c = 0;';
queryString += 'for (i = 0, j = nvert-1; i < nvert; j = i++) {';
queryString += ' if ( ((verty[i]>testy) != (verty[j]>testy)) &&(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ){';
queryString += ' c = !c;';
queryString += ' }';
queryString += '}';
queryString += 'return c;';
queryString += '"""; ';
queryString += 'SELECT pickup_latitude, pickup_longitude, dropoff_latitude, dropoff_longitude, pickup_datetime ';
queryString += 'FROM `' + publicProjectId + '.' + datasetId + '.' + tableName + '` ';
queryString += 'WHERE pointInPolygon(pickup_latitude, pickup_longitude) = TRUE ';
queryString += 'LIMIT ' + recordLimit;
return queryString;
}
Có hai điều đang diễn ra ở đây. Trước tiên, mã này sẽ tạo câu lệnh CREATE TEMPORARY FUNCTION
để đóng gói mã JavaScript nhằm xác định xem một điểm nhất định có nằm trong đa giác hay không. Toạ độ đa giác được chèn bằng cách sử dụng lệnh gọi phương thức JSON.stringify(poly)
để chuyển đổi một mảng JavaScript gồm các cặp toạ độ x,y thành một chuỗi. Đối tượng đa giác được truyền dưới dạng đối số đến hàm tạo SQL.
Thứ hai, mã này tạo câu lệnh SQL SELECT
chính. UDF được gọi trong biểu thức WHERE
trong ví dụ này.
Tích hợp với Maps API
Để sử dụng tính năng này với thư viện vẽ Maps API, chúng ta cần lưu đa giác do người dùng vẽ và truyền đa giác này vào phần UDF của truy vấn SQL.
Trước tiên, chúng ta cần xử lý sự kiện vẽ polygoncomplete
để lấy toạ độ của hình dạng dưới dạng một mảng gồm các cặp kinh độ và vĩ độ:
drawingManager.addListener('polygoncomplete', polygon => {
let path = polygon.getPaths().getAt(0);
let queryPolygon = path.map(element => {
return [element.lng(), element.lat()];
});
polygonQuery(queryPolygon);
});
Sau đó, hàm polygonQuery
có thể tạo các hàm Javascript UDF dưới dạng một chuỗi, cũng như câu lệnh SQL sẽ gọi hàm UDF.
Hãy xem step7/map.html để biết ví dụ minh hoạ về cách hoạt động của tính năng này.
Kết quả ví dụ
Dưới đây là một ví dụ về kết quả truy vấn địa điểm đón khách từ Dữ liệu về taxi màu vàng của TLC ở Thành phố New York năm 2016 trong BigQuery bằng cách sử dụng đa giác vẽ tự do, với dữ liệu đã chọn được vẽ dưới dạng bản đồ nhiệt.
13. Vươn xa hơn
Dưới đây là một số đề xuất về cách mở rộng lớp học lập trình này để xem xét các khía cạnh khác của dữ liệu. Bạn có thể tìm thấy ví dụ minh hoạ về những ý tưởng này tại step8/map.html trong kho lưu trữ mã.
Liên kết điểm trả xe
Cho đến nay, chúng tôi chỉ lập bản đồ các vị trí nhận hàng. Bằng cách yêu cầu các cột dropoff_latitude
và dropoff_longitude
, đồng thời sửa đổi mã bản đồ nhiệt để vẽ các cột này, bạn có thể xem đích đến của các chuyến đi taxi bắt đầu tại một vị trí cụ thể.
Ví dụ: hãy xem taxi thường trả khách ở đâu khi họ yêu cầu đón khách quanh Toà nhà Empire State.
Thay đổi mã cho câu lệnh SQL trong polygonSql()
để yêu cầu các cột này ngoài vị trí lấy hàng.
function polygonSql(poly){
let queryString = 'CREATE TEMPORARY FUNCTION pointInPolygon(latitude FLOAT64, longitude FLOAT64) ';
queryString += 'RETURNS BOOL LANGUAGE js AS """ ';
queryString += 'var polygon=' + JSON.stringify(poly) + ';';
queryString += 'var vertx = [];';
queryString += 'var verty = [];';
queryString += 'var nvert = 0;';
queryString += 'var testx = longitude;';
queryString += 'var testy = latitude;';
queryString += 'for(coord in polygon){';
queryString += ' vertx[nvert] = polygon[coord][0];';
queryString += ' verty[nvert] = polygon[coord][1];';
queryString += ' nvert ++;';
queryString += '}';
queryString += 'var i, j, c = 0;';
queryString += 'for (i = 0, j = nvert-1; i < nvert; j = i++) {';
queryString += ' if ( ((verty[i]>testy) != (verty[j]>testy)) &&(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ){';
queryString += ' c = !c;';
queryString += ' }';
queryString += '}';
queryString += 'return c;';
queryString += '"""; ';
queryString += 'SELECT pickup_latitude, pickup_longitude, dropoff_latitude, dropoff_longitude, pickup_datetime ';
queryString += 'FROM `' + publicProjectId + '.' + datasetId + '.' + tableName + '` ';
queryString += 'WHERE pointInPolygon(pickup_latitude, pickup_longitude) = TRUE ';
queryString += 'LIMIT ' + recordLimit;
return queryString;
}
Sau đó, hàm doHeatMap
có thể dùng các giá trị giảm thay thế. Đối tượng kết quả có một giản đồ mà bạn có thể kiểm tra để tìm vị trí của các cột này trong mảng. Trong trường hợp này, các phần tử đó sẽ ở vị trí chỉ mục 2 và 3. Bạn có thể đọc các chỉ mục này từ một biến để dễ quản lý mã hơn. Xin lưu ý rằng maxIntensity
của bản đồ nhiệt được đặt để hiển thị mật độ tối đa là 20 lượt bỏ qua trên mỗi pixel.
Thêm một số biến để cho phép bạn thay đổi cột mà bạn dùng cho dữ liệu bản đồ nhiệt.
// Show query results as a Heatmap.
function doHeatMap(rows){
let latCol = 2;
let lngCol = 3;
let heatmapData = [];
if (heatmap!=null){
heatmap.setMap(null);
}
for (let i = 0; i < rows.length; i++) {
let f = rows[i].f;
let coords = { lat: parseFloat(f[latCol].v), lng: parseFloat(f[lngCol].v) };
let latLng = new google.maps.LatLng(coords);
heatmapData.push(latLng);
}
heatmap = new google.maps.visualization.HeatmapLayer({
data: heatmapData,
maxIntensity: 20
});
heatmap.setMap(map);
}
Đây là bản đồ nhiệt cho thấy sự phân bố của các điểm trả khách từ tất cả các điểm đón khách ngay xung quanh toà nhà Empire State vào năm 2016. Bạn có thể thấy mật độ cao (các đốm màu đỏ) của các điểm đến ở khu Midtown, đặc biệt là xung quanh Quảng trường Thời đại, cũng như dọc theo Đại lộ số 5 giữa đường số 23 và đường số 14. Các địa điểm có mật độ cao khác không xuất hiện ở mức thu phóng này bao gồm sân bay La Guardia và JFK, Trung tâm Thương mại Thế giới và Công viên Battery.
Tạo kiểu cho bản đồ cơ sở
Khi tạo Google Maps bằng Maps JavaScript API, bạn có thể đặt kiểu bản đồ bằng đối tượng JSON. Đối với hình ảnh trực quan hoá dữ liệu, bạn nên tắt màu trong bản đồ. Bạn có thể tạo và dùng thử các kiểu bản đồ bằng Trình hướng dẫn tạo kiểu của API Google Maps tại mapstyle.withgoogle.com.
Bạn có thể đặt kiểu bản đồ khi khởi tạo một đối tượng bản đồ hoặc vào bất kỳ thời điểm nào sau đó. Dưới đây là cách thêm kiểu tuỳ chỉnh trong hàm initMap()
:
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 40.744593, lng: -73.990370}, // Manhattan, New York.
zoom: 12,
styles: [
{
"elementType": "geometry",
"stylers": [
{
"color": "#f5f5f5"
}
]
},
{
"elementType": "labels.icon",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "water",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
}
]
});
setUpDrawingTools();
}
Kiểu mẫu bên dưới cho thấy một bản đồ thang độ xám có nhãn địa điểm yêu thích.
[
{
"elementType": "geometry",
"stylers": [
{
"color": "#f5f5f5"
}
]
},
{
"elementType": "labels.icon",
"stylers": [
{
"visibility": "on"
}
]
},
{
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#616161"
}
]
},
{
"elementType": "labels.text.stroke",
"stylers": [
{
"color": "#f5f5f5"
}
]
},
{
"featureType": "administrative.land_parcel",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#bdbdbd"
}
]
},
{
"featureType": "poi",
"elementType": "geometry",
"stylers": [
{
"color": "#eeeeee"
}
]
},
{
"featureType": "poi",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#757575"
}
]
},
{
"featureType": "poi.park",
"elementType": "geometry",
"stylers": [
{
"color": "#e5e5e5"
}
]
},
{
"featureType": "poi.park",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
},
{
"featureType": "road",
"elementType": "geometry",
"stylers": [
{
"color": "#ffffff"
}
]
},
{
"featureType": "road.arterial",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#757575"
}
]
},
{
"featureType": "road.highway",
"elementType": "geometry",
"stylers": [
{
"color": "#dadada"
}
]
},
{
"featureType": "road.highway",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#616161"
}
]
},
{
"featureType": "road.local",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
},
{
"featureType": "transit.line",
"elementType": "geometry",
"stylers": [
{
"color": "#e5e5e5"
}
]
},
{
"featureType": "transit.station",
"elementType": "geometry",
"stylers": [
{
"color": "#eeeeee"
}
]
},
{
"featureType": "water",
"elementType": "geometry",
"stylers": [
{
"color": "#c9c9c9"
}
]
},
{
"featureType": "water",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
}
]
Đưa ra ý kiến phản hồi cho người dùng
Mặc dù BigQuery thường phản hồi trong vài giây, nhưng đôi khi bạn nên cho người dùng biết rằng đang có hoạt động diễn ra trong khi truy vấn đang chạy.
Thêm một số giao diện người dùng vào trang web của bạn để cho thấy phản hồi của hàm checkJobStatus()
và một hình ảnh động để cho biết rằng truy vấn đang diễn ra.
Thông tin bạn có thể hiển thị bao gồm thời lượng truy vấn, lượng dữ liệu được trả về và lượng dữ liệu được xử lý.
Thêm một số HTML sau <div>
bản đồ để tạo một bảng điều khiển cho trang. Bảng điều khiển này sẽ cho biết số lượng hàng mà một truy vấn trả về, thời gian truy vấn mất và lượng dữ liệu được xử lý.
<div id="menu">
<div id="stats">
<h3>Statistics:</h3>
<table>
<tr>
<td>Total Locations:</td><td id="rowCount"> - </td>
</tr>
<tr>
<td>Query Execution:</td><td id="duration"> - </td>
</tr>
<tr>
<td>Data Processed:</td><td id="bytes"> - </td>
</tr>
</table>
</div>
</div>
Giao diện và vị trí của bảng điều khiển này do CSS kiểm soát. Thêm CSS để đặt bảng điều khiển ở góc trên cùng bên trái của trang bên dưới các nút loại bản đồ và thanh công cụ vẽ như trong đoạn mã bên dưới.
#menu {
position: absolute;
background: rgba(255, 255, 255, 0.8);
z-index: 1000;
top: 50px;
left: 10px;
padding: 15px;
}
#menu h1 {
margin: 0 0 10px 0;
font-size: 1.75em;
}
#menu div {
margin: 5px 0px;
}
Bạn có thể thêm đồ hoạ động vào trang nhưng ẩn đi cho đến khi cần, đồng thời sử dụng một số mã JavaScript và CSS để hiện đồ hoạ đó khi một công việc BigQuery đang chạy.
Thêm một số mã HTML để hiển thị một hình ảnh động. Có một tệp hình ảnh có tên là loader.gif
trong thư mục img
trong kho lưu trữ mã.
<img id="spinner" src="img/loader.gif">
Thêm một số CSS để định vị hình ảnh và ẩn hình ảnh theo mặc định cho đến khi cần.
#spinner {
position: absolute;
top: 50%;
left: 50%;
margin-left: -32px;
margin-top: -32px;
opacity: 0;
z-index: -1000;
}
Cuối cùng, hãy thêm một số JavaScript để cập nhật bảng điều khiển trạng thái và hiện hoặc ẩn đồ hoạ khi một truy vấn đang chạy. Bạn có thể dùng đối tượng response
để cập nhật bảng điều khiển tuỳ theo thông tin có sẵn.
Khi kiểm tra một công việc hiện tại, bạn có thể sử dụng thuộc tính response.statistics
. Khi công việc hoàn tất, bạn có thể truy cập vào các thuộc tính response.totalRows
và response.totalBytesProcessed
. Việc chuyển đổi mili giây thành giây và byte thành gigabyte để hiển thị là hữu ích cho người dùng, như minh hoạ trong mẫu mã bên dưới.
function updateStatus(response){
if(response.statistics){
let durationMs = response.statistics.endTime - response.statistics.startTime;
let durationS = durationMs/1000;
let suffix = (durationS ==1) ? '':'s';
let durationTd = document.getElementById("duration");
durationTd.innerHTML = durationS + ' second' + suffix;
}
if(response.totalRows){
let rowsTd = document.getElementById("rowCount");
rowsTd.innerHTML = response.totalRows;
}
if(response.totalBytesProcessed){
let bytesTd = document.getElementById("bytes");
bytesTd.innerHTML = (response.totalBytesProcessed/1073741824) + ' GB';
}
}
Gọi phương thức này khi có phản hồi cho lệnh gọi checkJobStatus()
và khi kết quả truy vấn được tìm nạp. Ví dụ:
// Poll a job to see if it has finished executing.
function checkJobStatus(jobId){
let request = gapi.client.bigquery.jobs.get({
'projectId': billingProjectId,
'jobId': jobId
});
request.execute(response => {
//Show progress to the user
updateStatus(response);
if (response.status.errorResult){
// Handle any errors.
console.log(response.status.error);
return;
}
if (response.status.state == 'DONE'){
// Get the results.
clearTimeout(jobCheckTimer);
getQueryResults(jobId);
return;
}
// Not finished, check again in a moment.
jobCheckTimer = setTimeout(checkJobStatus, 500, [jobId]);
});
}
// When a BigQuery job has completed, fetch the results.
function getQueryResults(jobId){
let request = gapi.client.bigquery.jobs.getQueryResults({
'projectId': billingProjectId,
'jobId': jobId
});
request.execute(response => {
doHeatMap(response.result.rows);
updateStatus(response);
})
}
Để bật/tắt ảnh động, hãy thêm một hàm để kiểm soát chế độ hiển thị của ảnh động. Hàm này sẽ bật/tắt độ mờ của mọi Phần tử DOM HTML được truyền đến hàm.
function fadeToggle(obj){
if(obj.style.opacity==1){
obj.style.opacity = 0;
setTimeout(() => {obj.style.zIndex = -1000;}, 1000);
} else {
obj.style.zIndex = 1000;
obj.style.opacity = 1;
}
}
Cuối cùng, hãy gọi phương thức này trước khi xử lý một truy vấn và sau khi kết quả truy vấn được trả về từ BigQuery.
Mã này gọi hàm fadeToggle
khi người dùng đã vẽ xong một hình chữ nhật.
drawingManager.addListener('rectanglecomplete', rectangle => {
//show an animation to indicate that something is happening.
fadeToggle(document.getElementById('spinner'));
rectangleQuery(rectangle.getBounds());
});
Khi nhận được phản hồi truy vấn, hãy gọi lại fadeToggle()
để ẩn hình ảnh động.
// When a BigQuery job has completed, fetch the results.
function getQueryResults(jobId){
let request = gapi.client.bigquery.jobs.getQueryResults({
'projectId': billingProjectId,
'jobId': jobId
});
request.execute(response => {
doHeatMap(response.result.rows);
//hide the animation.
fadeToggle(document.getElementById('spinner'));
updateStatus(response);
})
}
Trang này sẽ có dạng như sau.
Hãy xem ví dụ đầy đủ trong step8/map.html.
14. Những điều cần cân nhắc
Quá nhiều điểm đánh dấu
Nếu bạn đang làm việc với các bảng rất lớn, truy vấn của bạn có thể trả về quá nhiều hàng để hiển thị hiệu quả trên bản đồ. Giới hạn kết quả bằng cách thêm mệnh đề WHERE
hoặc câu lệnh LIMIT
.
Việc vẽ nhiều điểm đánh dấu có thể khiến bản đồ khó đọc. Hãy cân nhắc sử dụng HeatmapLayer
để cho biết mật độ hoặc sử dụng điểm đánh dấu cụm để cho biết vị trí của nhiều điểm dữ liệu bằng một biểu tượng duy nhất cho mỗi cụm. Bạn có thể xem thêm thông tin chi tiết trong hướng dẫn về Cụm điểm đánh dấu của chúng tôi.
Tối ưu hoá truy vấn
BigQuery sẽ quét toàn bộ bảng với mọi truy vấn. Để tối ưu hoá việc sử dụng hạn mức BigQuery, hãy chỉ chọn những cột bạn cần trong truy vấn.
Truy vấn sẽ nhanh hơn nếu bạn lưu trữ vĩ độ và kinh độ dưới dạng số thực thay vì chuỗi.
Xuất kết quả thú vị
Các ví dụ ở đây yêu cầu người dùng cuối phải được xác thực dựa trên bảng BigQuery, điều này sẽ không phù hợp với mọi trường hợp sử dụng. Khi đã khám phá ra một số mẫu thú vị, bạn có thể dễ dàng chia sẻ những mẫu này với nhiều người hơn bằng cách xuất kết quả từ BigQuery và tạo một tập dữ liệu tĩnh bằng Lớp dữ liệu của Google Maps.
Phần pháp lý nhàm chán
Hãy lưu ý Điều khoản dịch vụ của Nền tảng Google Maps. Để biết thêm thông tin về giá của Nền tảng Google Maps, hãy xem tài liệu trực tuyến.
Chơi với nhiều dữ liệu hơn!
Có một số tập dữ liệu công khai trong BigQuery có các cột vĩ độ và kinh độ, chẳng hạn như tập dữ liệu về Taxi ở Thành phố New York từ năm 2009 đến năm 2016, dữ liệu về chuyến đi của Uber và Lyft ở Thành phố New York và tập dữ liệu GDELT.
15. Xin chúc mừng!
Chúng tôi hy vọng hướng dẫn này sẽ giúp bạn nhanh chóng bắt đầu sử dụng một số truy vấn địa lý đối với các bảng BigQuery để có thể khám phá các mẫu và trực quan hoá chúng trên Google Maps. Chúc bạn lập bản đồ vui vẻ!
Tiếp theo là gì?
Nếu bạn muốn tìm hiểu thêm về Nền tảng Google Maps hoặc BigQuery, hãy xem các đề xuất sau.
Hãy xem phần BigQuery là gì để tìm hiểu thêm về dịch vụ kho dữ liệu không máy chủ ở quy mô petabyte của Google.
Hãy xem hướng dẫn cách tạo một ứng dụng đơn giản bằng BigQuery API.
Hãy xem hướng dẫn cho nhà phát triển về thư viện vẽ để biết thêm thông tin chi tiết về cách cho phép người dùng tương tác để vẽ các hình dạng trên Google Maps.
Hãy xem những cách khác để trực quan hoá dữ liệu trên Google Maps.
Hãy xem Hướng dẫn bắt đầu sử dụng API ứng dụng Javascript để hiểu các khái niệm cơ bản về cách sử dụng API ứng dụng để truy cập vào các API khác của Google.