Truy vấn và trực quan hóa dữ liệu vị trí trong BigQuery bằng Nền tảng Google Maps (JavaScript)

Truy vấn và trực quan hóa dữ liệu vị trí trong BigQuery bằng Nền tảng Google Maps (JavaScript)

Thông tin về lớp học lập trình này

subjectLần cập nhật gần đây nhất: thg 12 3, 2021
account_circleTác giả: Google Maps Platform Team

1. Tổng quan

Maps có thể là một công cụ rất hữu ích khi trực quan hóa các mẫu trong tập dữ liệu liên quan đến vị trí theo 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ư đường dân số hoặc mã bưu chính.

Khi những tập dữ liệu này rất lớn, chúng có thể khó truy vấn và trực quan hóa 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à API Google Maps để xây dựng truy vấn và trực quan hóa kết quả, bạn có thể nhanh chóng khám phá các mẫu địa lý trong dữ liệu của mình với rất ít thiết lập hoặc mã hóa và 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 họa cách cung cấp thông tin chi tiết dựa trên vị trí vào các tập dữ liệu công khai rất lớn bằng BigQuery. Bạn cũng sẽ xây dựng một trang web tải bản đồ bằng cách sử dụng API JavaScript của Nền tảng Google Maps, sau đó chạy và trực quan hóa 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 API của Google cho JavaScriptAPI BigQuery.

Kiến thức bạn sẽ học được

  • Cách truy vấn tập dữ liệu vị trí theo tỷ lệ petabyte tính bằng giây với BigQuery, bằng cách sử dụng truy vấn SQL, Hàm do người dùng xác định API BigQuery
  • 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ẽ các hình trên đó
  • Cách trực quan hóa truy vấn dựa trên các tập dữ liệu lớn trên Google Maps như trong hình minh họa bên dưới, cho thấy mật độ điểm thả taxi trong năm 2016 từ các hành trình bắt đầu từ khối xung quanh Tòa nhà Empire State.

Ảnh chụp màn hình lúc 11/05/2017 05-09 - 11/01/2017

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 cho các tập dữ liệu rất lớn. Ứng dụng 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 về 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á một cách trực quan các tập dữ liệu rất lớn để xem các mẫu mà không 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 lớn đến mức nào bằng cách sử dụng cơ sở hạ tầng có khả năng mở rộng và quản lý khổng lồ của BigQuery.

Nền tảng Google Maps

Nền tảng Google Maps cung cấp quyền truy cập 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 dùng để cung cấp bản đồ và các truy vấn dựa trên vị trí được nhúng cho người dùng.

Lớp vẽ API JavaScript của Google Maps Platform cho phép bạn vẽ hình dạng trên bản đồ. Bạn có thể chuyển đổi chúng thành dữ liệu đầu vào để chạy truy vấn dựa trên các bảng BigQuery có lưu trữ giá trị vĩ độ và kinh độ trong cột.

Để bắt đầu, bạn cần có một dự án Google Cloud Platform đã bật API BigQuery và Maps.

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), thì 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 của Google Cloud Platform ( console.cloud.google.com) và tạo một dự án mới. Ở đầu màn hình, bạn có trình đơn thả xuống Dự án:

f2a353c3301dc649.png

Sau khi nhấp vào trình đơn thả xuống dự án này, bạn sẽ nhận được một mục trình đơn cho phép bạn tạo dự án mới:

56a42dfa7ac27a35.png

Trong hộp có nội dung "quot; Nhập tên mới cho dự án của bạn " nhập tên cho dự án mới, ví dụ &&tt;BigQuery Codelab":

Codelab – tạo dự án (1).png

Mã dự án sẽ được tạo cho bạn. Mã dự án là một tên riêng biệt trên tất cả các dự án Google Cloud. Hãy nhớ Mã dự án vì như sau bạn sẽ dùng. Tên ở trên đã được sử dụng và sẽ không hoạt động cho bạn. Hãy chèn mã 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 đã chọn hoặc tạo ở bước trước. Thanh toán phải được bật trên dự án này. Sau khi bật tùy chọn thanh toán, bạn có thể bật API BigQuery.

Cách bạn bật tính năng thanh toán tùy thuộc vào việc bạn đang tạo dự án mới hay bạn đang bật lại tính năng thanh toán cho một dự án hiện tại.

Google cung cấp bản dùng thử miễn phí 12 tháng với mức sử dụng Google Cloud Platform trị giá lên tới 300 đô la mà bạn có thể sử dụng cho Lớp học mã này, tìm hiểu thêm chi tiết tại https://cloud.google.com/free/.

Dự án mới

Khi tạo 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, thì 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 trước khi có thể sử dụng nhiều tính năng của Google Cloud Platform. Để tạo 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 bài viết Tạo tài khoản thanh toán mới.

Dự án hiện có

