1. Ringkasan
Peta dapat menjadi alat yang sangat efektif saat memvisualisasikan pola dalam set data yang terkait dengan lokasi dalam beberapa cara. Relasi ini dapat berupa nama tempat, nilai lintang dan bujur tertentu, atau nama area yang memiliki batas tertentu seperti wilayah sensus atau kode pos.
Jika set data ini menjadi sangat besar, set data tersebut dapat sulit dikueri dan divisualisasikan menggunakan alat konvensional. Dengan menggunakan Google BigQuery untuk membuat kueri data dan Google Maps API untuk membuat kueri dan memvisualisasikan output, Anda dapat dengan cepat menjelajahi pola geografis dalam data Anda dengan sedikit penyiapan atau pengodean, dan tanpa harus mengelola sistem untuk menyimpan set data yang sangat besar.
Yang akan Anda build
Dalam codelab ini, Anda akan menulis dan menjalankan beberapa kueri yang menunjukkan cara memberikan insight berbasis lokasi ke set data publik yang sangat besar menggunakan BigQuery. Anda juga akan membuat halaman web yang memuat peta menggunakan Google Maps Platform JavaScript API, lalu menjalankan dan memvisualisasikan kueri spasial terhadap set data publik yang sama dan sangat besar menggunakan Google APIs Client Library for JavaScript dan BigQuery API.
Yang akan Anda pelajari
- Cara membuat kueri set data lokasi berskala petabyte dalam hitungan detik dengan BigQuery, menggunakan kueri SQL, Fungsi yang Ditentukan Pengguna , dan BigQuery API
- Cara menggunakan Google Maps Platform untuk menambahkan Peta Google ke halaman web dan memungkinkan pengguna menggambar bentuk di peta tersebut
- Cara memvisualisasikan kueri terhadap set data besar di Google Maps seperti pada contoh gambar di bawah, yang menunjukkan kepadatan lokasi penurunan penumpang taksi pada tahun 2016 dari perjalanan yang dimulai dari blok di sekitar Empire State Building.
Yang Anda butuhkan
- Pengetahuan dasar tentang HTML, CSS, JavaScript, SQL, dan Chrome DevTools
- Browser web modern, seperti Chrome, Firefox, Safari, atau Edge versi terbaru.
- Editor teks atau IDE pilihan Anda
Teknologi
BigQuery
BigQuery adalah layanan analisis data Google untuk set data yang sangat besar. Layanan ini memiliki RESTful API dan mendukung kueri yang ditulis dalam SQL. Jika Anda memiliki data dengan nilai lintang dan bujur, data tersebut dapat digunakan untuk membuat kueri data Anda menurut lokasi. Keuntungannya adalah Anda dapat menjelajahi set data yang sangat besar secara visual untuk melihat pola tanpa harus mengelola infrastruktur server atau database. Anda bisa mendapatkan jawaban atas pertanyaan Anda dalam beberapa detik, berapa pun ukuran tabel Anda, menggunakan skalabilitas besar dan infrastruktur terkelola BigQuery.
Google Maps Platform
Google Maps Platform menyediakan akses terprogram ke data peta, tempat, dan rute Google. Saat ini, lebih dari 2 juta situs dan aplikasi menggunakannya untuk menyediakan peta sematan dan kueri berbasis lokasi kepada penggunanya.
Lapisan Gambar Google Maps Platform JavaScript API memungkinkan Anda menggambar bentuk di peta. Data ini dapat dikonversi menjadi input untuk menjalankan kueri terhadap tabel BigQuery yang memiliki nilai lintang dan bujur yang disimpan dalam kolom.
Untuk memulai, Anda memerlukan project Google Cloud Platform dengan BigQuery dan Maps API yang diaktifkan.
2. Mempersiapkan
Akun Google
Jika belum memiliki Akun Google (Gmail atau Google Apps), Anda harus membuatnya.
Buat Proyek
Login ke Konsol Google Cloud Platform ( console.cloud.google.com) dan buat project baru. Di bagian atas layar, ada menu drop-down Project:
Setelah mengklik menu drop-down project ini, Anda akan mendapatkan item menu yang memungkinkan Anda membuat project baru:
Di kotak yang bertuliskan "Masukkan nama baru untuk project Anda", masukkan nama untuk project baru Anda, misalnya "BigQuery Codelab":
Project ID akan dibuat untuk Anda. Project ID adalah nama unik di semua project Google Cloud. Ingat Project ID Anda, karena Anda akan menggunakannya nanti. Maaf, nama di atas telah digunakan dan tidak akan berfungsi untuk Anda. Masukkan Project ID Anda sendiri di mana pun Anda melihat YOUR_PROJECT_ID dalam codelab ini.
Aktifkan Penagihan
Untuk mendaftar ke BigQuery, gunakan project yang dipilih atau dibuat pada langkah sebelumnya. Penagihan harus diaktifkan pada project ini. Setelah penagihan diaktifkan, Anda dapat mengaktifkan BigQuery API.
Cara mengaktifkan penagihan bergantung pada apakah Anda membuat project baru atau mengaktifkan kembali penagihan untuk project yang sudah ada.
Google menawarkan uji coba gratis selama 12 bulan untuk penggunaan Google Cloud Platform hingga senilai $300 yang dapat Anda gunakan untuk Codelab ini. Cari tahu detail selengkapnya di https://cloud.google.com/free/.
Project baru
Saat membuat project baru, Anda akan diminta untuk memilih akun penagihan yang ingin ditautkan ke project tersebut. Jika Anda hanya memiliki satu akun penagihan, akun tersebut akan otomatis ditautkan ke project Anda.
Jika tidak memiliki akun penagihan, Anda harus membuatnya dan mengaktifkan penagihan untuk project Anda agar dapat menggunakan berbagai fitur Google Cloud Platform. Untuk membuat akun penagihan baru dan mengaktifkan penagihan untuk project Anda, ikuti petunjuk di Membuat akun penagihan baru.
Project yang ada
Jika Anda memiliki project yang penagihannya dinonaktifkan untuk sementara, Anda dapat mengaktifkan kembali penagihan:
- Buka Cloud Platform Console.
- Dari daftar project, pilih project yang penagihannya ingin diaktifkan kembali.
- Buka menu sebelah kiri konsol, lalu pilih Billing
. Anda akan diminta untuk memilih akun penagihan.
- Klik Tetapkan akun.
Buat Akun penagihan baru
Untuk membuat akun penagihan baru:
- Buka Cloud Platform Console dan login atau, jika Anda belum memiliki akun, daftar.
- Buka menu sisi kiri konsol, lalu pilih Penagihan
- Klik tombol Akun penagihan baru. (Perhatikan bahwa jika ini bukan akun penagihan pertama Anda, Anda harus membuka daftar akun penagihan terlebih dahulu dengan mengklik nama akun penagihan yang ada di dekat bagian atas halaman, lalu mengklik Kelola akun penagihan.)
- Masukkan nama akun penagihan dan masukkan informasi penagihan Anda. Opsi yang Anda lihat bergantung pada negara alamat penagihan Anda. Perhatikan bahwa untuk akun Amerika Serikat, Anda tidak dapat mengubah status pajak setelah akun dibuat.
- Klik Submit and enable billing.
Secara default, orang yang membuat akun penagihan adalah administrator penagihan untuk akun tersebut.
Untuk mengetahui informasi tentang cara memverifikasi rekening bank dan menambahkan metode pembayaran cadangan, lihat Menambahkan, menghapus, atau memperbarui metode pembayaran.
Aktifkan BigQuery API
Untuk mengaktifkan BigQuery API di project Anda, buka halaman BigQuery API di Marketplace di konsol, lalu klik tombol ‘Aktifkan' berwarna biru.
3. Membuat kueri data Lokasi di BigQuery
Ada tiga cara untuk membuat kueri data lokasi yang disimpan sebagai nilai lintang dan bujur di BigQuery.
- Kueri persegi panjang: tentukan area yang diminati sebagai kueri yang memilih semua baris dalam rentang garis lintang dan bujur minimum dan maksimum.
- Kueri radius: tentukan area yang diminati dengan menghitung lingkaran di sekitar titik menggunakan formula Haversine dan fungsi Math untuk memodelkan bentuk bumi.
- Kueri poligon: tentukan bentuk kustom dan gunakan Fungsi yang Ditentukan Pengguna untuk menyatakan logika titik dalam poligon yang diperlukan untuk menguji apakah lintang dan bujur setiap baris berada di dalam bentuk.
Untuk memulai, gunakan Editor Kueri di bagian BigQuery pada konsol Google Cloud Platform untuk menjalankan kueri berikut terhadap data taksi NYC.
SQL Standar vs. Legacy SQL
BigQuery mendukung dua versi SQL: Legacy SQL dan Standard SQL. Yang terakhir adalah standar ANSI 2011. Untuk tujuan tutorial ini, kita akan menggunakan SQL Standar karena memiliki kepatuhan standar yang lebih baik.
Jika ingin menjalankan SQL Lama di editor BigQuery, Anda dapat melakukannya dengan melakukan hal berikut:
- Klik tombol 'Lainnya'
- Pilih 'Setelan kueri' dari menu dropdown
- Di bagian 'SQL dialect', pilih tombol pilihan 'Legacy'
- Klik tombol 'Simpan'
Kueri Persegi Panjang
Kueri persegi panjang cukup mudah dibuat di BigQuery. Anda hanya perlu menambahkan klausa WHERE
yang membatasi hasil yang ditampilkan ke hasil dengan lokasi di antara nilai minimum dan maksimum untuk garis lintang dan bujur.
Coba contoh di bawah di konsol BigQuery. Kueri ini mencari beberapa statistik perjalanan rata-rata untuk perjalanan yang dimulai di area persegi panjang yang mencakup midtown dan lower Manhattan. Ada dua lokasi berbeda yang dapat Anda coba, hapus komentar pada klausa WHERE
kedua untuk menjalankan kueri pada perjalanan yang dimulai di bandara 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
Hasil untuk kedua kueri menunjukkan bahwa ada perbedaan besar dalam jarak perjalanan rata-rata, tarif, dan tip untuk penjemputan di kedua lokasi.
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 |
Kueri Radius
Kueri radius juga mudah dibuat di SQL jika Anda memahami sedikit matematika. Dengan menggunakan fungsi Matematika SQL Lama BigQuery, Anda dapat membuat kueri SQL menggunakan Formula Haversine yang memperkirakan area melingkar atau tutup bola di permukaan bumi.
Berikut contoh pernyataan SQL BigQuery untuk kueri lingkaran yang berpusat di 40.73943, -73.99585
dengan radius 0,1 km.
Fungsi ini menggunakan nilai konstanta 111,045 kilometer untuk memperkirakan jarak yang diwakili oleh satu derajat.
Ini didasarkan pada contoh yang ditemukan di 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 untuk Formula Haversine terlihat rumit, tetapi yang perlu Anda lakukan hanyalah memasukkan koordinat pusat lingkaran, radius, serta nama project, set data, dan tabel untuk BigQuery.
Berikut adalah contoh kueri yang menghitung beberapa statistik perjalanan rata-rata untuk penjemputan dalam jarak 100 m dari Empire State Building. Salin dan tempel ini ke konsol web BigQuery untuk melihat hasilnya. Ubah lintang dan bujur untuk membandingkan dengan area lain seperti lokasi di 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
Hasil kueri ada di bawah. Anda dapat melihat bahwa ada perbedaan besar dalam tip rata-rata, tarif, jarak perjalanan, ukuran proporsional tip terhadap tarif, dan tarif rata-rata per mil yang ditempuh.
Empire State Building:
avg_tip | avg_fare | avg_distance | avg_tip_pc | avg_fare_mile |
1,17 | 11.08 | 45,28 | 10,53 | 6,42 |
Bronx
avg_tip | avg_fare | avg_distance | avg_tip_pc | avg_fare_mile |
0,52 | 17,63 | 4,75 | 4,74 | 10.9 |
Kueri Poligon
SQL tidak mendukung kueri menggunakan bentuk arbitrer selain persegi panjang dan lingkaran. BigQuery tidak memiliki jenis data geometri atau indeks spasial native, jadi untuk menjalankan kueri menggunakan bentuk poligon, Anda memerlukan pendekatan yang berbeda dari kueri SQL langsung. Salah satu caranya adalah dengan menentukan fungsi geometri di JavaScript dan mengeksekusinya sebagai Fungsi yang Ditentukan Pengguna (UDF) di BigQuery.
Banyak operasi geometri dapat ditulis dalam JavaScript sehingga mudah untuk mengambil satu operasi dan mengeksekusinya terhadap tabel BigQuery yang berisi nilai lintang dan bujur. Anda perlu meneruskan poligon kustom melalui UDF dan melakukan pengujian terhadap setiap baris, hanya menampilkan baris yang lintang dan bujurnya berada di dalam poligon. Cari tahu lebih lanjut UDF di referensi BigQuery.
Algoritma Point In Polygon
Ada banyak cara untuk menghitung apakah suatu titik berada di dalam poligon di JavaScript. Berikut adalah port dari C implementasi terkenal yang menggunakan algoritma ray tracing untuk menentukan apakah suatu titik berada di dalam atau di luar poligon dengan menghitung berapa kali garis yang panjangnya tak terhingga melintasi batas bentuk. Hanya memerlukan beberapa baris kode:
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;
}
Melakukan porting ke JavaScript
Versi JavaScript dari algoritma ini terlihat seperti ini:
/* 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;
}
Saat menggunakan SQL Standar di BigQuery, pendekatan UDF hanya memerlukan satu pernyataan, tetapi UDF harus ditentukan sebagai fungsi sementara dalam pernyataan. Berikut contohnya. Tempel pernyataan SQL di bawah ke jendela Query Editor.
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
Selamat!
Sekarang Anda telah menjalankan tiga jenis kueri spasial menggunakan BigQuery. Seperti yang telah Anda lihat, lokasi sangat memengaruhi data hasil untuk kueri terhadap set data ini, tetapi kecuali Anda menebak tempat untuk menjalankan kueri, sulit untuk menemukan pola spasial secara ad-hoc hanya dengan menggunakan kueri SQL.
Sayangnya, kita tidak dapat memvisualisasikan data di peta, dan menjelajahi data dengan menentukan area minat yang diinginkan. Nah, dengan menggunakan Google Maps API, Anda dapat melakukannya. Pertama, Anda harus mengaktifkan Maps API, menyiapkan halaman web sederhana yang berjalan di mesin lokal, dan mulai menggunakan BigQuery API untuk mengirim kueri dari halaman web Anda.
4. Menggunakan Google Maps API
Setelah menjalankan beberapa kueri spasial sederhana, langkah berikutnya adalah memvisualisasikan output untuk melihat pola. Untuk melakukannya, Anda akan mengaktifkan Maps API, membuat halaman web yang mengirimkan kueri dari peta ke BigQuery, lalu menggambar hasilnya di peta.
Aktifkan Maps JavaScript API
Untuk Codelab ini, Anda harus mengaktifkan Maps JavaScript API Google Maps Platform di project Anda. Untuk itu, lakukan:
- Di konsol Google Cloud Platform, buka Marketplace.
- Di Marketplace, telusuri 'Maps JavaScript API'
- Klik kartu untuk Maps JavaScript API di hasil penelusuran
- Klik tombol 'Aktifkan'
Membuat Kunci API
Untuk membuat permintaan ke Google Maps Platform, Anda harus membuat kunci API dan mengirimkannya bersama semua permintaan. Untuk membuat kunci API, lakukan hal berikut:
- Di konsol Google Cloud Platform, klik menu hamburger untuk membuka nav kiri
- Pilih 'API & Layanan' > 'Kredensial'
- Klik tombol 'Create Credential', lalu pilih 'API Key'
- Salin kunci API baru
Download kode dan siapkan server web
Klik tombol berikut untuk mendownload semua kode untuk codelab ini:
Ekstrak file ZIP yang didownload. Tindakan ini akan mengekstrak folder root (bigquery
), yang berisi satu folder untuk setiap langkah codelab ini, beserta semua resource yang akan Anda butuhkan.
Folder stepN
berisi status akhir yang diinginkan dari setiap langkah codelab ini. Folder tersebut disediakan sebagai referensi Kita akan melakukan semua pekerjaan coding di direktori yang disebut work
.
Menyiapkan server web lokal
Meskipun Anda bebas menggunakan server web Anda sendiri, codelab ini dirancang agar berfungsi dengan baik dengan Server Web Chrome. Jika aplikasi tersebut belum diinstal, Anda dapat menginstalnya dari Chrome Web Store.
Setelah diinstal, buka aplikasi. Di Chrome, Anda dapat melakukannya sebagai berikut:
- Buka Chrome
- Pada kolom URL di bagian atas, ketik chrome://apps
- Tekan Enter
- Di jendela yang terbuka, klik ikon Server Web. Anda juga dapat mengklik kanan aplikasi untuk membukanya di tab reguler atau yang disematkan, layar penuh, atau jendela baru
Anda akan melihat dialog ini berikutnya, yang memungkinkan Anda mengonfigurasi server web lokal:
- Klik 'PILIH FOLDER' dan pilih lokasi tempat Anda mendownload file contoh codelab
- Di bagian ‘Opsi', centang kotak di samping ‘Tampilkan index.html secara otomatis':
- Geser tombol berlabel 'Server Web: DIMULAI' ke kiri, lalu kembali ke kanan untuk menghentikan, lalu memulai ulang server web
5. Memuat peta dan alat gambar
Membuat halaman peta dasar
Mulai dengan halaman HTML sederhana yang memuat Peta Google menggunakan Maps JavaScript API dan beberapa baris Javascript. Kode dari Contoh Peta Sederhana Google Maps Platform adalah tempat yang tepat untuk memulai. Kode ini direproduksi di sini agar Anda dapat menyalin dan menempelkannya ke editor teks atau IDE pilihan Anda, atau Anda dapat menemukannya dengan membuka index.html
dari repo yang Anda download.
- Salin
index.html
ke folderwork
di salinan lokal repo Anda - Salin folder img/ ke folder work/ di salinan lokal repo Anda
- Buka work/
index.html
di editor teks atau IDE Anda - Ganti
YOUR_API_KEY
dengan kunci API yang Anda buat sebelumnya
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"
async defer></script>
- Di browser Anda, buka
localhost:<port>/work
, denganport
adalah nomor port yang ditentukan dalam konfigurasi server web lokal Anda. Port default-nya adalah8887
. Anda akan melihat peta pertama Anda ditampilkan.
Jika Anda menerima pesan error di browser, periksa apakah kunci API Anda sudah benar dan server web lokal Anda aktif.
Mengubah lokasi dan tingkat zoom default
Kode yang menetapkan lokasi dan tingkat zoom ada di baris 27 & 28 index.html, dan saat ini berpusat di Sydney, Australia:
<script>
let map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -34.397, lng: 150.644},
zoom: 8
});
}
</script>
Tutorial ini menggunakan data perjalanan taksi BigQuery untuk New York, jadi selanjutnya Anda akan mengubah kode inisialisasi peta untuk memusatkan lokasi di New York City pada tingkat zoom yang sesuai - 13 atau 14 akan berfungsi dengan baik.
Untuk melakukannya, perbarui blok kode di atas menjadi berikut untuk memusatkan peta di Empire State Building dan menyesuaikan tingkat zoom ke 14:
<script>
let map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 40.7484405, lng: -73.9878531},
zoom: 14
});
}
</script>
Selanjutnya, muat ulang peta di browser Anda untuk melihat hasilnya.
Memuat library gambar dan visualisasi
Untuk menambahkan kemampuan menggambar ke peta, Anda akan mengubah skrip yang memuat Maps JavaScript API dengan menambahkan parameter opsional yang memberi tahu Google Maps Platform untuk mengaktifkan library gambar.
Codelab ini juga menggunakan HeatmapLayer
, jadi Anda juga akan mengupdate skrip untuk meminta library visualisasi. Untuk melakukannya, tambahkan parameter libraries
, dan tentukan pustaka visualization
dan drawing
sebagai nilai yang dipisahkan koma, misalnya libraries=
visualization,drawing
Kodenya akan terlihat seperti berikut:
<script src='http://maps.googleapis.com/maps/api/js?libraries=visualization,drawing&callback=initMap&key=YOUR_API_KEY' async defer></script>
Menambahkan DrawingManager
Untuk menggunakan bentuk yang digambar pengguna sebagai input ke kueri, tambahkan DrawingManager
ke peta Anda, dengan mengaktifkan alat Circle
, Rectangle
, dan Polygon
.
Sebaiknya masukkan semua kode penyiapan DrawingManager
ke dalam fungsi baru, jadi di salinan index.html Anda, lakukan hal berikut:
- Tambahkan fungsi bernama
setUpDrawingTools()
dengan kode berikut untuk membuatDrawingManager
dan menetapkan propertimap
-nya untuk mereferensikan objek peta di halaman.
Opsi yang diteruskan ke google.maps.drawing.DrawingManager(options)
menetapkan jenis gambar bentuk default dan opsi tampilan untuk bentuk yang digambar. Untuk memilih area peta yang akan dikirim sebagai kueri, bentuk harus memiliki keburaman nol. Untuk mengetahui informasi selengkapnya tentang opsi yang tersedia, lihat Opsi 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);
}
- Panggil
setUpDrawingTools()
di fungsiinitMap()
setelah objek peta dibuat
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 40.744593, lng: -73.990370}, // Manhattan, New York.
zoom: 12
});
setUpDrawingTools();
}
- Muat ulang index.html dan periksa apakah alat gambar Anda terlihat. Periksa juga apakah Anda dapat menggunakannya untuk menggambar lingkaran, persegi panjang, dan bentuk poligon.
Anda dapat mengklik dan menarik untuk menggambar lingkaran dan persegi, tetapi poligon harus digambar dengan mengklik setiap simpul, dan mengklik dua kali untuk menyelesaikan bentuk.
Menangani Peristiwa Menggambar
Anda memerlukan beberapa kode untuk menangani peristiwa yang diaktifkan saat pengguna selesai menggambar bentuk, seperti halnya Anda memerlukan koordinat bentuk yang digambar untuk membuat kueri SQL.
Kita akan menambahkan kode untuk ini di langkah selanjutnya, tetapi untuk saat ini kita akan membuat tiga pengendali peristiwa kosong untuk menangani peristiwa rectanglecomplete
, circlecomplete
, dan polygoncomplete
. Pada tahap ini, handler tidak perlu menjalankan kode apa pun.
Tambahkan kode berikut ke bagian bawah fungsi 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.
});
Anda dapat menemukan contoh kode yang berfungsi ini di salinan lokal repositori, di folder step2
: step2/map.html.
6. Menggunakan BigQuery Client API
Google BigQuery Client API akan membantu Anda menghindari penulisan banyak kode boilerplate yang diperlukan untuk membuat permintaan, mengurai respons, dan menangani autentikasi. Codelab ini menggunakan BigQuery API melalui Google APIs Client Library for JavaScript karena kita akan mengembangkan aplikasi berbasis browser.
Selanjutnya, Anda akan menambahkan kode untuk memuat API ini di halaman web dan menggunakannya untuk berinteraksi dengan BigQuery.
Tambahkan Google Client API untuk JavaScript
Anda akan menggunakan Google Client API for Javascript untuk menjalankan kueri terhadap BigQuery. Di salinan index.html
(di folder work
), muat API menggunakan tag <script>
seperti ini. Letakkan tag tepat di bawah tag <script>
yang memuat Maps API:
<script src='https://apis.google.com/js/client.js'></script>
Setelah memuat Google Client API, beri otorisasi kepada pengguna untuk mengakses data di BigQuery. Untuk melakukannya, Anda dapat menggunakan OAuth 2.0. Pertama, Anda perlu menyiapkan beberapa kredensial di Project Konsol Google Cloud.
Buat Kredensial OAuth 2.0
- Di Konsol Google Cloud, dari Navigation menu, pilih APIs & Services > Credentials.
Sebelum dapat menyiapkan kredensial, Anda perlu menambahkan beberapa konfigurasi untuk layar Otorisasi yang akan dilihat pengguna akhir aplikasi Anda saat mereka mengizinkan aplikasi Anda mengakses data BigQuery atas nama mereka.
Untuk melakukannya, klik tab OAuth consent screen. 2. Anda perlu menambahkan BigQuery API ke cakupan untuk token ini. Klik tombol Tambahkan Cakupan di bagian Cakupan untuk Google API. 3. Dari daftar, centang kotak di samping entri BigQuery API dengan cakupan ../auth/bigquery
. 4. Klik Tambahkan. 5. Masukkan nama di kolom 'Nama aplikasi'. 6. Klik Simpan untuk menyimpan setelan Anda. 7. Selanjutnya, Anda akan membuat Client ID OAuth. Untuk melakukannya, klik Buat Kredensial:
- Di menu dropdown, klik Client ID OAuth.
- Di bagian Application Type, pilih Web application.
- Di kolom Nama Aplikasi, ketik nama untuk project Anda. Misalnya, "BigQuery dan Maps".
- Di bagian Restrictions, pada kolom Authorized JavaScript Origins, masukkan URL localhost, termasuk nomor port. Misalnya:
http://localhost:8887
.
- Klik tombol Buat.
Pop-up akan menampilkan client ID dan rahasia klien. Anda memerlukan ID klien untuk melakukan autentikasi terhadap BigQuery. Salin dan tempelkan ke work/index.html
sebagai variabel JavaScript global baru bernama clientId
.
let clientId = 'YOUR_CLIENT_ID';
7. Otorisasi dan Inisialisasi
Halaman web Anda harus memberi otorisasi kepada pengguna untuk mengakses BigQuery sebelum menginisialisasi peta. Dalam contoh ini, kita menggunakan OAuth 2.0 seperti yang dijelaskan di bagian otorisasi dokumentasi JavaScript Client API. Anda harus menggunakan ID klien OAuth dan Project ID untuk mengirim kueri.
Saat Google Client API dimuat di halaman web, Anda harus melakukan langkah-langkah berikut:
- Otorisasi pengguna.
- Jika diizinkan, muat BigQuery API.
- Muat dan lakukan inisialisasi peta.
Lihat step3/map.html untuk melihat contoh tampilan halaman HTML yang sudah selesai.
Mengotorisasi pengguna
Pengguna akhir aplikasi harus mengizinkan aplikasi untuk mengakses data di BigQuery atas nama mereka. Google Client API untuk JavaScript menangani logika OAuth untuk melakukannya.
Dalam aplikasi dunia nyata, Anda memiliki banyak pilihan tentang cara mengintegrasikan langkah otorisasi.
Misalnya, Anda dapat memanggil authorize()
dari elemen UI seperti tombol, atau melakukannya saat halaman telah dimuat. Di sini, kita telah memilih untuk mengizinkan pengguna setelah Google Client API untuk JavaScript dimuat, dengan menggunakan fungsi callback dalam metode gapi.load()
.
Tulis beberapa kode segera setelah tag <script>
yang memuat Google Client API untuk Javascript guna memuat library klien dan modul autentikasi agar kita dapat mengautentikasi pengguna secara langsung.
<script src='https://apis.google.com/js/client.js'></script>
<script type='text/javascript'>
gapi.load('client:auth', authorize);
</script>
Saat otorisasi, muat BigQuery API
Setelah pengguna diberi otorisasi, muat BigQuery API.
Pertama, panggil gapi.auth.authorize()
dengan variabel clientId
yang Anda tambahkan pada langkah sebelumnya. Tangani respons dalam fungsi callback yang disebut handleAuthResult
.
Parameter immediate
mengontrol apakah pop-up ditampilkan kepada pengguna atau tidak. Setel ke true
untuk menyembunyikan pop-up otorisasi jika pengguna sudah diizinkan.
Tambahkan fungsi ke halaman Anda yang bernama handleAuthResult()
. Fungsi ini perlu mengambil parameter authresult
, yang akan memungkinkan Anda mengontrol alur logika, bergantung pada apakah pengguna berhasil diotorisasi atau tidak.
Tambahkan juga fungsi yang disebut loadApi
untuk memuat BigQuery API jika pengguna berhasil diberi otorisasi.
Tambahkan logika dalam fungsi handleAuthResult()
untuk memanggil loadApi()
jika ada objek authResult
yang diteruskan ke fungsi, dan jika properti error
objek memiliki nilai false
.
Tambahkan kode ke fungsi loadApi()
untuk memuat BigQuery API menggunakan metode 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');
}
Memuat peta
Langkah terakhir adalah melakukan inisialisasi peta. Anda perlu mengubah sedikit urutan logika untuk melakukannya. Saat ini, inisialisasi dilakukan saat Maps API JavaScript telah dimuat.
Anda dapat melakukannya dengan memanggil fungsi initMap()
dari metode then()
setelah metode load()
pada objek gapi.client
.
// Load BigQuery client API
function loadApi(){
gapi.client.load('bigquery', 'v2').then(
() => initMap()
);
}
8. Konsep BigQuery API
Panggilan BigQuery API biasanya dieksekusi dalam hitungan detik, tetapi mungkin tidak langsung menampilkan respons. Anda memerlukan beberapa logika untuk melakukan polling BigQuery guna mengetahui status tugas yang berjalan lama, dan hanya mengambil hasil saat tugas selesai.
Kode lengkap untuk langkah ini ada di step4/map.html.
Mengirim permintaan
Tambahkan fungsi Javascript ke work/index.html
untuk mengirim kueri menggunakan API, dan beberapa variabel untuk menyimpan nilai set data dan project BigQuery yang berisi tabel yang akan dikueri, serta ID project yang akan ditagih untuk setiap biaya.
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.
});
}
Memeriksa status tugas
Fungsi checkJobStatus
di bawah menunjukkan cara memeriksa status tugas secara berkala, menggunakan metode API get
dan jobId
yang ditampilkan oleh permintaan kueri asli. Berikut contoh yang berjalan setiap 500 milidetik hingga tugas selesai.
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]);
});
}
Ubah metode sendQuery
untuk memanggil metode checkJobStatus()
sebagai callback dalam panggilan request.execute()
. Teruskan ID tugas ke checkJobStatus
. Hal ini diekspos oleh objek respons sebagai 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));
}
Mendapatkan hasil kueri
Untuk mendapatkan hasil kueri setelah selesai dijalankan, gunakan panggilan API jobs.getQueryResults
. Tambahkan fungsi ke halaman Anda yang disebut getQueryResults()
, yang menerima parameter jobId
:
function getQueryResults(jobId){
let request = gapi.client.bigquery.jobs.getQueryResults({
'projectId': billingProjectId,
'jobId': jobId
});
request.execute(response => {
// Do something with the results.
})
}
9. Membuat kueri data lokasi dengan BigQuery API
Ada tiga cara untuk menggunakan SQL guna menjalankan kueri spasial terhadap data di BigQuery:
- memilih berdasarkan persegi panjang (juga dikenal sebagai kotak pembatas),
- pilih menurut radius, dan
- fitur Fungsi yang Ditentukan Pengguna yang canggih.
Ada contoh kueri kotak pembatas dan radius di bagian Fungsi Matematika dalam Referensi SQL lama BigQuery, di bagian 'Contoh Lanjutan'.
Untuk kueri kotak pembatas dan radius, Anda dapat memanggil metode query
BigQuery API. Buat SQL untuk setiap kueri dan teruskan ke fungsi sendQuery
yang Anda buat pada langkah sebelumnya.
Contoh kode yang berfungsi untuk langkah ini ada di step4/map.html.
Kueri persegi panjang
Cara paling sederhana untuk menampilkan data BigQuery di peta adalah dengan meminta semua baris yang lintang dan bujurnya berada dalam persegi panjang, menggunakan perbandingan kurang dari dan lebih dari. Hal ini dapat berupa tampilan peta saat ini atau bentuk yang digambar di peta.
Untuk menggunakan bentuk yang digambar oleh pengguna, ubah kode di index.html
untuk menangani peristiwa gambar yang diaktifkan saat persegi panjang selesai. Dalam contoh ini, kode menggunakan getBounds()
pada objek persegi panjang untuk mendapatkan objek yang merepresentasikan luas persegi panjang dalam koordinat peta, dan meneruskannya ke fungsi yang disebut rectangleQuery
:
drawingManager.addListener('rectanglecomplete', rectangle => rectangleQuery(rectangle.getBounds()));
Fungsi rectangleQuery
hanya perlu menggunakan koordinat kanan atas (timur laut) dan kiri bawah (barat daya) untuk membuat perbandingan kurang dari/lebih dari terhadap setiap baris dalam tabel BigQuery Anda. Berikut adalah contoh yang mengkueri tabel yang memiliki kolom bernama 'pickup_latitude'
dan 'pickup_longitude'
yang menyimpan nilai lokasi.
Menentukan tabel BigQuery
Untuk membuat kueri tabel menggunakan BigQuery API, Anda harus memberikan nama tabel dalam bentuk yang sepenuhnya memenuhi syarat dalam kueri SQL Anda. Format di SQL Standar adalah project.dataset.tablename
. Di Legacy SQL, nilainya adalah project.dataset.tablename
.
Ada banyak tabel perjalanan Taksi NYC yang tersedia. Untuk melihatnya, buka konsol web BigQuery dan luaskan item menu "public datasets". Temukan set data bernama new_york
dan luaskan untuk melihat tabel. Pilih tabel perjalanan Yellow Taxi: bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2016
).
Menentukan Project ID
Dalam panggilan API, Anda perlu menentukan nama project Google Cloud Platform untuk tujuan penagihan. Dalam codelab ini, project ini bukan project yang sama dengan project yang berisi tabel. Jika Anda bekerja dengan tabel yang telah dibuat di project Anda sendiri dengan mengupload data, Project ID ini akan sama dengan yang ada di pernyataan SQL Anda.
Tambahkan variabel JavaScript ke kode Anda untuk menyimpan referensi ke project Set Data Publik yang berisi tabel yang Anda kueri, ditambah nama tabel dan nama set data. Anda juga memerlukan variabel terpisah untuk merujuk ke Project ID penagihan Anda sendiri.
Tambahkan variabel JavaScript global bernama billingProjectId, publicProjectId, datasetId
dan tableName
ke salinan index.html Anda.
Lakukan inisialisasi variabel 'publicProjectId'
, 'datasetId'
, dan 'tableName'
dengan detail dari project Set Data Publik BigQuery. Lakukan inisialisasi billingProjectId
dengan Project ID Anda sendiri (yang Anda buat di "Penyiapan" sebelumnya dalam codelab ini).
let billingProjectId = 'YOUR_PROJECT_ID';
let publicProjectId = 'bigquery-public-data';
let datasetId = 'new_york_taxi_trips';
let tableName = 'tlc_yellow_trips_2016';
Sekarang tambahkan dua fungsi ke kode Anda untuk membuat SQL dan mengirim kueri ke BigQuery menggunakan fungsi sendQuery
yang Anda buat pada langkah sebelumnya.
Fungsi pertama harus disebut rectangleSQL()
dan harus menerima dua argumen, sepasang objek google.Maps.LatLng
yang merepresentasikan sudut persegi panjang dalam koordinat peta.
Fungsi kedua harus dipanggil rectangleQuery()
. Tindakan ini akan meneruskan teks kueri ke fungsi 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;
}
Pada tahap ini, Anda memiliki cukup kode untuk mengirim kueri ke BigQuery untuk semua baris yang tercakup dalam persegi panjang yang digambar oleh pengguna. Sebelum menambahkan metode kueri lain untuk lingkaran dan bentuk bebas, mari kita lihat cara menangani data yang kembali dari kueri.
10. Memvisualisasikan respons
Tabel BigQuery bisa sangat besar—Petabyte data—dan dapat bertambah ratusan ribu baris per detik. Jadi, penting untuk mencoba dan membatasi jumlah data yang ditampilkan agar dapat digambar di peta. Menggambar lokasi setiap baris dalam set hasil yang sangat besar (puluhan ribu baris atau lebih) akan menghasilkan peta yang tidak dapat dibaca. Ada banyak teknik untuk menggabungkan lokasi baik dalam kueri SQL maupun di peta, dan Anda dapat membatasi hasil yang akan ditampilkan kueri.
Kode lengkap untuk langkah ini tersedia di step5/map.html.
Untuk menjaga jumlah data yang ditransfer ke halaman web Anda agar berukuran wajar untuk codelab ini, ubah fungsi rectangleSQL()
untuk menambahkan pernyataan yang membatasi respons hingga 10.000 baris. Dalam contoh di bawah, nilai ini ditentukan dalam variabel global bernama recordLimit
, sehingga semua fungsi kueri dapat menggunakan nilai yang sama.
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;
}
Untuk memvisualisasikan kepadatan lokasi, Anda dapat menggunakan peta panas. Maps JavaScript API memiliki class HeatmapLayer untuk tujuan ini. HeatmapLayer mengambil array koordinat garis lintang dan garis bujur sehingga cukup mudah untuk mengonversi baris yang ditampilkan dari kueri menjadi peta panas.
Dalam fungsi getQueryResults
, teruskan array response.result.rows
ke fungsi Javascript baru bernama doHeatMap()
yang akan membuat peta panas.
Setiap baris akan memiliki properti bernama f
yang merupakan array kolom. Setiap kolom akan memiliki properti v
yang berisi nilai.
Kode Anda perlu melakukan loop pada kolom di setiap baris dan mengekstrak nilai.
Dalam kueri SQL, Anda hanya meminta nilai Latitude dan Longitude dari lokasi penjemputan taksi, sehingga hanya akan ada dua kolom dalam respons.
Jangan lupa untuk memanggil setMap()
di lapisan peta panas setelah Anda menetapkan array posisi ke lapisan tersebut. Tindakan ini akan membuatnya terlihat di peta.
Berikut contohnya:
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);
}
Pada tahap ini, Anda akan dapat:
- Membuka halaman dan memberikan otorisasi terhadap BigQuery
- Gambar persegi panjang di suatu tempat di NYC
- Lihat hasil kueri yang dihasilkan yang divisualisasikan sebagai peta panas.
Berikut adalah contoh hasil dari kueri persegi terhadap data Taksi Kuning NYC 2016, yang digambarkan sebagai peta panas. Hal ini menunjukkan distribusi pengambilan di sekitar Empire State Building pada hari Sabtu di bulan Juli:
11. Membuat kueri berdasarkan radius di sekitar titik
Kueri radius sangat mirip. Dengan menggunakan Fungsi matematika SQL Lama BigQuery, Anda dapat membuat kueri SQL menggunakan Formula Haversine yang memperkirakan area melingkar di permukaan bumi.
Dengan menggunakan teknik yang sama untuk persegi panjang, Anda dapat menangani peristiwa OverlayComplete
untuk mendapatkan pusat dan radius lingkaran yang digambar pengguna, serta membuat SQL untuk kueri dengan cara yang sama.
Contoh kode yang berfungsi untuk langkah ini disertakan dalam repositori kode sebagai step6/map.html.
drawingManager.addListener('circlecomplete', circle => circleQuery(circle));
Di salinan index.html, tambahkan dua fungsi kosong baru: circleQuery()
dan haversineSQL()
.
Kemudian, tambahkan pengendali peristiwa circlecomplete
yang meneruskan pusat dan radius ke fungsi baru yang disebut circleQuery().
Fungsi circleQuery()
akan memanggil haversineSQL()
untuk membuat SQL untuk kueri, lalu mengirim kueri dengan memanggil fungsi sendQuery()
sesuai dengan contoh kode berikut.
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;
}
Cobalah!
Tambahkan kode di atas dan coba alat 'Lingkaran' untuk memilih area peta. Hasilnya akan terlihat seperti ini:
12. Mengkueri bentuk arbitrer
Ringkasan: SQL tidak mendukung kueri menggunakan bentuk arbitrer selain persegi panjang dan lingkaran. BigQuery tidak memiliki jenis data geometri native, jadi untuk menjalankan kueri menggunakan bentuk poligon, Anda memerlukan pendekatan yang berbeda dari kueri SQL langsung.
Salah satu fitur BigQuery yang sangat canggih yang dapat digunakan untuk tujuan ini adalah Fungsi yang Ditentukan Pengguna (UDF). UDF menjalankan kode JavaScript di dalam kueri SQL.
Kode yang berfungsi untuk langkah ini ada di step7/map.html.
UDF di BigQuery API
Pendekatan BigQuery API untuk UDF sedikit berbeda dengan konsol web: Anda harus memanggil jobs.insert method
.
Untuk kueri SQL Standar melalui API, hanya satu pernyataan SQL yang diperlukan untuk menggunakan Fungsi yang Ditentukan Pengguna. Nilai useLegacySql
harus ditetapkan ke false
. Contoh JavaScript di bawah menunjukkan fungsi yang membuat dan mengirim objek permintaan untuk menyisipkan tugas baru, dalam hal ini kueri dengan Fungsi yang Ditentukan Pengguna.
Contoh praktis pendekatan ini ada di 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));
}
Kueri SQL dibuat sebagai berikut:
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;
}
Ada dua hal yang terjadi di sini. Pertama, kode membuat pernyataan CREATE TEMPORARY FUNCTION
yang merangkum kode JavaScript untuk mengetahui apakah titik tertentu berada di dalam poligon. Koordinat poligon dimasukkan menggunakan panggilan metode JSON.stringify(poly)
untuk mengonversi array JavaScript pasangan koordinat x,y menjadi string. Objek poligon diteruskan sebagai argumen ke fungsi yang membangun SQL.
Kedua, kode membuat pernyataan SQL SELECT
utama. UDF dipanggil dalam ekspresi WHERE
dalam contoh ini.
Melakukan integrasi dengan Maps API
Untuk menggunakannya dengan library gambar Maps API, kita perlu menyimpan poligon yang digambar oleh pengguna dan meneruskannya ke bagian UDF dari kueri SQL.
Pertama, kita perlu menangani peristiwa gambar polygoncomplete
, untuk mendapatkan koordinat bentuk sebagai array pasangan bujur dan lintang:
drawingManager.addListener('polygoncomplete', polygon => {
let path = polygon.getPaths().getAt(0);
let queryPolygon = path.map(element => {
return [element.lng(), element.lat()];
});
polygonQuery(queryPolygon);
});
Fungsi polygonQuery
kemudian dapat membuat fungsi Javascript UDF sebagai string, serta pernyataan SQL yang akan memanggil fungsi UDF.
Lihat step7/map.html untuk contoh penggunaan ini.
Contoh output
Berikut contoh hasil kueri penjemputan dari Data Taksi Kuning TLC NYC 2016 di BigQuery menggunakan poligon bebas, dengan data yang dipilih digambar sebagai peta panas.
13. Mempelajari Lebih Lanjut
Berikut beberapa saran tentang cara memperluas codelab ini untuk melihat aspek lain dari data. Anda dapat menemukan contoh ide ini yang berfungsi di step8/map.html di repositori kode.
Memetakan penghentian
Sejauh ini, kita hanya memetakan lokasi pengambilan. Dengan meminta kolom dropoff_latitude
dan dropoff_longitude
serta mengubah kode peta panas untuk memplotnya, Anda dapat melihat tujuan perjalanan taksi yang dimulai di lokasi tertentu.
Misalnya, mari kita lihat di mana taksi cenderung menurunkan penumpang saat mereka meminta penjemputan di sekitar Empire State Building.
Ubah kode untuk pernyataan SQL di polygonSql()
untuk meminta kolom ini selain lokasi pengambilan.
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;
}
Fungsi doHeatMap
kemudian dapat menggunakan nilai penghentian sebagai gantinya. Objek hasil memiliki skema yang dapat diperiksa untuk menemukan lokasi kolom ini dalam array. Dalam hal ini, posisi indeksnya adalah 2 dan 3. Indeks ini dapat dibaca dari variabel untuk membuat kode lebih mudah dikelola. Perhatikan bahwa maxIntensity
peta panas ditetapkan untuk menampilkan kepadatan 20 penghentian per piksel sebagai maksimum.
Tambahkan beberapa variabel agar Anda dapat mengubah kolom yang digunakan untuk data peta panas.
// 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);
}
Berikut adalah peta panas yang menunjukkan distribusi pengantaran dari semua lokasi penjemputan di sekitar Empire State Building pada tahun 2016. Anda dapat melihat konsentrasi besar (gumpalan merah) tujuan di Midtown, terutama di sekitar Times Square, serta di sepanjang 5th Avenue antara 23rd St dan 14th St. Lokasi dengan kepadatan tinggi lainnya yang tidak ditampilkan pada tingkat zoom ini mencakup bandara La Guardia dan JFK, World Trade Center, dan Battery Park.
Menata gaya peta dasar
Saat membuat Google Maps menggunakan Maps JavaScript API, Anda dapat menyetel gaya peta menggunakan objek JSON. Untuk visualisasi data, warna dalam peta dapat diredam. Anda dapat membuat dan mencoba gaya peta menggunakan Wizard Penataan Gaya Google Maps API di mapstyle.withgoogle.com.
Anda dapat menetapkan gaya peta saat menginisialisasi objek peta, atau kapan saja setelahnya. Berikut cara menambahkan gaya kustom dalam fungsi 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();
}
Gaya sampel di bawah menampilkan peta skala abu-abu dengan label lokasi menarik.
[
{
"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"
}
]
}
]
Memberikan masukan kepada pengguna
Meskipun BigQuery biasanya memberikan respons dalam hitungan detik, terkadang berguna untuk menunjukkan kepada pengguna bahwa sesuatu sedang terjadi saat kueri sedang berjalan.
Tambahkan beberapa UI ke halaman web Anda yang menampilkan respons fungsi checkJobStatus()
, dan grafik animasi untuk menunjukkan bahwa kueri sedang berlangsung.
Informasi yang dapat Anda tampilkan mencakup durasi kueri, jumlah data yang ditampilkan, dan jumlah data yang diproses.
Tambahkan beberapa HTML setelah <div>
peta untuk membuat panel ke halaman yang akan menampilkan jumlah baris yang ditampilkan oleh kueri, waktu yang diperlukan kueri, dan jumlah data yang diproses.
<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>
Tampilan dan posisi panel ini dikontrol oleh CSS. Tambahkan CSS untuk memosisikan panel di sudut kiri atas halaman di bawah tombol jenis peta dan toolbar gambar seperti pada cuplikan di bawah.
#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;
}
Grafik animasi dapat ditambahkan ke halaman, tetapi disembunyikan hingga diperlukan, dan beberapa kode JavaScript dan CSS digunakan untuk menampilkannya saat tugas BigQuery sedang berjalan.
Tambahkan beberapa HTML untuk menampilkan grafik animasi. Ada file gambar bernama loader.gif
di folder img
dalam repositori kode.
<img id="spinner" src="img/loader.gif">
Tambahkan beberapa CSS untuk memosisikan gambar dan menyembunyikannya secara default hingga diperlukan.
#spinner {
position: absolute;
top: 50%;
left: 50%;
margin-left: -32px;
margin-top: -32px;
opacity: 0;
z-index: -1000;
}
Terakhir, tambahkan beberapa JavaScript untuk memperbarui panel status dan menampilkan atau menyembunyikan grafik saat kueri sedang berjalan. Anda dapat menggunakan objek response
untuk memperbarui panel, bergantung pada informasi yang tersedia.
Saat memeriksa tugas saat ini, ada properti response.statistics
yang dapat Anda gunakan. Setelah tugas selesai, Anda dapat mengakses properti response.totalRows
dan response.totalBytesProcessed
. Pengguna akan terbantu jika milidetik dikonversi menjadi detik dan byte dikonversi menjadi gigabyte untuk ditampilkan seperti yang ditunjukkan dalam contoh kode di bawah.
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';
}
}
Panggil metode ini saat ada respons terhadap panggilan checkJobStatus()
dan saat hasil kueri diambil. Contoh:
// 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);
})
}
Untuk berganti-ganti grafik animasi, tambahkan fungsi untuk mengontrol visibilitasnya. Fungsi ini akan mengubah keburaman Elemen DOM HTML apa pun yang diteruskan ke fungsi tersebut.
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;
}
}
Terakhir, panggil metode ini sebelum memproses kueri, dan setelah hasil kueri kembali dari BigQuery.
Kode ini memanggil fungsi fadeToggle
saat pengguna selesai menggambar persegi panjang.
drawingManager.addListener('rectanglecomplete', rectangle => {
//show an animation to indicate that something is happening.
fadeToggle(document.getElementById('spinner'));
rectangleQuery(rectangle.getBounds());
});
Setelah respons kueri diterima, panggil fadeToggle()
lagi untuk menyembunyikan grafik animasi.
// 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);
})
}
Halaman akan terlihat seperti ini.
Lihat contoh lengkap di step8/map.html.
14. Hal-Hal yang Perlu Dipertimbangkan
Terlalu Banyak Penanda
Jika Anda menggunakan tabel yang sangat besar, kueri Anda mungkin menampilkan terlalu banyak baris untuk ditampilkan secara efisien di peta. Batasi hasil dengan menambahkan klausa WHERE
atau pernyataan LIMIT
.
Menggambar banyak penanda dapat membuat peta sulit dibaca. Pertimbangkan untuk menggunakan HeatmapLayer
untuk menunjukkan kepadatan, atau mengelompokkan penanda untuk menunjukkan lokasi banyak titik data menggunakan satu simbol per kelompok. Ada detail selengkapnya di tutorial Pengelompokan Penanda kami.
Mengoptimalkan Kueri
BigQuery akan memindai seluruh tabel dengan setiap kueri. Untuk mengoptimalkan penggunaan kuota BigQuery, pilih hanya kolom yang Anda butuhkan dalam kueri.
Kueri akan lebih cepat jika Anda menyimpan lintang dan bujur sebagai float, bukan string.
Mengekspor Hasil Menarik
Contoh di sini mengharuskan pengguna akhir diautentikasi terhadap tabel BigQuery, yang tidak sesuai untuk setiap kasus penggunaan. Setelah menemukan beberapa pola yang menarik, Anda dapat membagikannya dengan lebih mudah kepada audiens yang lebih luas dengan mengekspor hasil dari BigQuery dan membuat set data statis menggunakan Lapisan Data Google Maps.
Bagian Hukum yang Membosankan
Perhatikan Persyaratan Layanan Google Maps Platform. Untuk mengetahui detail selengkapnya tentang harga Google Maps Platform, lihat dokumentasi online.
Bermain dengan Lebih Banyak Data!
Ada sejumlah set data publik di BigQuery yang memiliki kolom lintang dan bujur, misalnya set data Taksi NYC dari tahun 2009-2016, data perjalanan Uber dan Lyft di NYC, dan set data GDELT.
15. Selamat!
Kami harap hal ini membantu Anda memulai dan menjalankan beberapa kueri geo dengan cepat terhadap tabel BigQuery sehingga Anda dapat menemukan pola dan memvisualisasikannya di Google Maps. Selamat membuat peta!
Apa langkah selanjutnya?
Jika Anda ingin mempelajari Google Maps Platform atau BigQuery lebih lanjut, lihat saran berikut.
Lihat Apa itu BigQuery untuk mempelajari lebih lanjut layanan data warehouse serverless berskala petabyte dari Google.
Lihat panduan cara membuat aplikasi sederhana menggunakan BigQuery API.
Lihat panduan developer untuk library gambar untuk mengetahui detail selengkapnya tentang cara mengaktifkan interaksi pengguna untuk menggambar bentuk di Google Maps.
Lihat cara lain untuk memvisualisasikan data di Peta Google.
Lihat panduan Memulai untuk Client API Javascript guna memahami konsep dasar penggunaan Client API untuk mengakses Google API lainnya.