Nếu bạn có dự án mà bạn tạm thời vô hiệu hóa thanh toán, bạn có thể bật lại thanh toán:

  1. Chuyển đến Bảng điều khiển Cloud Platform.
  2. Từ danh sách dự án, hãy chọn dự án để bật lại tùy chọn thanh toán.
  3. Mở trình đơn bên trái của bảng điều khiển, rồi chọn Thanh toán Thanh toán. Bạn sẽ được nhắc chọn tài khoản thanh toán.
  4. Nhấp vào Đặt 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:

  1. Hãy truy cập Bảng điều khiển Cloud Platform và đăng nhập hoặc nếu bạn chưa có tài khoản, hãy đăng ký.
  2. Mở trình đơn bên trái của bảng điều khiển, rồi chọn Thanh toán Thanh toán
  3. 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, 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.)
  4. Nhập tên của tài khoản thanh toán và nhập thông tin thanh toán. Các tùy chọn bạn thấy tùy thuộc vào quốc gia trong địa chỉ thanh toán của bạn. Xin lưu ý rằng đối với tài khoản tại Hoa Kỳ, bạn không thể thay đổi trạng thái thuế sau khi tạo tài khoản.
  5. Nhấp vào Gửi và bật thanh toán.

Theo mặc định, người tạo tài khoản thanh toán là một 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 phần Thêm, xóa hoặc cập nhật phương thức thanh toán.

Bật API BigQuery

Để bật API BigQuery trong dự án của bạn, hãy truy cập Trang web dành cho API BigQuery trong bảng điều khiển và nhấp vào nút "Bật\39"; màu xanh dương.

3. Truy vấn dữ liệu vị trí trong BigQuery

Có ba cách để truy vấn dữ liệu vị trí được lưu trữ dưới dạng vĩ độ, giá trị kinh độ trong BigQuery.

  • Truy vấn hình chữ nhật: chỉ định khu vực quan tâm làm truy vấn chọn tất cả các hàng trong phạm vi kinh độ và vĩ độ tối thiểu và tối đa.
  • Truy vấn bán kính: chỉ định khu vực quan tâm bằng cách tính toán một vòng tròn quanh một điểm bằng cách sử dụng công thức Haversine và các hàm Toán học để lập mô hình hình dạng của trái đất.
  • Truy vấn đa giác: chỉ định hình dạng tùy chỉnh và sử dụng Hàm do người dùng xác định để thể hiện logic điểm tại đa giác cần thiết để kiểm tra xem vĩ độ và kinh độ của mỗi hàng có nằm bên 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 mục Big Query của bảng điều khiển Google Cloud Platform để chạy các truy vấn sau dựa trên dữ liệu về taxi ở New York.

SQL chuẩn so với SQL cũ

BigQuery hỗ trợ hai phiên bản SQL: Legacy SQLStandard SQL. Sau đó là tiêu chuẩn ANSI 2011. Trong mục đích của hướng dẫn này, chúng tôi sẽ sử dụng SQL chuẩn vì trang này có tuân thủ 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ể thực hiện như sau:

  1. Nhấp vào nút "Thêm#39";
  2. Chọn "Cài đặt truy vấn#39; từ trình đơn thả xuống
  3. Trong phần "Phương ngữ SQL\39;", hãy chọn nút chọn "Cũ"
  4. Nhấp vào nút "Lưu\39";

Truy vấn hình chữ nhật

Các truy vấn hình chữ nhật khá dễ tạo trong BigQuery. Bạn chỉ cần thêm một mệnh đề WHERE để giới hạn kết quả được 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 về vĩ độ và kinh độ.

Hãy xem ví dụ bên dưới trong bảng điều khiển của BigQuery. Truy vấn này dựa trên số liệu thống kê về chuyến đi trung bình cho các chuyến đi bắt đầu trong một khu vực hình chữ nhật có chứa khu vực trung tâm và khu Manhattan thấp hơn. Bạn có thể thử hai vị trí khác nhau, không giải thích được mệnh đề WHERE thứ hai để thực hiện truy vấn về 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ả cho hai cụm từ tìm kiếm này cho thấy có sự khác biệt lớn về khoảng cách trung bình, giá vé và mẹo để nhận xe ở hai địa điểm này.

thành phố Hathattan

avg_Mẹo

avg_fare

ở khoảng cách trung bình

avg_snippet_pc

avg_fare_mile

2,52

12,03

9,97

22,39

5,97

JFK

avg_Mẹo

avg_fare

ở khoảng cách trung bình

avg_snippet_pc

avg_fare_mile

9.22

48,49

41,19

22,48

4,36

Truy vấn bán kính

Truy vấn bán kính cũng dễ tạo trong SQL nếu bạn biết một chút về toán học. Bằng cách sử dụng các hàm Toán học cũ của BigQuery\39; bạn có thể tạo một truy vấn SQL bằng Công thức Haversine, giúp tính gần đúng diện tích hình tròn hoặc nắp hình cầu trên bề mặt trái đất.

Đây là một ví dụ về BigQuery SQL dành cho truy vấn vòng tròn có tâm là 40.73943, -73.99585 với bán kính 0,1 km.

Ứng dụng này sử dụng một giá trị không đổi là 111,045 km để ước tính khoảng cách thể hiện bằng một độ.

Dựa trên ví dụ này tại http://www.plumislandmedia.net/mysql/haversine-mysql-gầnest-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 tọa độ trung tâm vòng tròn, bán kính và tên dự án, tập dữ liệu và bảng cho BigQuery.

Đây là một truy vấn mẫu sẽ tính toán một số số liệu thống kê về chuyến đi trung bình cho các đơn đặt hàng tự đến lấy trong phạm vi 100m của Tòa nhà Empire State. Sao chép và dán tên 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 như vị trí tại 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

Dưới đây là kết quả của truy vấn. Bạn có thể thấy có sự khác biệt lớn về giá vé trung bình, giá vé, khoảng cách chuyến đi, kích thước tương ứng của tiền boa với giá vé và giá vé trung bình cho mỗi dặm lái xe.

Tòa nhà Empire State:

avg_Mẹo

avg_fare

ở khoảng cách trung bình

avg_snippet_pc

avg_fare_mile

1,17

11,08

45,28

10,53

6,42

Bronx

avg_Mẹo

avg_fare

ở khoảng cách trung bình

avg_snippet_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 tùy ý ngoài hình chữ nhật và hình tròn. BigQuery không có loại dữ liệu hình học gốc hoặc chỉ mục không gian nào, vì vậy để chạy truy vấn bằng cách sử dụng các hình đa giác, bạn cần một phương pháp khác để truy vấn SQL đơn giản. Một phương pháp bạn có thể sử dụng là xác định một hàm hình học trong JavaScript và thực thi hàm này dưới dạng Hàm do người dùng xác định (UDF) trong BigQuery.

Nhiều thao tác hình học có thể được viết bằng JavaScript để dễ dàng thực hiện và thực thi dựa trên bảng BigQuery chứa các giá trị vĩ độ và kinh độ. Bạn cần chuyển đa giác tùy chỉnh qua UDF và kiểm tra từng hàng, chỉ trả về các 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 về BigQuery.

Thuật toán trỏ vào đa giác

Có nhiều cách để tính toán liệu một điểm có nằm trong một đa giác trong JavaScript hay không. Đây là một cổng từ C của quy trình triển khai nổi tiếng sử dụng thuật toán theo dõi tia để xác định xem một điểm nằm bên trong hay bên ngoài một đa giác bằng cách tính số lần một đường thẳng dài vô hạn vượt qua ranh giới của hình dạng. Tính năng này chỉ chiếm 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 trông giố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 tiếp cận UDF chỉ yêu cầu một câu lệnh duy nhất, nhưng UDF phải được định nghĩa là một hàm tạm thời trong câu lệnh. Dưới đây là 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!

Bạn hiện đã chạy ba 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ả cho truy vấn so với tập dữ liệu này, nhưng trừ khi bạn đoán vị trí chạy truy vấn, thật khó để khám phá các mẫu không gian đặc biệt chỉ bằng truy vấn SQL.

Nếu chỉ có thể hình ảnh hóa dữ liệu trên bản đồ và khám phá dữ liệu, hãy xác định các khu vực ưa thích tùy ý! Được rồi, bạn có thể làm việc này bằng API Google Maps. Trước tiên, bạn cần bật API Maps, thiết lập một trang web đơn giản chạy trên máy cục bộ của mình và bắt đầu sử dụng API BigQuery để gửi các cụm từ tìm kiếm trên trang web đó.

4. Làm việc với API Google Maps

Có một số truy vấn đơn giản về không gian, bước tiếp theo là trực quan hóa kết quả để xem các mẫu. Để làm điều này, bạn sẽ bật API Maps, tạo một trang web gửi các truy vấn từ một bản đồ đến BigQuery, sau đó vẽ kết quả trên bản đồ.

Bật API JavaScript của Maps

Đối với Lớp học lập trình này, bạn sẽ cần bật API JavaScript của Maps trên Nền tảng Google Maps 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:

  1. Trong bảng điều khiển của Google Cloud Platform, hãy truy cập vào Thị trường
  2. Trong Thị trường, hãy tìm kiếm "API JavaScript của Maps#39";
  3. Nhấp vào ô cho API JavaScript của Maps trong kết quả tìm kiếm
  4. Nhấp vào nút "Bật\39";

Tạo khóa API

Để đưa ra yêu cầu cho Nền tảng Google Maps, bạn cần phải tạo một khóa API và gửi khóa đó với tất cả các yêu cầu. Để tạo một khóa API, hãy làm như sau:

  1. Trong bảng điều khiển của Google Cloud Platform, hãy nhấp vào trình đơn hamburger để mở bảng điều hướng bên trái
  2. Chọn "API & amp; Dịch vụ\39; > "Thông tin xác thực#39;
  3. Nhấp vào nút "Tạo thông tin xác thực#39"; rồi chọn "Khóa API#39";
  4. Sao chép khóa API mới

Tải mã xuống và thiết lập máy chủ web

Nhấp vào nút sau để tải tất cả mã xuống 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 thư mục gốc (bigquery), trong đó có một thư mục cho mỗi bước của lớp học mã này, cùng với tất cả tài nguyên mà bạn cần.

Các thư mục stepN chứa trạng thái kết thúc mong muốn của từng bước trong lớp học lập trình này. Bạn có thể tham khảo ở đây. Chúng ta sẽ thực hiện tất cả công việc mã hóa trong thư mục có tên work.

Thiết lập máy chủ web cục bộ

Mặc dù bạn có thể 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 tốt với Máy chủ web Chrome. Nếu bạn chưa cài đặt ứng dụng đó, bạn có thể cài đặt ứng dụng 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:

  1. Mở Chrome
  2. Trong thanh địa chỉ ở trên cùng, hãy nhập chrome://apps
  3. Nhấn Enter
  4. 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, toàn màn hình hoặc cửa sổ mới a3ed00e79b8bfee7.png Bạn sẽ thấy hộp thoại này tiếp theo, cho phép bạn định cấu hình máy chủ web cục bộ: 81b6151c3f60c948.png
  5. Nhấp vào "CHOOSE l bản giây" rồi chọn vị trí mà bạn đã tải các tệp mẫu lớp học xuống
  6. Trong phần "Tùy chọn\39;", hãy chọn hộp bên cạnh "Tự động hiển thị index.html×39;: 17f4913500faa86f.png
  7. Trượt nút bật/tắt có nhãn "Máy chủ web: BẮT ĐẦU#39; sang trái, sau đó quay lại bên phải để dừng rồi khởi động lại máy chủ web

a5d554d0d4a91851.png

5. Tải công cụ bản đồ và bản vẽ

Tạo một trang bản đồ cơ bản

Bắt đầu với một trang HTML đơn giản tải Google Maps bằng cách sử dụng API JavaScript của Maps và một vài dòng JavaScript. Mã từ Mẫu bản đồ đơn giản của Nền tảng Google Maps là một cách tuyệt vời để bắt đầu. Phần này được sao chép vào đây để bạn sao chép và dán vào trình chỉnh sửa văn bản hoặc IDE mà bạn chọn. Bạn cũng có thể tìm tệp này bằng cách mở index.html từ kho lưu trữ mà bạn đã tải xuống.

  1. Sao chép index.html vào thư mục work trong bản sao cục bộ của kho lưu trữ
  2. Sao chép thư mục img/ áp dụng vào thư mục công việc/ thư mục trong bản sao cục bộ của kho lưu trữ
  3. Mở tác vụ/index.html trong trình chỉnh sửa văn bản hoặc IDE
  4. Thay thế YOUR_API_KEY bằng khóa 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>
  1. 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 các bản đồ đầu tiên của mình được hiển thị.

Nếu bạn nhận được thông báo lỗi trong trình duyệt, hãy kiểm tra xem khóa API của bạn có chính xác không và máy chủ web cục bộ có đang hoạt động không.

Thay đổi vị trí và mức thu phóng mặc định

Mã thiết lập vị trí và mức thu phóng nằm trên dòng 27 & 28 của index.html và hiện 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 taxi BigQuery cho New York, vì vậy, tiếp theo bạn sẽ thay đổi mã khởi tạo bản đồ để căn giữa ở một vị trí trong thành phố New York ở mức thu phóng phù 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 phần sau để căn giữa bản đồ trên 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, tải lại bản đồ trong trình duyệt của bạn để xem kết quả.

Tải thư viện bản vẽ và hình ảnh trực quan

Để thêm tính năng vẽ vào bản đồ của 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 thông số không bắt buộc cho biết Google Maps Platform 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 hình ảnh trực quan. Để làm việc này, hãy thêm thông số libraries, cũng như chỉ định các thư viện visualizationdrawing làm giá trị được phân tách bằng dấu phẩy, ví dụ: libraries=visualization,drawing

Phần khai báo sẽ có dạng 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, khi công cụ Circle, RectanglePolygon đượ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:

  1. Thêm một hàm có tên là setUpDrawingTools()với mã sau để tạo DrawingManager và đặt thuộc tính map của nó để tham chiếu đối tượng bản đồ trong trang.

Các tùy chọn được chuyển vào google.maps.drawing.DrawingManager(options) đặt loại hình vẽ mặc định và các tùy chọn hiển thị cho hình dạng đã 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 tùy chọn hiện có, hãy xem phần Tùy chọn Vẽ.

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);
}
  1. Gọi setUpDrawingTools() trong hàm initMap() 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
();
}
  1. Tải lại index.html và kiểm tra xem bạn đã nhìn thấy các công cụ vẽ hay chưa. Đồng thời kiểm tra xem bạn có thể sử dụng các công cụ này để vẽ hình tròn, hình chữ nhật và hình dạng đa giác không.

Bạn có thể nhấp và kéo để vẽ hình tròn và hình chữ nhật nhưng đa giác cần được vẽ bằng cách nhấp vào mỗi đỉnh và nhấp đúp để hoàn tất hình dạng.

Xử lý sự kiện vẽ

Bạn cần một số mã để xử lý những 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 tọa độ của các hình đã vẽ để tạo truy vấn SQL.

Chúng ta sẽ thêm mã cho bước này vào một thời điểm khác, nhưng hiện tại, chúng ta sẽ giữ nguyên ba trình xử lý sự kiện trống để xử lý các sự kiện rectanglecomplete, circlecompletepolygoncomplete. Trình xử lý không phải chạy bất kỳ mã nào ở giai đoạn này.

Hãy thêm phần sau vào cuối hàm setUpDrawingTools() của bạn:

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 ví dụ đang hoạt động của mã này trong bản sao cục bộ của repo, trong thư mục step2: step2/map.html.

6. Sử dụng API ứng dụng BigQuery

API ứng dụng Google BigQuery sẽ giúp bạn tránh 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ý việc xác thực. Lớp học lập trình này sử dụng API BigQuery thông qua Thư viện ứng dụng API của Google cho JavaScript vì chúng tôi 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ã này để tương tác với BigQuery.

Thêm API Google Client cho JavaScript

Bạn sẽ sử dụng API Google Client cho JavaScript để chạy các truy vấn dựa trên BigQuery. Trong bản sao của index.html (trong thư mục work), hãy tải API bằng thẻ <script> như thế này. Đặt thẻ ngay bên dưới thẻ <script> tải API Maps:

<script src='https://apis.google.com/js/client.js'></script>

Sau khi tải API Google Client, hãy cho phép 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 xác thực trong Dự án Google Cloud Console.

Tạo thông tin đăng nhập OAuth 2.0

  1. Trong Google Cloud Console, trên Trình đơn điều hướng, hãy chọn API và amp; 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 của mình, bạn cần thêm một số cấu hình cho màn hình Cấp phép mà người dùng cuối của ứng dụng sẽ xem khi họ thay mặt họ truy cập dữ liệu BigQuery.

Để làm việc này, hãy nhấp vào thẻ Màn hình xin phép bằng OAuth. 2. Bạn cần phải thêm API Big Query vào phạm vi cho mã thông báo này. Nhấp vào nút Thêm phạm vi trong phần API Phạm vi cho Google. 3. Trong danh sách, hãy đánh dấu vào hộp bên cạnh mục API Big Query có phạm vi ../auth/bigquery. 4. Nhấp vào Thêm. 5. Nhập tên vào trường "Tên ứng dụng×39". 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:

4d18a965fc760e39.png

  1. Trong trình đơn thả xuống, hãy nhấp vào Mã ứng dụng OAuth. 1f8b36a1c27c75f0.png
  2. Trong phần Loại ứng dụng, hãy chọn Ứng dụng web.
  3. Trong trường Tên ứng dụng, nhập tên cho dự án của bạn. Ví dụ: "BigQuery và Maps".
  4. Trong mục Hạn chế, trong trường Nguồn gốc JavaScript được ủy quyền, hãy nhập URL của máy chủ cục bộ, bao gồm cả số cổng. Ví dụ: http://localhost:8887
  1. Nhấp vào nút Tạo.

Một cửa sổ bật lên sẽ hiển thị cho bạn mã ứng dụng và mật khẩu ứng dụng. Bạn cần có mã ứng dụng khách để xác thực dựa trên BigQuery. Hãy sao chép và dán giá trị này vào work/index.html dưới dạng một biến JavaScript toàn cục mới có tên là clientId.

let clientId = 'YOUR_CLIENT_ID';

7. Ủy quyền và khởi chạy

Trang web của bạn cần phải cho phép 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 tôi sử dụng OAuth 2.0 như được mô tả trong phần ủy quyền trong tài liệu API ứng dụng JavaScript. Bạn cần phải sử dụng mã ứng dụng khách OAuth và mã dự án để gửi truy vấn.

Khi API của Ứng dụng Google được tải trong trang web, bạn cần thực hiện các bước sau:

  • Uỷ quyền người dùng.
  • Nếu được ủy quyền, hãy tải API BigQuery.
  • Tải và khởi tạo bản đồ.

Xem step3/map.html để biết ví dụ về hình thức của trang HTML đã hoàn tất.

Uỷ quyền người dùng

Người dùng cuối của ứng dụng cần phải cho phép ứng dụng truy cập dữ liệu trong BigQuery thay mặt cho ứng dụng. API Google Client cho JavaScript xử lý logic OAuth để thực hiện việc này.

Trong ứng dụng thực tế, bạn có nhiều lựa chọn về cách tích hợp bước ủy quyền.

Ví dụ: bạn có thể gọi authorize() từ một phần tử giao diện người dùng như một nút hoặc thực hiện việc này khi trang đã tải. Ở đây chúng tôi đã chọn cho phép người dùng này sau khi API Google Client cho JavaScript được tải, bằng cách sử dụng một hàm callback trong phương thức gapi.load().

Hãy viết một số mã ngay sau thẻ <script> tải API Google Client để JavaScript tải cả thư viện ứng dụng và mô-đun xác thực để chúng tôi 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 được ủy quyền, hãy tải API BigQuery

Sau khi người dùng đã được ủy quyền, hãy tải API BigQuery.

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 hàm callback có tên handleAuthResult.

Thông số immediate kiểm soát việc cửa sổ bật lên có được hiển thị cho người dùng hay không. Đặt là true để chặn cửa sổ bật lên ủy quyền nếu người dùng đã được ủy 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 lấy tham số authresult. Tham số này sẽ cho phép bạn kiểm soát luồng logic tùy thuộc vào việc người dùng có được ủy 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 API BigQuery nếu người dùng đã được ủy quyền thành công.

Thêm logic trong hàm handleAuthResult() để gọi loadApi()nếu có một đối tượng authResult được chuyển vào hàm và nếu thuộc tính error của đối tượng có giá trị false.

Thêm mã vào hàm loadApi() để tải API BigQuery bằng cách sử dụ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 tạo bản đồ. Bạn cần thay đổi thứ tự logic một chút để làm điều này. Hiện tại, ứng dụng sẽ khởi chạy khi JavaScript của Maps API đã tải.

Bạn có thể thực hiện việc này bằng cách gọi hàm initMap() của 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ề API BigQuery

Lệnh gọi API BigQuery 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ò ý kiến BigQuery để 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 hàm JavaScript vào work/index.html để gửi truy vấn bằng API và một số biến để lưu trữ các giá trị của tập dữ liệu BigQuery và dự án chứa bảng để truy vấn cũng như mã dự án sẽ được lập hóa đơn cho 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 công việc

Hàm checkJobStatus dưới đây cho biết cách kiểm tra trạng thái của công việc theo định kỳ, bằng cách sử dụng phương thức API getjobId được trả về bởi yêu cầu truy vấn ban đầu. Dưới đây là ví dụ chạy 500 mili giây một lần 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 lệnh gọi lại trong lệnh gọi request.execute(). Chuyển mã công việc cho checkJobStatus. Điều này được hiển thị bởi đối tượng phản hồi 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ả truy vấn

Để nhận kết quả 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 vào trang của bạn có tên là getQueryResults(). Hàm này chấp nhận một thông số 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 API BigQuery

Có ba cách để sử dụng SQL để chạy truy vấn không gian dựa trên dữ liệu trong BigQuery:

Có các ví dụ về truy vấn 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 phần "Ví dụ nâng cao×39".

Đối với các truy vấn về ô và bán kính giới hạn, bạn có thể gọi phương thức API BigQuery query. Tạo SQL cho từng truy vấn và chuyển truy vấn này sang hàm sendQuery mà bạn đã tạo ở bước trước.

Một ví dụ về cách làm việc của mã cho bước này là 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, sử dụng kích thước nhỏ hơn và lớn hơn so với so sánh. Đây có thể là chế độ xem bản đồ hiện tại hoặc hình dạng được vẽ trên bản đồ.

Để sử dụng một hình dạng 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 thành. Trong ví dụ này, mã sử dụng getBounds() trên đối tượng hình chữ nhật để lấy đối tượng đại diện cho mức độ của hình chữ nhật trong tọa độ bản đồ và chuyển đối tượng đó đến hàm có tên là rectangleQuery:

drawingManager.addListener('rectanglecomplete', rectangle => rectangleQuery(rectangle.getBounds()));

Hàm rectangleQuery chỉ cần sử dụng tọa độ trên cùng bên phải (phía đông bắc) và phía dưới bên trái (phía tây tây) để tạo ra một cột nhỏ hơn/lớn hơn so với mỗi hàng trong bảng BigQuery. Sau đây là một ví dụ về truy vấn một bảng có tên là cột 'pickup_latitude' và cột '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 API BigQuery, 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ũ, project.dataset.tablename.

Có nhiều bảng chuyến đi Taxi ở New York. Để xem các mục đó, hãy truy cập vào bảng điều khiển web của 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 là new_york và mở rộng tập dữ liệu đó để xem các bảng. Chọn bảng chuyến đi 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 nhằm 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 giống với 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 mình bằng cách tải dữ liệu lên, thì Mã dự án này sẽ giống với bảng 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 giữ thông tin tham chiếu đến dự án Tập dữ liệu công khai có 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 mình.

Thêm các biến JavaScript toàn cục được gọi là billingProjectId, publicProjectId, datasetIdtableName vào bản sao của bạn trong index.html.

Khởi chạy các biến 'publicProjectId', 'datasetId''tableName' cùng với 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 bạn đã tạo "Bắt đầu thiết lập" sớm hơn 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 hai 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 thể hiện các góc của hình chữ nhật trong tọa độ bản đồ.

Hàm thứ hai phải có tên là rectangleQuery(). Thao tác này sẽ chuyể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;
}

Tại thời điểm này, bạn có đủ mã để gửi 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 chúng ta thêm các phương thức truy vấn khác cho vòng tròn và hình dạng tự do, hãy xem cách xử lý dữ liệu được trả về từ một truy vấn.

10. Hình ảnh hóa phản hồi

Các bảng BigQuery có thể rất lớn – Petabyte dữ liệu – và có thể tăng hàng trăm nghìn hàng mỗi giây. Do đó, điều quan trọng là phải thử và giới hạn 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 tập hợp kết quả rất lớn (hàng chục nghìn hàng hoặc lớn hơn) sẽ dẫn đến bản đồ không đọc được. Có nhiều kỹ thuật tổng hợp vị trí trong cả truy vấn SQL và trên bản đồ và bạn có thể giới hạn kết quả mà truy vấn sẽ trả về.

Bạn có thể xem mã đầy đủ của bước này trong step5/map.html.

Để giảm lượng dữ liệu 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 câu lệnh giới hạn phản hồi ở 10000 hàng. Trong ví dụ bên dưới, giá trị này được chỉ định trong một biến toàn cục có tên là recordLimit để tất cả các hàm truy vấn đều 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 ảnh hóa mật độ của các vị trí, bạn có thể sử dụng bản đồ nhiệt. API JavaScript của Maps có một lớp Heatmaplayer cho mục đích này. Lớp nhiệt đồ lấy một mảng vĩ độ, kinh độ để dễ dàng chuyển đổi các hàng được trả về từ truy vấn thành sơ đồ nhiệt.

Trong hàm getQueryResults, hãy chuyển mảng response.result.rows sang một hàm JavaScript mới có tên là doHeatMap(). Hàm này sẽ tạo 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 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 phải lặp lại 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 xe bán tải, do đó, sẽ chỉ có hai 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 địa điểm đó xuất hiện trên bản đồ.

Dưới đây là 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);
}

Tại thời điểm này, bạn sẽ có thể:

  • Mở trang đó rồi ủy quyền cho BigQuery
  • Vẽ một hình chữ nhật ở một nơi nào đó ở New York
  • Xem kết quả truy vấn thu được được trình bày dưới dạng bản đồ nhiệt.

Dưới đây là ví dụ về kết quả từ truy vấn hình chữ nhật so với dữ liệu Taxi màu vàng năm 2016 của New York, được vẽ dưới dạng bản đồ nhiệt. Ví dụ: Công ty phân phối xe bán tải quanh Tòa nhà Empire State vào một ngày thứ Bảy trong tháng 7:

7b1face0e7c71c78.png

11. Truy vấn theo bán kính xung quanh một điểm

Truy vấn bán kính rất giống nhau. Bằng cách sử dụng các hàm Toán học BigQuery 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 diện tích hình tròn trên bề mặt trái đất.

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 vòng tròn do người dùng vẽ và tạo SQL cho truy vấn tương tự.

Một ví dụ về cách làm việc của mã cho bước này được đưa vào kho lưu trữ mã dưới dạng step6/map.html.

drawingManager.addListener('circlecomplete', circle => circleQuery(circle));

Trong bản sao lập chỉ mục của bạn, hãy thêm hai hàm trống mới: circleQuery()haversineSQL().

Sau đó, thêm một trình xử lý sự kiện circlecomplete để chuyển tâm và bán kính vào 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 rồi gửi truy vấn bằng cách gọi hàm sendQuery() theo mã mẫu 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;
}

Dùng thử!

Thêm mã ở trên và thử công cụ ‘Vòng tròn\39; chọn một khu vực trên bản đồ. Kết quả sẽ trông như sau:

845418166b7cc7a3.png

12. Truy vấn các hình dạng tùy ý

Tổng kết: SQL không hỗ trợ truy vấn bằng các hình dạng tùy ý ngoài hình chữ nhật và hình tròn. BigQuery không có loại dữ liệu hình học gốc nào, vì vậy để chạy truy vấn bằng cách sử dụng các hình đa giác, bạn cần một phương pháp khác để truy vấn đơn giản SQL.

Một tính năng BigQuery rất mạnh mẽ có thể dùng cho mục đích 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.

Mã đang hoạt động cho bước này nằm trong step7/map.html.

UDF trong API BigQuery

Cách tiếp cận API BigQuery cho UDF hơi khác 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 qua API, chỉ cần một câu lệnh SQL để sử dụng Hàm do người dùng xác định. Giá trị của useLegacySql phải được đặt thành false. Ví dụ JavaScript dưới đây cho thấy một hàm tạo và gửi một đố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à truy vấn có Hàm do người dùng xác định.

Ví dụ hoạt động của phương pháp này là 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 xây dựng 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. Thứ nhất, mã này đang tạo câu lệnh CREATE TEMPORARY FUNCTION đóng gói mã JavaScript để làm việc nếu một điểm nhất định nằm trong một đa giác. Tọa độ đa giác được chèn bằng lệnh gọi phương thức JSON.stringify(poly) để chuyển đổi một mảng JavaScript của các cặp tọa độ x,y thành một chuỗi. Đối tượng đa giác được chuyển ở dạng đối số cho 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 API Maps

Để sử dụng tính năng này với thư viện vẽ bằng API Maps, chúng ta cần lưu đa giác do người dùng vẽ và chuyển phần 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, để có được tọa độ 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 hàm JavaScript UDF dưới dạng chuỗi, cũng như câu lệnh SQL sẽ gọi hàm UDF.

Hãy xemstep7/map.html để biết ví dụ về cách thực hiện.

Nội dung xuất mẫu

Sau đây là ví dụ về kết quả truy vấn trạng thái đến lấy hàng từ dữ liệu Taxi màu vàng TLC NYC 2016 trong BigQuery bằng cách sử dụng đa giác rảnh tay, với dữ liệu đã chọn được vẽ dưới dạng bản đồ nhiệt.

Ảnh chụp màn hình lúc 10:00 sáng 40/05/2017

13. Tiế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 một ví dụ đang hoạt động của các ý tưởng này tại step8/map.html trong kho lưu trữ mã.

Giảm số lần liên kết

Cho đến nay, chúng tôi chỉ mới ánh xạ các vị trí đón. Bằng cách yêu cầu các cột dropoff_latitudedropoff_longitude cũng như sửa đổi mã bản đồ nhiệt để vẽ biểu đồ. Thay vào đó, bạn có thể xem các điểm đến trong hành trình taxi bắt đầu tại một vị trí cụ thể.

Ví dụ: hãy xem nơi taxi có xu hướng trả khách khi họ yêu cầu xe đón xung quanh Tòa 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í nhận 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ể sử dụng các giá trị bỏ ngang. Đối tượng kết quả có một giản đồ có thể được 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, chúng sẽ ở vị trí lập chỉ mục 2 và 3. Các chỉ mục này có thể được đọc từ một biến để làm cho mã dễ quản lý hơn. NB maxIntensity của bản đồ nhiệt được đặt để hiển thị mật độ điểm ảnh giảm 20 lần cho mỗi pixel ở mức tối đa.

Thêm một số biến để cho phép bạn thay đổi các cột 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);
}

Sau đây là bản đồ nhiệt cho thấy tình trạng phân phối xe thả xuống từ tất cả các đơn hàng tự đến lấy xung quanh Tòa nhà Empire State vào năm 2016. Bạn có thể nhìn thấy các khu vực tập trung lớn (tập hợp màu đỏ) của các điểm đến ở trung tâm, đặc biệt là xung quanh Quảng trường Thời đại, cũng như dọc theo Đại lộ 5 giữa đường 23 St và 14 St. 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à sân bay JFK, Trung tâm Thương mại Thế giới và Công viên pin.

Ảnh chụp màn hình lúc 10:40 ngày 19/5/2017

Tạo kiểu cho bản đồ cơ sở

Khi tạo Google Maps bằng API JavaScript của Maps, bạn có thể thiết lập kiểu bản đồ bằng cách sử dụng đối tượng JSON. Đối với hình ảnh dữ liệu, mã này có thể hữu ích khi ẩn màu trong bản đồ. Bạn có thể tạo và thử các kiểu bản đồ bằng trình hướng dẫn tạo kiểu API của Google Maps tại mapstyle.withgoogle.com.

Bạn có thể thiết lập kiểu bản đồ khi khởi tạo đối tượng bản đồ hoặc bất cứ lúc nào sau đó. Dưới đây là cách bạn thêm kiểu tùy 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 thể hiện bản đồ thang màu xám có các điểm có nhãn sở 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"
     
}
   
]
 
}
]

Gửi ý 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 sẽ hữu ích để cho người dùng biết rằng có điều gì đó đang xảy 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ả lại và lượng dữ liệu được xử lý.

Thêm một số HTML sau khi ánh xạ <div> để tạo một bảng điều khiển trên trang sẽ hiển thị số lượng hàng do truy vấn trả về, thời gian truy vấn được xử lý 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ã dưới đây.

#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 hình ảnh động vào trang nhưng ẩn hình ảnh cho đến khi bắt buộc, và một số mã JavaScript và CSS dùng để hiển thị khi công việc BigQuery đang chạy.

Thêm một số HTML để hiển thị đồ họa độ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 trạng thái và hiển thị hoặc ẩn hình ảnh khi truy vấn đang chạy. Bạn có thể sử dụng đối tượng response để cập nhật bảng điều khiển tùy thuộc vào 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 hoàn tất công việc, bạn có thể truy cập vào các thuộc tính response.totalRowsresponse.totalBytesProcessed. Người dùng nên chuyển đổi mili giây thành giây và byte thành gigabyte để hiển thị như minh họa 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 hình ảnh động, hãy thêm một hàm để kiểm soát chế độ hiển thị của hình ảnh động. Hàm này sẽ chuyển đổi độ mờ của bất kỳ Phần tử DOM HTML nào được chuyể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ý truy vấn và sau khi kết quả truy vấn trở lại từ BigQuery.

Mã này sẽ 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 độ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 sẽ có dạng như sau.

Ảnh chụp màn hình lúc 2:32.19 chiều.2017-05-10

Hãy xem ví dụ đầy đủ trong step8/map.html.

14. Những điểm 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ông đọc được. Hãy cân nhắc dùng HeatmapLayer để hiển thị mật độ, hoặc đánh dấu các cụm để chỉ ra vị trí của nhiều điểm dữ liệu bằng một ký hiệu duy nhất trong mỗi cụm. Bạn có thể xem thêm thông tin chi tiết trong Hướng dẫn phân nhóm đánh dấu.

Tối ưu hóa truy vấn

BigQuery sẽ quét toàn bộ bảng bằng mọi cụm từ tìm kiếm. Để tối ưu hóa việc sử dụng hạn mức BigQuery, bạn chỉ nên chọn các cột cần thiết trong truy vấn của mình.

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 các 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 theo 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 bạn đã phát hiện một số mẫu thú vị, có thể dễ dàng chia sẻ các mẫu này với đối tượng rộng hơn bằng cách xuất kết quả từ BigQuery và tạo tập dữ liệu tĩnh bằng cách sử dụng Lớp dữ liệu của Google Maps.

Lưu ý đến Điều khoản dịch vụ của Nền tảng Google Maps. Để biết thêm thông tin chi tiết về cách đặt giá trên Nền tảng Google Maps, hãy xem tài liệu trực tuyến.

Chơi bằng nhiều dữ liệu!

Có một số tập dữ liệu công khai trong BigQuery có các cột vĩ độ và kinh độ, ví dụ: các tập dữ liệu NYC Taxi từ năm 2009-2016, dữ liệu chuyến đi của Uber và Lyft NYtập dữ liệu GDELT.

15. Xin chúc mừng!

Chúng tôi hy vọng điều này giúp bạn nhanh chóng thiết lập và chạy một số truy vấn địa lý dựa vào bảng BigQuery để bạn có thể khám phá các mẫu và trực quan hóa chúng trên Google Maps. Chúc bạn lập bản đồ thật vui!

Nội dung 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 nội dung đề xuất sau.

Hãy xem BigQuery là gì để tìm hiểu thêm về dịch vụ kho dữ liệu không cỡ máy chủ, petabyte và không máy chủ của Google.

Hãy xem hướng dẫn về cách tạo ứng dụng đơn giản bằng API BigQuery.

Xem hướng dẫn cho nhà phát triển về thư viện bản vẽ để biết thêm chi tiết về cách cho phép người dùng tương tác để vẽ hình dạng trên Google Maps.

Hãy xem các cách khác để trực quan hóa dữ liệu trên Google Maps.

Xem Hướng dẫn bắt đầu sử dụng AP (Điểm truy cập) cho ứng dụng JavaScript Tôi hiểu các khái niệm cơ bản về cách sử dụng API Ứng dụng để truy cập các API khác của Google.