ค้นหาและแสดงภาพข้อมูลตำแหน่งใน BigQuery ด้วย Google Maps Platform (JavaScript)

1. ภาพรวม

Maps เป็นเครื่องมือที่มีประสิทธิภาพมากเมื่อแสดงรูปแบบในชุดข้อมูลที่เกี่ยวข้องกับตำแหน่งในบางลักษณะ ความสัมพันธ์นี้อาจเป็นชื่อสถานที่ ค่าละติจูดและลองจิจูดที่เฉพาะเจาะจง หรือชื่อพื้นที่ที่มีขอบเขตที่เฉพาะเจาะจง เช่น เขตสำมะโนประชากรหรือรหัสไปรษณีย์

เมื่อชุดข้อมูลเหล่านี้มีขนาดใหญ่มาก การค้นหาและการแสดงภาพโดยใช้เครื่องมือทั่วไปอาจทำได้ยาก การใช้ Google BigQuery เพื่อค้นหาข้อมูลและ Google Maps API เพื่อสร้างการค้นหาและแสดงภาพเอาต์พุตจะช่วยให้คุณสํารวจรูปแบบทางภูมิศาสตร์ในข้อมูลได้อย่างรวดเร็วโดยไม่ต้องตั้งค่าหรือเขียนโค้ดมากนัก และไม่ต้องจัดการระบบเพื่อจัดเก็บชุดข้อมูลขนาดใหญ่มาก

สิ่งที่คุณจะสร้าง

ในโค้ดแล็บนี้ คุณจะได้เขียนและเรียกใช้การค้นหาบางรายการที่แสดงวิธีให้ข้อมูลเชิงลึกตามสถานที่ตั้งในชุดข้อมูลสาธารณะขนาดใหญ่มากโดยใช้ BigQuery นอกจากนี้ คุณยังสร้างหน้าเว็บที่จะโหลดแผนที่โดยใช้ Google Maps Platform JavaScript API จากนั้นเรียกใช้และแสดงภาพการค้นหาเชิงพื้นที่เทียบกับชุดข้อมูลสาธารณะขนาดใหญ่เดียวกันโดยใช้ไลบรารีของไคลเอ็นต์ Google APIs สำหรับ JavaScript และ BigQuery API

สิ่งที่คุณจะได้เรียนรู้

  • วิธีค้นหาชุดข้อมูลตำแหน่งระดับเพตะไบต์ในไม่กี่วินาทีด้วย BigQuery โดยใช้การค้นหา SQL, ฟังก์ชันที่ผู้ใช้กำหนด และ BigQuery API
  • วิธีใช้ Google Maps Platform เพื่อเพิ่ม Google Maps ลงในหน้าเว็บและช่วยให้ผู้ใช้วาดรูปร่างบนแผนที่ได้
  • วิธีแสดงภาพการค้นหาเทียบกับชุดข้อมูลขนาดใหญ่บน Google Maps เช่น ในภาพตัวอย่างด้านล่าง ซึ่งแสดงความหนาแน่นของสถานที่ตั้งที่แท็กซี่ส่งผู้โดยสารในปี 2016 จากการเดินทางที่เริ่มต้นจากบล็อกรอบๆ ตึกเอ็มไพร์สเตต

Screen Shot 2017-05-09 at 11.01.12 AM.png

สิ่งที่คุณต้องมี

  • ความรู้พื้นฐานเกี่ยวกับ HTML, CSS, JavaScript, SQL และเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome
  • เว็บเบราว์เซอร์รุ่นใหม่ เช่น Chrome, Firefox, Safari หรือ Edge เวอร์ชันล่าสุด
  • โปรแกรมแก้ไขข้อความหรือ IDE ที่คุณเลือก

เทคโนโลยี

BigQuery

BigQuery คือบริการวิเคราะห์ข้อมูลของ Google สำหรับชุดข้อมูลขนาดใหญ่มาก โดยมี RESTful API และรองรับการค้นหาที่เขียนด้วย SQL หากมีข้อมูลที่มีค่าละติจูดและลองจิจูด คุณจะใช้ค่าดังกล่าวเพื่อค้นหาข้อมูลตามสถานที่ตั้งได้ ข้อดีคือคุณสามารถสำรวจชุดข้อมูลขนาดใหญ่มากเพื่อดูรูปแบบได้โดยไม่ต้องจัดการโครงสร้างพื้นฐานของเซิร์ฟเวอร์หรือฐานข้อมูล คุณจะได้รับคำตอบสำหรับคำถามภายในไม่กี่วินาทีไม่ว่าตารางจะมีขนาดใหญ่เพียงใดก็ตาม โดยใช้ความสามารถในการปรับขนาดมหาศาลและโครงสร้างพื้นฐานที่มีการจัดการของ BigQuery

Google Maps Platform

Google Maps Platform ให้สิทธิ์เข้าถึงข้อมูลแผนที่ สถานที่ และเส้นทางของ Google แบบเป็นโปรแกรม ปัจจุบันมีเว็บไซต์และแอปกว่า 2 ล้านรายการที่ใช้ API นี้เพื่อแสดงแผนที่แบบฝังและคำค้นหาตามตำแหน่งแก่ผู้ใช้

เลเยอร์การวาดของ Google Maps Platform JavaScript API ช่วยให้คุณวาดรูปร่างบนแผนที่ได้ ซึ่งสามารถแปลงเป็นอินพุตเพื่อเรียกใช้การค้นหาเทียบกับตาราง BigQuery ที่มีค่าละติจูดและลองจิจูดที่จัดเก็บไว้ในคอลัมน์

หากต้องการเริ่มต้นใช้งาน คุณต้องมีโปรเจ็กต์ Google Cloud Platform ที่เปิดใช้ BigQuery และ Maps API

2. การเริ่มต้นใช้งาน

บัญชี Google

หากยังไม่มีบัญชี Google (Gmail หรือ Google Apps) คุณต้องสร้างบัญชี

สร้างโปรเจ็กต์

ลงชื่อเข้าใช้คอนโซล Google Cloud Platform ( console.cloud.google.com) แล้วสร้างโปรเจ็กต์ใหม่ ที่ด้านบนของหน้าจอจะมีเมนูแบบเลื่อนลงของโปรเจ็กต์

f2a353c3301dc649.png

เมื่อคลิกเมนูแบบเลื่อนลงของโปรเจ็กต์นี้ คุณจะเห็นรายการเมนูที่ช่วยให้คุณสร้างโปรเจ็กต์ใหม่ได้

56a42dfa7ac27a35.png

ในช่องที่ระบุว่า "ป้อนชื่อใหม่สำหรับโปรเจ็กต์" ให้ป้อนชื่อโปรเจ็กต์ใหม่ เช่น "Codelab BigQuery"

Codelab - create project (1).png

ระบบจะสร้างรหัสโปรเจ็กต์ให้คุณ รหัสโปรเจ็กต์คือชื่อที่ไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมด โปรดจดรหัสโปรเจ็กต์ไว้เพื่อใช้ในภายหลัง มีผู้ใช้ชื่อข้างต้นแล้วและคุณจะใช้ชื่อนี้ไม่ได้ แทรกรหัสโปรเจ็กต์ของคุณเองทุกที่ที่คุณเห็น YOUR_PROJECT_ID ในโค้ดแล็บนี้

เปิดใช้การเรียกเก็บเงิน

หากต้องการลงชื่อสมัครใช้ BigQuery ให้ใช้โปรเจ็กต์ที่เลือกหรือสร้างในขั้นตอนก่อนหน้า ต้องเปิดใช้การเรียกเก็บเงินในโปรเจ็กต์นี้ เมื่อเปิดใช้การเรียกเก็บเงินแล้ว คุณจะเปิดใช้ BigQuery API ได้

วิธีเปิดใช้การเรียกเก็บเงินจะขึ้นอยู่กับว่าคุณกำลังสร้างโปรเจ็กต์ใหม่หรือเปิดใช้การเรียกเก็บเงินอีกครั้งสำหรับโปรเจ็กต์ที่มีอยู่

Google มีการทดลองใช้ฟรี 12 เดือนสำหรับการใช้งาน Google Cloud Platform มูลค่าสูงสุด $300 ซึ่งคุณอาจใช้กับ Codelab นี้ได้ ดูรายละเอียดเพิ่มเติมได้ที่ https://cloud.google.com/free/

โปรเจ็กต์ใหม่

เมื่อสร้างโปรเจ็กต์ใหม่ ระบบจะแจ้งให้คุณเลือกบัญชีสำหรับการเรียกเก็บเงินที่ต้องการลิงก์กับโปรเจ็กต์ หากมีบัญชีสำหรับการเรียกเก็บเงินเพียงบัญชีเดียว ระบบจะลิงก์บัญชีนั้นกับโปรเจ็กต์โดยอัตโนมัติ

หากไม่มีบัญชีสำหรับการเรียกเก็บเงิน คุณต้องสร้างบัญชีและเปิดใช้การเรียกเก็บเงินสำหรับโปรเจ็กต์ก่อนจึงจะใช้ฟีเจอร์ต่างๆ ของ Google Cloud Platform ได้ หากต้องการสร้างบัญชีสำหรับการเรียกเก็บเงินใหม่และเปิดใช้การเรียกเก็บเงินสำหรับโปรเจ็กต์ ให้ทำตามวิธีการในสร้างบัญชีสำหรับการเรียกเก็บเงินใหม่

โปรเจ็กต์ที่มีอยู่

หากมีโปรเจ็กต์ที่ปิดใช้การเรียกเก็บเงินชั่วคราว คุณจะเปิดใช้การเรียกเก็บเงินอีกครั้งได้โดยทำดังนี้

  1. ไปที่คอนโซล Cloud Platform
  2. จากรายการโปรเจ็กต์ ให้เลือกโปรเจ็กต์ที่จะเปิดใช้การเรียกเก็บเงินอีกครั้ง
  3. เปิดเมนูด้านซ้ายของคอนโซล แล้วเลือกการเรียกเก็บเงิน การเรียกเก็บเงิน ระบบแจ้งให้คุณเลือกบัญชีสำหรับการเรียกเก็บเงิน
  4. คลิกตั้งค่าบัญชี

สร้างบัญชีสำหรับการเรียกเก็บเงินใหม่

วิธีสร้างบัญชีสำหรับการเรียกเก็บเงินใหม่

  1. ไปที่คอนโซล Cloud Platform แล้วลงชื่อเข้าใช้ หรือหากยังไม่มีบัญชี ให้ลงชื่อสมัครใช้
  2. เปิดเมนูด้านซ้ายของคอนโซล แล้วเลือกการเรียกเก็บเงิน การเรียกเก็บเงิน
  3. คลิกปุ่มบัญชีสำหรับการเรียกเก็บเงินใหม่ (โปรดทราบว่าหากนี่ไม่ใช่บัญชีสำหรับการเรียกเก็บเงินแรกของคุณ คุณจะต้องเปิดรายการบัญชีสำหรับการเรียกเก็บเงินก่อนโดยคลิกชื่อบัญชีสำหรับการเรียกเก็บเงินที่มีอยู่ใกล้ด้านบนของหน้า จากนั้นคลิกจัดการบัญชีสำหรับการเรียกเก็บเงิน)
  4. ป้อนชื่อบัญชีสำหรับการเรียกเก็บเงินและป้อนข้อมูลสำหรับการเรียกเก็บเงิน ตัวเลือกที่คุณเห็นจะขึ้นอยู่กับประเทศตามที่อยู่สำหรับการเรียกเก็บเงิน โปรดทราบว่าสำหรับบัญชีในสหรัฐอเมริกา คุณจะเปลี่ยนสถานะภาษีไม่ได้หลังจากสร้างบัญชีแล้ว
  5. คลิกส่งและเปิดใช้การเรียกเก็บเงิน

โดยค่าเริ่มต้น ผู้ที่สร้างบัญชีสำหรับการเรียกเก็บเงินจะเป็นผู้ดูแลระบบการเรียกเก็บเงินของบัญชี

ดูข้อมูลเกี่ยวกับการยืนยันบัญชีธนาคารและการเพิ่มวิธีการชำระเงินสำรองได้ที่เพิ่ม นำออก หรืออัปเดตวิธีการชำระเงิน

เปิดใช้ BigQuery API

หากต้องการเปิดใช้ BigQuery API ในโปรเจ็กต์ ให้ไปที่หน้า BigQuery API ใน Marketplace ในคอนโซล แล้วคลิกปุ่ม "เปิดใช้" สีน้ำเงิน

3. การค้นหาข้อมูลตำแหน่งใน BigQuery

วิธีค้นหาข้อมูลตำแหน่งที่จัดเก็บเป็นค่าละติจูด ลองจิจูดใน BigQuery มี 3 วิธี

  • การค้นหารูปสี่เหลี่ยมผืนผ้า: ระบุพื้นที่ที่สนใจเป็นการค้นหาที่เลือกแถวทั้งหมดภายในช่วงละติจูดและลองจิจูดต่ำสุดและสูงสุด
  • การค้นหารัศมี: ระบุพื้นที่ที่สนใจโดยการคำนวณวงกลมรอบจุดโดยใช้สูตรฮาเวอร์ไซน์และฟังก์ชันทางคณิตศาสตร์เพื่อจำลองรูปร่างของโลก
  • การค้นหารูปหลายเหลี่ยม: ระบุรูปร่างที่กำหนดเองและใช้ฟังก์ชันที่ผู้ใช้กำหนดเพื่อแสดงตรรกะจุดในรูปหลายเหลี่ยมที่จำเป็นในการทดสอบว่าละติจูดและลองจิจูดของแต่ละแถวอยู่ภายในรูปร่างหรือไม่

หากต้องการเริ่มต้นใช้งาน ให้ใช้เครื่องมือแก้ไขการค้นหาในส่วน BigQuery ของคอนโซล Google Cloud Platform เพื่อเรียกใช้การค้นหาต่อไปนี้กับข้อมูลแท็กซี่ในนิวยอร์ก

SQL มาตรฐานเทียบกับ SQL เดิม

BigQuery รองรับ SQL 2 เวอร์ชัน ได้แก่ SQL เดิมและ SQL มาตรฐาน ส่วนอย่างหลังคือมาตรฐาน ANSI ปี 2011 ในบทแนะนำนี้ เราจะใช้ Standard SQL เนื่องจากเป็นไปตามข้อกำหนดมาตรฐานได้ดีกว่า

หากต้องการเรียกใช้ SQL เดิมในเครื่องมือแก้ไข BigQuery คุณสามารถทำได้โดยทำดังนี้

  1. คลิกปุ่ม "เพิ่มเติม"
  2. เลือก "การตั้งค่าการค้นหา" จากเมนูแบบเลื่อนลง
  3. ในส่วน "ภาษา SQL" ให้เลือกปุ่มตัวเลือก "เดิม"
  4. คลิกปุ่ม "บันทึก"

การค้นหาสี่เหลี่ยมผืนผ้า

การสร้างการค้นหาสี่เหลี่ยมผืนผ้าใน BigQuery นั้นค่อนข้างตรงไปตรงมา คุณเพียงแค่ต้องเพิ่มWHEREข้อกำหนดที่จำกัดผลลัพธ์ที่แสดงให้เฉพาะผลลัพธ์ที่มีสถานที่ตั้งซึ่งอยู่ระหว่างค่าต่ำสุดและสูงสุดสำหรับละติจูดและลองจิจูด

ลองใช้ตัวอย่างด้านล่างในคอนโซล BigQuery การค้นหานี้จะค้นหาสถิติการเดินทางโดยเฉลี่ยบางอย่างสำหรับการเดินทางที่เริ่มต้นในพื้นที่สี่เหลี่ยมผืนผ้าซึ่งมีมิดทาวน์และโลเวอร์แมนฮัตตัน คุณลองใช้ตำแหน่งอื่นได้ 2 แห่ง ยกเลิกการแสดงความคิดเห็นในอนุประโยคที่ 2 ของ WHERE เพื่อเรียกใช้การค้นหาการเดินทางที่เริ่มต้นที่สนามบิน 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

ผลลัพธ์ของคำค้นหาทั้ง 2 รายการแสดงให้เห็นว่าระยะทางในการเดินทาง ค่าโดยสาร และทิปสำหรับการรับใน 2 สถานที่นั้นแตกต่างกันอย่างมาก

แมนฮัตตัน

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

การค้นหารัศมี

นอกจากนี้ คุณยังสร้างการค้นหาระยะทางใน SQL ได้ง่ายๆ หากมีความรู้ด้านคณิตศาสตร์เล็กน้อย การใช้ฟังก์ชันทางคณิตศาสตร์ของ SQL เดิมของ BigQuery ช่วยให้คุณสร้างการค้นหา SQL โดยใช้สูตรฮาเวอร์ไซน์ ซึ่งประมาณพื้นที่วงกลมหรือส่วนทรงกลมบนพื้นผิวโลกได้

ต่อไปนี้คือตัวอย่างคำสั่ง SQL ของ BigQuery สำหรับการค้นหารูปวงกลมที่อยู่ตรงกลาง 40.73943, -73.99585 โดยมีรัศมี 0.1 กม.

โดยใช้ค่าคงที่ 111.045 กิโลเมตรเพื่อประมาณระยะทางที่แสดงด้วย 1 องศา

ซึ่งอิงตามตัวอย่างที่พบใน 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 สำหรับสูตรฮาเวอร์ไซน์ดูซับซ้อน แต่สิ่งที่คุณต้องทำคือป้อนพิกัดจุดศูนย์กลางของวงกลม รัศมี และชื่อโปรเจ็กต์ ชุดข้อมูล และตารางสำหรับ BigQuery

ต่อไปนี้คือตัวอย่างคำค้นหาที่คำนวณสถิติการเดินทางโดยเฉลี่ยสำหรับการรับที่อยู่ภายใน 100 เมตรจากตึกเอ็มไพร์สเตต คัดลอกและวางลงในเว็บคอนโซลของ BigQuery เพื่อดูผลลัพธ์ เปลี่ยนละติจูดและลองจิจูดเพื่อเปรียบเทียบกับพื้นที่อื่นๆ เช่น สถานที่ในบรองซ์

#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

ผลการค้นหาอยู่ด้านล่าง คุณจะเห็นว่าค่าทิป ค่าโดยสาร ระยะทางในการเดินทาง ขนาดของค่าทิปเมื่อเทียบกับค่าโดยสาร และค่าโดยสารเฉลี่ยต่อไมล์ที่ขับมีความแตกต่างกันมาก

ตึกเอ็มไพร์สเตท

avg_tip

avg_fare

avg_distance

avg_tip_pc

avg_fare_mile

1.17

11.08

45.28

10.53

6.42

บรองซ์

avg_tip

avg_fare

avg_distance

avg_tip_pc

avg_fare_mile

0.52

17.63

4.75

4.74

10.9

การค้นหารูปหลายเหลี่ยม

SQL ไม่รองรับการค้นหาโดยใช้รูปร่างที่กำหนดเองนอกเหนือจากสี่เหลี่ยมผืนผ้าและวงกลม BigQuery ไม่มีประเภทข้อมูลเรขาคณิตหรือดัชนีเชิงพื้นที่ในตัว ดังนั้นหากต้องการเรียกใช้การค้นหาโดยใช้รูปร่างหลายเหลี่ยม คุณจะต้องใช้วิธีการอื่นแทนการค้นหา SQL แบบตรงไปตรงมา วิธีหนึ่งคือการกำหนดฟังก์ชันเรขาคณิตใน JavaScript และเรียกใช้เป็นฟังก์ชันที่กำหนดโดยผู้ใช้ (UDF) ใน BigQuery

การดำเนินการทางเรขาคณิตหลายอย่างเขียนใน JavaScript ได้ จึงง่ายต่อการนำไปใช้และดำเนินการกับตาราง BigQuery ที่มีค่าละติจูดและลองจิจูด คุณต้องส่งรูปหลายเหลี่ยมที่กำหนดเองผ่าน UDF และทำการทดสอบกับแต่ละแถว โดยจะแสดงเฉพาะแถวที่ละติจูดและลองจิจูดอยู่ภายในรูปหลายเหลี่ยม ดูข้อมูลเพิ่มเติมเกี่ยวกับ UDF ในข้อมูลอ้างอิงของ BigQuery

อัลกอริทึมจุดในรูปหลายเหลี่ยม

การคำนวณว่าจุดอยู่ภายในรูปหลายเหลี่ยมใน JavaScript หรือไม่นั้นทำได้หลายวิธี ตัวอย่างหนึ่งคือพอร์ตจาก C ของการใช้งานที่รู้จักกันดีซึ่งใช้อัลกอริทึมการติดตามรังสีเพื่อพิจารณาว่าจุดอยู่ภายในหรือภายนอกรูปหลายเหลี่ยมโดยการนับจำนวนครั้งที่เส้นยาวอนันต์ตัดขอบเขตของรูปร่าง โดยใช้โค้ดเพียงไม่กี่บรรทัด ดังนี้

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

การพอร์ตไปยัง JavaScript

เวอร์ชัน JavaScript ของอัลกอริทึมนี้มีลักษณะดังนี้

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

เมื่อใช้ SQL มาตรฐานใน BigQuery วิธี UDF จะต้องใช้คำสั่งเดียว แต่ต้องกำหนด UDF เป็นฟังก์ชันชั่วคราวในคำสั่ง ตัวอย่างเช่น วางคำสั่ง SQL ด้านล่างลงในหน้าต่างตัวแก้ไขคำค้นหา

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

ยินดีด้วย

ตอนนี้คุณได้เรียกใช้การค้นหาเชิงพื้นที่ 3 ประเภทโดยใช้ BigQuery แล้ว ดังที่ได้เห็น สถานที่ตั้งสร้างความแตกต่างอย่างมากให้กับข้อมูลผลลัพธ์สำหรับการค้นหาเทียบกับชุดข้อมูลนี้ แต่หากคุณไม่ทราบว่าจะเรียกใช้การค้นหาที่ใด ก็ยากที่จะค้นพบรูปแบบเชิงพื้นที่เฉพาะกิจโดยใช้การค้นหา SQL เพียงอย่างเดียว

หากเราสามารถแสดงภาพข้อมูลบนแผนที่และสำรวจข้อมูลได้โดยการกำหนดพื้นที่ที่สนใจตามต้องการ คุณทำเช่นนั้นได้โดยใช้ Google Maps API ก่อนอื่นคุณต้องเปิดใช้ Maps API ตั้งค่าหน้าเว็บอย่างง่ายที่ทำงานในเครื่องของคุณ และเริ่มใช้ BigQuery API เพื่อส่งคำค้นหาจากหน้าเว็บ

4. การทำงานกับ Google Maps API

หลังจากเรียกใช้การค้นหาเชิงพื้นที่อย่างง่ายแล้ว ขั้นตอนถัดไปคือการแสดงผลลัพธ์เป็นภาพเพื่อดูรูปแบบ โดยคุณจะต้องเปิดใช้ Maps API สร้างหน้าเว็บที่ส่งการค้นหาจากแผนที่ไปยัง BigQuery จากนั้นวาดผลลัพธ์บนแผนที่

เปิดใช้ Maps JavaScript API

สำหรับ Codelab นี้ คุณจะต้องเปิดใช้ Maps JavaScript API ของ Google Maps Platform ในโปรเจ็กต์ ซึ่งทำได้ดังนี้:

  1. ในคอนโซล Google Cloud Platform ให้ไปที่ Marketplace
  2. ค้นหา "Maps JavaScript API" ใน Marketplace
  3. คลิกไทล์สำหรับ Maps JavaScript API ในผลการค้นหา
  4. คลิกปุ่ม "เปิดใช้"

สร้างคีย์ API

หากต้องการส่งคำขอไปยัง Google Maps Platform คุณจะต้องสร้างคีย์ API และส่งคีย์ดังกล่าวพร้อมกับคำขอทั้งหมด หากต้องการสร้างคีย์ API ให้ทำดังนี้

  1. ในคอนโซล Google Cloud Platform ให้คลิกเมนูแฮมเบอร์เกอร์เพื่อเปิดการนำทางด้านซ้าย
  2. เลือก "API และบริการ" > "ข้อมูลเข้าสู่ระบบ"
  3. คลิกปุ่ม "สร้างข้อมูลเข้าสู่ระบบ" แล้วเลือก "คีย์ API"
  4. คัดลอกคีย์ API ใหม่

ดาวน์โหลดโค้ดและตั้งค่าเว็บเซิร์ฟเวอร์

คลิกปุ่มต่อไปนี้เพื่อดาวน์โหลดโค้ดทั้งหมดสำหรับ Codelab นี้

คลายไฟล์ ZIP ที่ดาวน์โหลด ซึ่งจะแตกโฟลเดอร์รูท (bigquery) ที่มีโฟลเดอร์สำหรับแต่ละขั้นตอนของโค้ดแล็บนี้ พร้อมกับทรัพยากรทั้งหมดที่คุณจะต้องใช้

stepN โฟลเดอร์มีสถานะสุดท้ายที่ต้องการของแต่ละขั้นตอนในโค้ดแล็บนี้ โดยมีไว้เพื่อใช้อ้างอิง เราจะเขียนโค้ดทั้งหมดในไดเรกทอรีที่ชื่อ work

ตั้งค่าเว็บเซิร์ฟเวอร์ในเครื่อง

แม้ว่าคุณจะใช้เว็บเซิร์ฟเวอร์ของคุณเองได้ แต่ Codelab นี้ออกแบบมาให้ทำงานได้ดีกับ Chrome Web Server หากยังไม่ได้ติดตั้งแอปดังกล่าว คุณสามารถติดตั้งได้จาก Chrome เว็บสโตร์

เมื่อติดตั้งแล้ว ให้เปิดแอป ใน Chrome คุณทำได้ดังนี้

  1. เปิด Chrome
  2. พิมพ์ chrome://apps ในแถบที่อยู่ด้านบน
  3. กด Enter
  4. ในหน้าต่างที่เปิดขึ้น ให้คลิกไอคอนเว็บเซิร์ฟเวอร์ คุณยังคลิกขวาที่แอปเพื่อเปิดในแท็บปกติหรือแท็บที่ปักหมุดไว้ แบบเต็มหน้าจอ หรือหน้าต่างใหม่ได้ด้วย a3ed00e79b8bfee7.png จากนั้นคุณจะเห็นกล่องโต้ตอบนี้ ซึ่งช่วยให้คุณกำหนดค่าเว็บเซิร์ฟเวอร์ในเครื่องได้ 81b6151c3f60c948.png
  5. คลิก "เลือกโฟลเดอร์" แล้วเลือกตำแหน่งที่คุณดาวน์โหลดไฟล์ตัวอย่างของ Codelab
  6. ในส่วน "ตัวเลือก" ให้เลือกช่องข้าง "แสดง index.html โดยอัตโนมัติ" 17f4913500faa86f.png
  7. เลื่อนปุ่มเปิด/ปิดที่มีป้ายกำกับว่า "Web Server: STARTED" ไปทางซ้าย แล้วเลื่อนกลับไปทางขวาเพื่อหยุดแล้วรีสตาร์ทเว็บเซิร์ฟเวอร์

a5d554d0d4a91851.png

5. กำลังโหลดเครื่องมือแผนที่และวาดภาพ

สร้างหน้าแผนที่พื้นฐาน

เริ่มต้นด้วยหน้า HTML อย่างง่ายที่โหลด Google Maps โดยใช้ Maps JavaScript API และ JavaScript เพียงไม่กี่บรรทัด โค้ดจากตัวอย่างแผนที่แบบง่ายของ Google Maps Platform เป็นจุดเริ่มต้นที่ดี เราได้ทำซ้ำไว้ที่นี่เพื่อให้คุณคัดลอกและวางลงในโปรแกรมแก้ไขข้อความหรือ IDE ที่ต้องการ หรือคุณจะค้นหาได้โดยเปิด index.html จากที่เก็บที่คุณดาวน์โหลดก็ได้

  1. คัดลอก index.html ไปยังโฟลเดอร์ work ในสำเนาที่เก็บไว้ในเครื่องของที่เก็บ
  2. คัดลอกโฟลเดอร์ img/ ไปยังโฟลเดอร์ work/ ในสำเนาของที่เก็บในเครื่อง
  3. เปิดงาน/index.html ในโปรแกรมแก้ไขข้อความหรือ IDE
  4. แทนที่ YOUR_API_KEY ด้วยคีย์ API ที่คุณสร้างไว้ก่อนหน้านี้
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"
    async defer></script>
  1. เปิด localhost:<port>/work ในเบราว์เซอร์ โดย port คือหมายเลขพอร์ตที่ระบุในการกำหนดค่าเว็บเซิร์ฟเวอร์ในเครื่อง พอร์ตเริ่มต้นคือ 8887 คุณควรเห็นแผนที่แรกที่แสดง

หากได้รับข้อความแสดงข้อผิดพลาดในเบราว์เซอร์ ให้ตรวจสอบว่าคีย์ API ถูกต้องและเว็บเซิร์ฟเวอร์ในเครื่องทำงานอยู่

เปลี่ยนตำแหน่งเริ่มต้นและระดับการซูม

โค้ดที่ตั้งค่าตำแหน่งและระดับการซูมอยู่ในบรรทัดที่ 27 และ 28 ของ index.html และปัจจุบันมีศูนย์กลางอยู่ที่ซิดนีย์ ออสเตรเลีย

<script>
      let map;
      function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
          center: {lat: -34.397, lng: 150.644},
          zoom: 8
        });
      }
</script>

บทแนะนำนี้ใช้ได้กับข้อมูลการเดินทางด้วยแท็กซี่ใน BigQuery สำหรับนิวยอร์ก ดังนั้นต่อไปคุณจะเปลี่ยนโค้ดการเริ่มต้นแผนที่ให้กึ่งกลางที่ตั้งในนิวยอร์กซิตี้ที่ระดับการซูมที่เหมาะสม ซึ่งระดับ 13 หรือ 14 น่าจะใช้ได้ดี

หากต้องการทำเช่นนี้ ให้อัปเดตโค้ดบล็อกด้านบนเป็นโค้ดต่อไปนี้เพื่อจัดกึ่งกลางแผนที่บนตึกเอ็มไพร์สเตตและปรับระดับการซูมเป็น 14

<script>
      let map;
      function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
          center: {lat: 40.7484405, lng: -73.9878531},
          zoom: 14
        });
      }
</script>

จากนั้นโหลดแผนที่ในเบราว์เซอร์ซ้ำเพื่อดูผลลัพธ์

โหลดไลบรารีการวาดภาพและการแสดงข้อมูลด้วยภาพ

หากต้องการเพิ่มความสามารถในการวาดลงในแผนที่ คุณจะต้องเปลี่ยนสคริปต์ที่โหลด Maps JavaScript API โดยเพิ่มพารามิเตอร์ที่ไม่บังคับซึ่งจะบอก Google Maps Platform ให้เปิดใช้ไลบรารีการวาด

Codelab นี้ยังใช้ HeatmapLayer ด้วย ดังนั้นคุณจะต้องอัปเดตสคริปต์เพื่อขอไลบรารีภาพด้วย โดยทําได้โดยเพิ่มพารามิเตอร์ libraries และระบุไลบรารี visualization และ drawing เป็นค่าที่คั่นด้วยคอมมา เช่น libraries=visualization,drawing

โดยควรมีลักษณะดังนี้

<script src='http://maps.googleapis.com/maps/api/js?libraries=visualization,drawing&callback=initMap&key=YOUR_API_KEY' async defer></script>

เพิ่ม DrawingManager

หากต้องการใช้รูปร่างที่ผู้ใช้วาดเป็นข้อมูลนำเข้าในการค้นหา ให้เพิ่ม DrawingManager ลงในแผนที่โดยเปิดใช้เครื่องมือ Circle, Rectangle และ Polygon

เราขอแนะนำให้ใส่DrawingManagerโค้ดการตั้งค่าทั้งหมดลงในฟังก์ชันใหม่ ในสำเนาของ index.html ให้ทำดังนี้

  1. เพิ่มฟังก์ชันที่ชื่อ setUpDrawingTools()พร้อมโค้ดต่อไปนี้เพื่อสร้าง DrawingManager และตั้งค่าพร็อพเพอร์ตี้ map เพื่ออ้างอิงออบเจ็กต์แผนที่ในหน้า

ตัวเลือกที่ส่งไปยัง google.maps.drawing.DrawingManager(options) จะกำหนดประเภทการวาดรูปร่างเริ่มต้นและตัวเลือกการแสดงผลสำหรับรูปร่างที่วาด หากต้องการเลือกพื้นที่ในแผนที่เพื่อส่งเป็นคำค้นหา รูปร่างควรมีความทึบแสงเป็น 0 ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกที่มีได้ที่ตัวเลือก 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);
}
  1. เรียกใช้ setUpDrawingTools() ในฟังก์ชัน initMap() หลังจากสร้างออบเจ็กต์แผนที่
function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 40.744593, lng: -73.990370}, // Manhattan, New York.
    zoom: 12
  });

  setUpDrawingTools();
}
  1. โหลด index.html ซ้ำและตรวจสอบว่าคุณเห็นเครื่องมือวาด และตรวจสอบว่าคุณใช้เครื่องมือเหล่านั้นเพื่อวาดวงกลม สี่เหลี่ยมผืนผ้า และรูปหลายเหลี่ยมได้

คุณคลิกและลากเพื่อวาดวงกลมและสี่เหลี่ยมได้ แต่ต้องวาดรูปหลายเหลี่ยมโดยคลิกจุดยอดแต่ละจุด แล้วดับเบิลคลิกเพื่อวาดรูปร่างให้เสร็จ

จัดการเหตุการณ์การวาด

คุณต้องมีโค้ดเพื่อจัดการเหตุการณ์ที่เริ่มทำงานเมื่อผู้ใช้วาดรูปร่างเสร็จ เช่นเดียวกับที่ต้องมีพิกัดของรูปร่างที่วาดเพื่อสร้างคําค้นหา SQL

เราจะเพิ่มโค้ดสำหรับขั้นตอนนี้ในขั้นตอนถัดไป แต่ตอนนี้เราจะสร้างเครื่องจัดการเหตุการณ์ว่าง 3 รายการเพื่อจัดการเหตุการณ์ rectanglecomplete, circlecomplete และ polygoncomplete โดยแฮนเดิลเลอร์ไม่จำเป็นต้องเรียกใช้โค้ดใดๆ ในขั้นตอนนี้

เพิ่มโค้ดต่อไปนี้ที่ด้านล่างของฟังก์ชัน 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.
});

คุณดูตัวอย่างโค้ดที่ใช้งานได้นี้ได้ในสำเนาที่เก็บในเครื่องของที่เก็บในโฟลเดอร์ step2: step2/map.html

6. การใช้ BigQuery Client API

Google BigQuery Client API จะช่วยให้คุณไม่ต้องเขียนโค้ดบอยเลอร์เพลตจำนวนมากที่จำเป็นต่อการสร้างคำขอ แยกวิเคราะห์การตอบกลับ และจัดการการตรวจสอบสิทธิ์ Codelab นี้ใช้ BigQuery API ผ่าน Google APIs Client Library สำหรับ JavaScript เนื่องจากเราจะพัฒนาแอปพลิเคชันที่ใช้เบราว์เซอร์

จากนั้นคุณจะเพิ่มโค้ดเพื่อโหลด API นี้ในหน้าเว็บและใช้เพื่อโต้ตอบกับ BigQuery

เพิ่ม Google Client API สำหรับ JavaScript

คุณจะใช้ Google Client API สำหรับ Javascript เพื่อเรียกใช้การค้นหาใน BigQuery ในสำเนาของ index.html (ในโฟลเดอร์ work) ให้โหลด API โดยใช้แท็ก <script> ดังนี้ วางแท็กใต้แท็ก <script> ที่โหลด Maps API ทันที

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

หลังจากโหลด Google Client API แล้ว ให้ให้สิทธิ์ผู้ใช้เข้าถึงข้อมูลใน BigQuery คุณใช้ OAuth 2.0 เพื่อดำเนินการนี้ได้ ก่อนอื่นคุณต้องตั้งค่าข้อมูลเข้าสู่ระบบบางอย่างในโปรเจ็กต์ Google Cloud Console

สร้างข้อมูลเข้าสู่ระบบ OAuth 2.0

  1. ใน Google Cloud Console ให้เลือก API และบริการ > ข้อมูลเข้าสู่ระบบจากเมนูการนำทาง

ก่อนที่จะตั้งค่าข้อมูลเข้าสู่ระบบได้ คุณต้องเพิ่มการกำหนดค่าบางอย่างสำหรับหน้าจอการให้สิทธิ์ที่ผู้ใช้ปลายทางของแอปพลิเคชันจะเห็นเมื่อให้สิทธิ์แอปของคุณเข้าถึงข้อมูล BigQuery ในนามของผู้ใช้

โดยคลิกแท็บหน้าจอขอความยินยอม OAuth 2. คุณต้องเพิ่ม BigQuery API ลงในขอบเขตของโทเค็นนี้ คลิกปุ่มเพิ่มขอบเขตในส่วนขอบเขตสำหรับ Google API 3. จากรายการ ให้เลือกช่องข้างรายการ BigQuery API ที่มีขอบเขต ../auth/bigquery 4. คลิกเพิ่ม 5. ป้อนชื่อในช่อง "ชื่อแอปพลิเคชัน" 6. คลิกบันทึกเพื่อบันทึกการตั้งค่า 7. จากนั้นคุณจะสร้างรหัสไคลเอ็นต์ OAuth โดยคลิกสร้างข้อมูลเข้าสู่ระบบ

4d18a965fc760e39.png

  1. ในเมนูแบบเลื่อนลง ให้คลิกรหัสไคลเอ็นต์ OAuth 1f8b36a1c27c75f0.png
  2. ในส่วนประเภทแอปพลิเคชัน ให้เลือกเว็บแอปพลิเคชัน
  3. ในช่องชื่อแอปพลิเคชัน ให้พิมพ์ชื่อโปรเจ็กต์ เช่น "BigQuery และ Maps"
  4. ในส่วนข้อจำกัด ให้ป้อน URL ของ localhost รวมถึงหมายเลขพอร์ตในช่องต้นทาง JavaScript ที่ได้รับอนุญาต เช่น http://localhost:8887
  1. คลิกที่ปุ่มสร้าง

ป๊อปอัปจะแสดงรหัสไคลเอ็นต์และรหัสลับไคลเอ็นต์ คุณต้องมี Client ID เพื่อทำการตรวจสอบสิทธิ์กับ BigQuery คัดลอกโค้ดดังกล่าวและวางลงใน work/index.html เป็นตัวแปร JavaScript ส่วนกลางใหม่ที่ชื่อ clientId

let clientId = 'YOUR_CLIENT_ID';

7. การให้สิทธิ์และการเริ่มต้น

หน้าเว็บของคุณจะต้องให้สิทธิ์ผู้ใช้เข้าถึง BigQuery ก่อนที่จะเริ่มต้นแผนที่ ในตัวอย่างนี้ เราใช้ OAuth 2.0 ตามที่อธิบายไว้ในส่วนการให้สิทธิ์ของเอกสารประกอบ API ไคลเอ็นต์ JavaScript คุณต้องใช้รหัสไคลเอ็นต์ OAuth และรหัสโปรเจ็กต์เพื่อส่งคำค้นหา

เมื่อโหลด Google Client API ในหน้าเว็บ คุณต้องทำตามขั้นตอนต่อไปนี้

  • ให้สิทธิ์ผู้ใช้
  • หากได้รับอนุญาต ให้โหลด BigQuery API
  • โหลดและเริ่มต้นแผนที่

ดูตัวอย่างลักษณะของหน้า HTML ที่เสร็จสมบูรณ์ได้ที่ step3/map.html

ให้สิทธิ์ผู้ใช้

ผู้ใช้ปลายทางของแอปพลิเคชันต้องให้สิทธิ์แอปพลิเคชันในการเข้าถึงข้อมูลใน BigQuery ในนามของตน Google Client API สำหรับ JavaScript จะจัดการตรรกะ OAuth เพื่อดำเนินการนี้

ในการใช้งานจริง คุณมีตัวเลือกมากมายเกี่ยวกับวิธีผสานรวมขั้นตอนการให้สิทธิ์

เช่น คุณอาจเรียกใช้ authorize() จากองค์ประกอบ UI เช่น ปุ่ม หรือเรียกใช้เมื่อหน้าเว็บโหลดแล้ว ในที่นี้ เราเลือกที่จะให้สิทธิ์ผู้ใช้หลังจากที่โหลด Google Client API สำหรับ JavaScript แล้ว โดยใช้ฟังก์ชัน Callback ในgapi.load()เมธอด

เขียนโค้ดทันทีหลังจากแท็ก <script> ที่โหลด Google Client API สำหรับ Javascript เพื่อโหลดทั้งไลบรารีของไคลเอ็นต์และโมดูลการตรวจสอบสิทธิ์เพื่อให้เราตรวจสอบสิทธิ์ผู้ใช้ได้ทันที

<script src='https://apis.google.com/js/client.js'></script>
<script type='text/javascript'>
  gapi.load('client:auth', authorize);
</script>

โหลด BigQuery API เมื่อมีการให้สิทธิ์

หลังจากให้สิทธิ์ผู้ใช้แล้ว ให้โหลด BigQuery API

ก่อนอื่น ให้เรียกใช้ gapi.auth.authorize() ด้วยตัวแปร clientId ที่คุณเพิ่มในขั้นตอนก่อนหน้า จัดการการตอบกลับในฟังก์ชัน Callback ที่ชื่อ handleAuthResult

พารามิเตอร์ immediate จะควบคุมว่าจะแสดงป๊อปอัปต่อผู้ใช้หรือไม่ ตั้งค่าเป็น true เพื่อระงับป๊อปอัปการให้สิทธิ์หากผู้ใช้ได้รับอนุญาตอยู่แล้ว

เพิ่มฟังก์ชันชื่อ handleAuthResult() ลงในหน้าเว็บ ฟังก์ชันต้องใช้พารามิเตอร์ authresult ซึ่งจะช่วยให้คุณควบคุมโฟลว์ของตรรกะได้โดยขึ้นอยู่กับว่าผู้ใช้ได้รับอนุญาตสำเร็จหรือไม่

นอกจากนี้ ให้เพิ่มฟังก์ชันที่ชื่อ loadApi เพื่อโหลด BigQuery API หากผู้ใช้ได้รับอนุญาตเรียบร้อยแล้ว

เพิ่มตรรกะในฟังก์ชัน handleAuthResult() เพื่อเรียกใช้ loadApi() หากมีการส่งออบเจ็กต์ authResult ไปยังฟังก์ชัน และหากพร็อพเพอร์ตี้ error ของออบเจ็กต์มีค่าเป็น false

เพิ่มโค้ดลงในฟังก์ชัน loadApi() เพื่อโหลด BigQuery API โดยใช้วิธี 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');
}

โหลดแผนที่

ขั้นตอนสุดท้ายคือการเริ่มต้นแผนที่ คุณต้องเปลี่ยนลำดับตรรกะเล็กน้อยเพื่อดำเนินการนี้ ปัจจุบันจะเริ่มต้นเมื่อโหลด JavaScript ของ Maps API แล้ว

คุณทำได้โดยเรียกใช้ฟังก์ชัน initMap() จากเมธอด then() หลังจากเมธอด load() ในออบเจ็กต์ gapi.client

// Load BigQuery client API
function loadApi(){
  gapi.client.load('bigquery', 'v2').then(
   () => initMap()
  );
}

8. แนวคิดเกี่ยวกับ BigQuery API

โดยปกติการเรียก API ของ BigQuery จะดำเนินการภายในไม่กี่วินาที แต่การตอบกลับอาจไม่กลับมาทันที คุณต้องมีตรรกะบางอย่างเพื่อสำรวจ BigQuery เพื่อดูสถานะของงานที่ใช้เวลานาน และดึงผลลัพธ์เมื่องานเสร็จสมบูรณ์แล้วเท่านั้น

โค้ดทั้งหมดสำหรับขั้นตอนนี้อยู่ใน step4/map.html

การส่งคำขอ

เพิ่มฟังก์ชัน JavaScript ลงใน work/index.html เพื่อส่งคําค้นหาโดยใช้ API และตัวแปรบางรายการเพื่อจัดเก็บค่าของชุดข้อมูลและโปรเจ็กต์ BigQuery ที่มีตารางที่จะค้นหา รวมถึงรหัสโปรเจ็กต์ที่จะเรียกเก็บเงินสําหรับค่าใช้จ่าย

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

ตรวจสอบสถานะของงาน

checkJobStatus ฟังก์ชันด้านล่างแสดงวิธีตรวจสอบสถานะของงานเป็นระยะๆ โดยใช้เมธอด API get และ jobId ที่ส่งคืนโดยคำขอการค้นหาเดิม ต่อไปนี้คือตัวอย่างที่ทำงานทุกๆ 500 มิลลิวินาทีจนกว่างานจะเสร็จสมบูรณ์

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

แก้ไขเมธอด sendQuery เพื่อเรียกใช้เมธอด checkJobStatus() เป็นการเรียกกลับในการเรียกใช้ request.execute() ส่งรหัสงานไปยัง checkJobStatus ออบเจ็กต์การตอบกลับจะแสดงค่านี้เป็น 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));
}

การรับผลลัพธ์ของการค้นหา

หากต้องการดูผลลัพธ์ของการค้นหาเมื่อการค้นหาเสร็จสิ้นแล้ว ให้ใช้การเรียก API jobs.getQueryResults เพิ่มฟังก์ชันลงในหน้าเว็บชื่อ getQueryResults() ซึ่งยอมรับพารามิเตอร์ jobId

function getQueryResults(jobId){
  let request = gapi.client.bigquery.jobs.getQueryResults({
    'projectId': billingProjectId,
    'jobId': jobId
  });
  request.execute(response => {
    // Do something with the results.
  })
}

9. การค้นหาข้อมูลตำแหน่งด้วย BigQuery API

คุณใช้ SQL เพื่อเรียกใช้การค้นหาเชิงพื้นที่กับข้อมูลใน BigQuery ได้ 3 วิธีดังนี้

  • เลือกโดยใช้สี่เหลี่ยมผืนผ้า (หรือที่เรียกว่ากล่องขอบเขต)
  • เลือกตามรัศมี และ
  • ฟีเจอร์ฟังก์ชันที่ผู้ใช้กำหนดที่มีประสิทธิภาพ

ดูตัวอย่างการค้นหากล่องขอบเขตและรัศมีได้ในส่วนฟังก์ชันทางคณิตศาสตร์ของข้อมูลอ้างอิง SQL เดิมของ BigQuery ในส่วน "ตัวอย่างขั้นสูง"

สำหรับการค้นหากรอบล้อมและรัศมี คุณสามารถเรียกใช้เมธอด query ของ BigQuery API ได้ สร้าง SQL สำหรับการค้นหาแต่ละรายการและส่งไปยังฟังก์ชัน sendQuery ที่คุณสร้างในขั้นตอนก่อนหน้า

ตัวอย่างโค้ดที่ใช้งานได้สำหรับขั้นตอนนี้อยู่ใน step4/map.html

การค้นหาสี่เหลี่ยมผืนผ้า

วิธีที่ง่ายที่สุดในการแสดงข้อมูล BigQuery บนแผนที่คือการขอแถวทั้งหมดที่ละติจูดและลองจิจูดอยู่ภายในสี่เหลี่ยมผืนผ้า โดยใช้การเปรียบเทียบน้อยกว่าและมากกว่า ซึ่งอาจเป็นมุมมองแผนที่ปัจจุบันหรือรูปร่างที่วาดบนแผนที่

หากต้องการใช้รูปร่างที่ผู้ใช้วาด ให้เปลี่ยนโค้ดใน index.html เพื่อจัดการเหตุการณ์การวาดที่ทริกเกอร์เมื่อวาดสี่เหลี่ยมผืนผ้าเสร็จ ในตัวอย่างนี้ โค้ดใช้ getBounds() ในออบเจ็กต์สี่เหลี่ยมผืนผ้าเพื่อรับออบเจ็กต์ที่แสดงถึงขอบเขตของสี่เหลี่ยมผืนผ้าในพิกัดแผนที่ แล้วส่งไปยังฟังก์ชันที่ชื่อ rectangleQuery

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

rectangleQuery ฟังก์ชันเพียงแค่ต้องใช้พิกัดด้านขวาบน (ตะวันออกเฉียงเหนือ) และด้านซ้ายล่าง (ตะวันตกเฉียงใต้) เพื่อสร้างการเปรียบเทียบน้อยกว่า/มากกว่ากับแต่ละแถวในตาราง BigQuery ต่อไปนี้เป็นตัวอย่างที่ค้นหาตารางที่มีคอลัมน์ชื่อ 'pickup_latitude' และ 'pickup_longitude' ซึ่งจัดเก็บค่าตำแหน่ง

การระบุตาราง BigQuery

หากต้องการค้นหาตารางโดยใช้ BigQuery API คุณต้องระบุชื่อตารางในรูปแบบที่มีคุณสมบัติครบถ้วนในการค้นหา SQL รูปแบบใน SQL มาตรฐานคือ project.dataset.tablename ใน SQL เดิมคือ project.dataset.tablename

มีตารางการเดินทางด้วยแท็กซี่ในนิวยอร์กซิตี้อยู่มากมาย หากต้องการดู ให้ไปที่คอนโซลเว็บ BigQuery แล้วขยายรายการเมนู "ชุดข้อมูลสาธารณะ" ค้นหาชุดข้อมูลที่ชื่อ new_york แล้วขยายเพื่อดูตาราง เลือกตารางการเดินทางด้วยแท็กซี่สีเหลือง: bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2016)

การระบุรหัสโปรเจ็กต์

ในการเรียก API คุณต้องระบุชื่อโปรเจ็กต์ Google Cloud Platform เพื่อวัตถุประสงค์ในการเรียกเก็บเงิน ในโค้ดแล็บนี้ โปรเจ็กต์นี้ไม่ใช่โปรเจ็กต์เดียวกับที่มีตาราง หากคุณทำงานกับตารางที่สร้างขึ้นในโปรเจ็กต์ของคุณเองโดยการอัปโหลดข้อมูล รหัสโปรเจ็กต์นี้จะเหมือนกับรหัสในคำสั่ง SQL

เพิ่มตัวแปร JavaScript ลงในโค้ดเพื่อเก็บการอ้างอิงไปยังโปรเจ็กต์ชุดข้อมูลสาธารณะที่มีตารางที่คุณกำลังค้นหา รวมถึงชื่อตารางและชื่อชุดข้อมูล นอกจากนี้ คุณยังต้องมีตัวแปรแยกต่างหากเพื่ออ้างอิงรหัสโปรเจ็กต์สำหรับการเรียกเก็บเงินของคุณเองด้วย

เพิ่มตัวแปร JavaScript ร่วมที่ชื่อ billingProjectId, publicProjectId, datasetId และ tableName ลงในสำเนาของ index.html

เริ่มต้นตัวแปร 'publicProjectId', 'datasetId' และ 'tableName' ด้วยรายละเอียดจากโปรเจ็กต์ชุดข้อมูลสาธารณะของ BigQuery เริ่มต้น billingProjectId ด้วยรหัสโปรเจ็กต์ของคุณเอง (รหัสที่คุณสร้างใน "การเริ่มต้นใช้งาน" ก่อนหน้านี้ใน Codelab นี้)

let billingProjectId = 'YOUR_PROJECT_ID';
let publicProjectId = 'bigquery-public-data';
let datasetId = 'new_york_taxi_trips';
let tableName = 'tlc_yellow_trips_2016';

ตอนนี้ให้เพิ่ม 2 ฟังก์ชันลงในโค้ดเพื่อสร้าง SQL และส่งการค้นหาไปยัง BigQuery โดยใช้ฟังก์ชัน sendQuery ที่คุณสร้างไว้ในขั้นตอนก่อนหน้า

ฟังก์ชันแรกควรมีชื่อว่า rectangleSQL() และต้องยอมรับอาร์กิวเมนต์ 2 รายการ ซึ่งเป็นออบเจ็กต์ google.Maps.LatLng 2 รายการที่แสดงมุมของสี่เหลี่ยมผืนผ้าในพิกัดแผนที่

ควรเรียกใช้ฟังก์ชันที่ 2 ว่า rectangleQuery() ซึ่งจะส่งข้อความค้นหาไปยังฟังก์ชัน 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;
}

ตอนนี้คุณมีโค้ดเพียงพอที่จะส่งการค้นหาไปยัง BigQuery สำหรับแถวทั้งหมดที่อยู่ในสี่เหลี่ยมผืนผ้าที่ผู้ใช้วาด ก่อนที่จะเพิ่มวิธีการค้นหาอื่นๆ สำหรับวงกลมและรูปร่างอิสระ มาดูวิธีจัดการข้อมูลที่ได้จากการค้นหากันก่อน

10. การแสดงภาพคำตอบ

ตาราง BigQuery อาจมีขนาดใหญ่มาก (ข้อมูลระดับเพตะไบต์) และอาจเพิ่มขึ้นหลายแสนแถวต่อวินาที ดังนั้นจึงควรพยายามจำกัดจำนวนข้อมูลที่แสดงผลเพื่อให้วาดบนแผนที่ได้ การวาดตำแหน่งของทุกแถวในชุดผลลัพธ์ขนาดใหญ่มาก (หลายหมื่นแถวขึ้นไป) จะทำให้แผนที่อ่านไม่ได้ มีเทคนิคมากมายในการรวบรวมสถานที่ทั้งในคำค้นหา SQL และบนแผนที่ และคุณสามารถจำกัดผลลัพธ์ที่คำค้นหาจะแสดงได้

ดูโค้ดทั้งหมดสำหรับขั้นตอนนี้ได้ที่ step5/map.html

หากต้องการให้ปริมาณข้อมูลที่โอนไปยังหน้าเว็บมีขนาดที่เหมาะสมสำหรับ Codelab นี้ ให้แก้ไขฟังก์ชัน rectangleSQL() เพื่อเพิ่มคำสั่งที่จำกัดการตอบกลับไว้ที่ 10000 แถว ในตัวอย่างด้านล่าง เราได้ระบุค่านี้ในตัวแปรส่วนกลางที่ชื่อ recordLimit เพื่อให้ฟังก์ชันการค้นหาทั้งหมดใช้ค่าเดียวกันได้

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

หากต้องการแสดงภาพความหนาแน่นของสถานที่ตั้ง คุณสามารถใช้แผนที่ความหนาแน่นได้ Maps JavaScript API มีคลาส HeatmapLayer สำหรับจุดประสงค์นี้ HeatmapLayer รับอาร์เรย์ของพิกัดละติจูด ลองจิจูด จึงแปลงแถวที่ได้จากการค้นหาเป็นแผนที่ความร้อนได้ง่าย

ในgetQueryResults ให้ส่งอาร์เรย์ response.result.rows ไปยังฟังก์ชัน JavaScript ใหม่ที่ชื่อ doHeatMap() ซึ่งจะสร้างฮีตแมป

แต่ละแถวจะมีพร็อพเพอร์ตี้ชื่อ f ซึ่งเป็นอาร์เรย์ของคอลัมน์ แต่ละคอลัมน์จะมีพร็อพเพอร์ตี้ v ที่มีค่า

โค้ดของคุณต้องวนซ้ำผ่านคอลัมน์ในแต่ละแถวและดึงค่าออกมา

ในคำค้นหา SQL คุณขอเฉพาะค่าละติจูดและลองจิจูดของจุดขึ้นแท็กซี่ ดังนั้นการตอบกลับจะมีเพียง 2 คอลัมน์

อย่าลืมเรียกใช้ setMap() ในเลเยอร์ฮีตแมปเมื่อกำหนดอาร์เรย์ของตำแหน่งให้กับเลเยอร์ ซึ่งจะทำให้สถานที่ดังกล่าวปรากฏบนแผนที่

เช่น

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

ในตอนนี้ คุณควรจะทำสิ่งต่อไปนี้ได้

  • เปิดหน้าเว็บและให้สิทธิ์เข้าถึง BigQuery
  • วาดสี่เหลี่ยมผืนผ้าที่ใดก็ได้ในนิวยอร์ก
  • ดูผลลัพธ์ของคำค้นหาที่ได้ซึ่งแสดงเป็นแผนที่ความหนาแน่น

นี่คือตัวอย่างผลลัพธ์จากการค้นหาสี่เหลี่ยมผืนผ้าเทียบกับข้อมูลแท็กซี่สีเหลืองในนิวยอร์กปี 2016 ซึ่งวาดเป็นแผนที่ความร้อน แผนที่นี้แสดงการกระจายตัวของการรับส่งรอบตึกเอ็มไพร์สเตตในวันเสาร์ของเดือนกรกฎาคม

7b1face0e7c71c78.png

11. การค้นหาตามรัศมีรอบจุด

ข้อความค้นหาระยะทางคล้ายกันมาก การใช้ ฟังก์ชันทางคณิตศาสตร์ของ SQL เดิมของ BigQuery คุณสามารถสร้างการค้นหา SQL โดยใช้สูตรฮาเวอร์ไซน์ซึ่งประมาณพื้นที่วงกลมบนพื้นผิวโลก

การใช้วิธีเดียวกันกับสี่เหลี่ยมผืนผ้า คุณสามารถจัดการเหตุการณ์ OverlayComplete เพื่อรับจุดศูนย์กลางและรัศมีของวงกลมที่ผู้ใช้วาด และสร้าง SQL สำหรับการค้นหาในลักษณะเดียวกันได้

ตัวอย่างโค้ดที่ใช้งานได้สำหรับขั้นตอนนี้จะรวมอยู่ในที่เก็บโค้ดเป็น step6/map.html

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

ในสำเนาของ index.html ให้เพิ่มฟังก์ชันว่างใหม่ 2 ฟังก์ชัน ได้แก่ circleQuery() และ haversineSQL()

จากนั้นเพิ่มcirclecompleteตัวแฮนเดิลเหตุการณ์ที่ส่งศูนย์กลางและรัศมีไปยังฟังก์ชันใหม่ที่ชื่อ circleQuery().

circleQuery() ฟังก์ชันจะเรียก haversineSQL() เพื่อสร้าง SQL สำหรับการค้นหา แล้วส่งการค้นหาโดยเรียกฟังก์ชัน sendQuery() ตามโค้ดตัวอย่างต่อไปนี้

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

ลองใช้งาน

เพิ่มโค้ดด้านบน แล้วลองใช้เครื่องมือ "วงกลม" เพื่อเลือกพื้นที่ของแผนที่ ผลลัพธ์ควรมีลักษณะดังนี้

845418166b7cc7a3.png

12. การค้นหารูปทรงที่กำหนดเอง

สรุป: SQL ไม่รองรับการค้นหาโดยใช้รูปร่างที่กำหนดเองนอกเหนือจากสี่เหลี่ยมผืนผ้าและวงกลม BigQuery ไม่มีประเภทข้อมูลเรขาคณิตดั้งเดิม ดังนั้นหากต้องการเรียกใช้การค้นหาโดยใช้รูปร่างหลายเหลี่ยม คุณจะต้องใช้วิธีการอื่นแทนการค้นหา SQL แบบตรงไปตรงมา

ฟีเจอร์ BigQuery ที่มีประสิทธิภาพมากอย่างหนึ่งซึ่งใช้สำหรับกรณีนี้ได้คือฟังก์ชันที่กำหนดโดยผู้ใช้ (UDF) UDF จะเรียกใช้โค้ด JavaScript ภายในคำค้นหา SQL

โค้ดที่ใช้งานได้สำหรับขั้นตอนนี้อยู่ใน step7/map.html

UDF ใน BigQuery API

แนวทาง BigQuery API สำหรับ UDF จะแตกต่างจากเว็บคอนโซลเล็กน้อย โดยคุณจะต้องเรียกใช้ jobs.insert method

สําหรับการค้นหา SQL มาตรฐานผ่าน API คุณต้องใช้คําสั่ง SQL เพียงรายการเดียวเพื่อใช้ฟังก์ชันที่ผู้ใช้กําหนด ค่าของ useLegacySql ต้องตั้งค่าเป็น false ตัวอย่าง JavaScript ด้านล่างแสดงฟังก์ชันที่สร้างและส่งออบเจ็กต์คำขอเพื่อแทรกงานใหม่ ในกรณีนี้คือการค้นหาที่มีฟังก์ชันที่ผู้ใช้กำหนด

ตัวอย่างที่ใช้งานได้ของแนวทางนี้อยู่ใน 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));
}

การค้นหา SQL มีโครงสร้างดังนี้

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

มี 2 สิ่งที่เกิดขึ้นที่นี่ ขั้นแรก โค้ดจะสร้างคำสั่ง CREATE TEMPORARY FUNCTION ที่ห่อหุ้มโค้ด JavaScript เพื่อดูว่าจุดที่กำหนดอยู่ภายในรูปหลายเหลี่ยมหรือไม่ ระบบจะแทรกพิกัดรูปหลายเหลี่ยมโดยใช้การเรียกเมธอด JSON.stringify(poly) เพื่อแปลงอาร์เรย์ JavaScript ของคู่พิกัด x,y เป็นสตริง ระบบจะส่งออบเจ็กต์รูปหลายเหลี่ยมเป็นอาร์กิวเมนต์ไปยังฟังก์ชันที่สร้าง SQL

ประการที่สอง โค้ดจะสร้างคำสั่ง SQL หลัก SELECT ในตัวอย่างนี้ ระบบจะเรียกใช้ UDF ในนิพจน์ WHERE

การผสานรวมกับ Maps API

หากต้องการใช้ฟีเจอร์นี้กับไลบรารีการวาดของ Maps API เราต้องบันทึกรูปหลายเหลี่ยมที่ผู้ใช้วาดและส่งไปยังส่วน UDF ของคำค้นหา SQL

ก่อนอื่นเราต้องจัดการpolygoncompleteเหตุการณ์การวาดเพื่อรับพิกัดของรูปร่างเป็นอาร์เรย์ของคู่ลองจิจูดและละติจูด

drawingManager.addListener('polygoncomplete', polygon => {
  let path = polygon.getPaths().getAt(0);
  let queryPolygon = path.map(element => {
    return [element.lng(), element.lat()];
  });
  polygonQuery(queryPolygon);
});

จากนั้น polygonQuery ฟังก์ชันจะสร้างฟังก์ชัน JavaScript ของ UDF เป็นสตริง รวมถึงคำสั่ง SQL ที่จะเรียกใช้ฟังก์ชัน UDF

ดูตัวอย่างการทำงานของฟีเจอร์นี้ได้ที่ step7/map.html

ตัวอย่างเอาต์พุต

ต่อไปนี้คือตัวอย่างผลลัพธ์ของการค้นหาการรับจากข้อมูลแท็กซี่สีเหลืองของ NYC TLC ปี 2016 ใน BigQuery โดยใช้รูปหลายเหลี่ยมแบบอิสระ และวาดข้อมูลที่เลือกเป็นฮีตแมป

Screen Shot 2017-05-09 at 10.00.48 AM.png

13. ก้าวไปอีกขั้น

คำแนะนำเกี่ยวกับวิธีขยาย Codelab นี้เพื่อดูแง่มุมอื่นๆ ของข้อมูลมีดังนี้ คุณดูตัวอย่างการทำงานของแนวคิดเหล่านี้ได้ที่ step8/map.html ในที่เก็บโค้ด

การหยุดกลางคันระหว่างการแมป

ขณะนี้เราได้ทำแผนที่เฉพาะสถานที่รับเท่านั้น การขอคอลัมน์ dropoff_latitude และ dropoff_longitude รวมถึงการแก้ไขโค้ดฮีตแมปเพื่อพล็อตคอลัมน์เหล่านี้แทน จะช่วยให้คุณเห็นจุดหมายปลายทางของการเดินทางด้วยแท็กซี่ที่เริ่มต้นจากสถานที่ตั้งที่เฉพาะเจาะจง

เช่น มาดูกันว่าแท็กซี่มักจะส่งผู้โดยสารที่ไหนเมื่อมีการขอรับรถแถวเอ็มไพร์สเตตบิลดิง

เปลี่ยนโค้ดสำหรับคำสั่ง SQL ใน polygonSql() เพื่อขอคอลัมน์เหล่านี้เพิ่มเติมจากสถานที่รับสินค้า

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

จากนั้นฟังก์ชัน doHeatMap จะใช้ค่าการทิ้งแทนได้ ออบเจ็กต์ผลลัพธ์มีสคีมาที่ตรวจสอบได้เพื่อค้นหาตำแหน่งของคอลัมน์เหล่านี้ในอาร์เรย์ ในกรณีนี้ จะอยู่ที่ตำแหน่งดัชนี 2 และ 3 คุณอ่านดัชนีเหล่านี้จากตัวแปรเพื่อให้จัดการโค้ดได้ง่ายขึ้น โปรดทราบว่า maxIntensity ของฮีตแมปได้รับการตั้งค่าให้แสดงความหนาแน่นของการออก 20 ครั้งต่อพิกเซลเป็นค่าสูงสุด

เพิ่มตัวแปรบางอย่างเพื่อให้คุณเปลี่ยนคอลัมน์ที่ใช้สำหรับข้อมูลฮีตแมปได้

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

แผนที่ความหนาแน่นนี้แสดงการกระจายของการส่งที่ยกเลิกจากจุดรับทั้งหมดที่อยู่รอบๆ ตึกเอ็มไพร์สเตตในปี 2016 คุณจะเห็นจุดหมายปลายทางในมิดทาวน์ (จุดสีแดง) กระจุกตัวอยู่เป็นจำนวนมาก โดยเฉพาะบริเวณไทม์สแควร์ รวมถึงตามถนน 5th Avenue ระหว่างถนน 23rd St กับ 14th St ส่วนสถานที่อื่นๆ ที่มีความหนาแน่นสูงซึ่งไม่แสดงในระดับการซูมนี้ ได้แก่ สนามบิน La Guardia และ JFK, เวิลด์เทรดเซ็นเตอร์ และแบตเตอรีพาร์ก

Screen Shot 2017-05-09 at 10.40.01 AM.png

การจัดรูปแบบแผนที่ฐาน

เมื่อสร้างแผนที่ Google โดยใช้ Maps JavaScript API คุณจะตั้งค่ารูปแบบแผนที่ได้โดยใช้ออบเจ็กต์ JSON การปิดเสียงสีในแผนที่อาจมีประโยชน์สำหรับการแสดงข้อมูลด้วยภาพ คุณสร้างและลองใช้รูปแบบแผนที่ได้โดยใช้ Google Maps API Styling Wizard ที่ mapstyle.withgoogle.com

คุณตั้งค่ารูปแบบแผนที่ได้เมื่อเริ่มต้นออบเจ็กต์แผนที่ หรือในภายหลังได้ทุกเมื่อ วิธีเพิ่มสไตล์ที่กำหนดเองในฟังก์ชัน 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();
}

รูปแบบตัวอย่างด้านล่างแสดงแผนที่แบบระดับสีเทาที่มีป้ายกำกับจุดที่น่าสนใจ

[
  {
    "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"
      }
    ]
  }
]

แสดงความคิดเห็นต่อผู้ใช้

แม้ว่าโดยปกติแล้ว BigQuery จะให้การตอบกลับภายในไม่กี่วินาที แต่บางครั้งก็มีประโยชน์ที่จะแสดงให้ผู้ใช้เห็นว่ามีบางอย่างเกิดขึ้นขณะที่การค้นหาทำงานอยู่

เพิ่ม UI บางอย่างลงในหน้าเว็บซึ่งแสดงการตอบกลับของฟังก์ชัน checkJobStatus() และกราฟิกเคลื่อนไหวเพื่อระบุว่าคำค้นหาอยู่ระหว่างดำเนินการ

ข้อมูลที่คุณแสดงได้ ได้แก่ ระยะเวลาการค้นหา จำนวนข้อมูลที่แสดง และจำนวนข้อมูลที่ประมวลผล

เพิ่ม HTML บางส่วนหลังแผนที่ <div> เพื่อสร้างแผงในหน้าที่จะแสดงจำนวนแถวที่คำค้นหาแสดงผล เวลาที่ใช้ในการค้นหา และปริมาณข้อมูลที่ประมวลผล

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

ลักษณะและตำแหน่งของแผงนี้ควบคุมโดย CSS เพิ่ม CSS เพื่อจัดตำแหน่งแผงที่มุมซ้ายบนของหน้าเว็บใต้ปุ่มประเภทแผนที่และแถบเครื่องมือวาดตามที่แสดงในข้อมูลโค้ดด้านล่าง

#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;
}

คุณเพิ่มกราฟิกเคลื่อนไหวลงในหน้าเว็บได้ แต่ต้องซ่อนไว้จนกว่าจะจำเป็น และใช้โค้ด JavaScript และ CSS บางส่วนเพื่อแสดงกราฟิกเมื่อมีการเรียกใช้ชื่องาน BigQuery

เพิ่ม HTML เพื่อแสดงกราฟิกเคลื่อนไหว มีไฟล์รูปภาพชื่อ loader.gif ในโฟลเดอร์ img ในที่เก็บโค้ด

<img id="spinner" src="img/loader.gif">

เพิ่ม CSS เพื่อจัดตำแหน่งรูปภาพและซ่อนรูปภาพโดยค่าเริ่มต้นจนกว่าจะจำเป็น

#spinner {
  position: absolute; 
  top: 50%; 
  left: 50%; 
  margin-left: -32px; 
  margin-top: -32px; 
  opacity: 0; 
  z-index: -1000;
}

สุดท้าย ให้เพิ่ม JavaScript เพื่ออัปเดตแผงสถานะและแสดงหรือซ่อนกราฟิกเมื่อมีการเรียกใช้การค้นหา คุณสามารถใช้ออบเจ็กต์ response เพื่ออัปเดตแผงได้โดยขึ้นอยู่กับข้อมูลที่มี

เมื่อตรวจสอบงานปัจจุบัน คุณจะใช้พร็อพเพอร์ตี้ response.statistics ได้ เมื่องานเสร็จสมบูรณ์แล้ว คุณจะเข้าถึงพร็อพเพอร์ตี้ response.totalRows และ response.totalBytesProcessed ได้ การแปลงมิลลิวินาทีเป็นวินาทีและไบต์เป็นกิกะไบต์เพื่อแสดงตามที่แสดงในโค้ดตัวอย่างด้านล่างจะเป็นประโยชน์ต่อผู้ใช้

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';
  }
}

เรียกใช้เมธอดนี้เมื่อมีการตอบกลับการเรียกใช้ checkJobStatus() และเมื่อมีการดึงข้อมูลผลการค้นหา เช่น

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

หากต้องการสลับกราฟิกเคลื่อนไหว ให้เพิ่มฟังก์ชันเพื่อควบคุมระดับการเข้าถึง ฟังก์ชันนี้จะสลับความทึบแสงขององค์ประกอบ DOM ของ HTML ที่ส่งไปยังฟังก์ชัน

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

สุดท้าย ให้เรียกใช้เมธอดนี้ก่อนประมวลผลการค้นหา และหลังจากที่ผลการค้นหาจาก BigQuery กลับมาแล้ว

โค้ดนี้จะเรียกใช้ฟังก์ชัน fadeToggle เมื่อผู้ใช้วาดสี่เหลี่ยมผืนผ้าเสร็จแล้ว

drawingManager.addListener('rectanglecomplete', rectangle => {
  //show an animation to indicate that something is happening.
  fadeToggle(document.getElementById('spinner'));
  rectangleQuery(rectangle.getBounds());
});

เมื่อได้รับคำตอบของการค้นหาแล้ว ให้เรียกใช้ fadeToggle() อีกครั้งเพื่อซ่อนกราฟิกเคลื่อนไหว

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

หน้าเว็บควรมีลักษณะดังนี้

Screen Shot 2017-05-10 at 2.32.19 PM.png

ดูตัวอย่างที่สมบูรณ์ได้ใน step8/map.html

14. สิ่งที่ควรพิจารณา

มีเครื่องหมายมากเกินไป

หากคุณทำงานกับตารางขนาดใหญ่มาก การค้นหาอาจแสดงแถวมากเกินไปจนแสดงบนแผนที่ได้อย่างไม่มีประสิทธิภาพ จำกัดผลลัพธ์โดยเพิ่มWHEREอนุประโยคหรือLIMITข้อความ

การวาดเครื่องหมายจำนวนมากอาจทำให้แผนที่อ่านไม่ได้ ลองใช้HeatmapLayerเพื่อแสดงความหนาแน่น หรือใช้เครื่องหมายคลัสเตอร์เพื่อระบุตำแหน่งของจุดข้อมูลจำนวนมากโดยใช้สัญลักษณ์เดียวต่อคลัสเตอร์ ดูรายละเอียดเพิ่มเติมได้ในบทแนะนำการจัดกลุ่มเครื่องหมาย

การเพิ่มประสิทธิภาพคำค้นหา

BigQuery จะสแกนทั้งตารางด้วยการค้นหาทุกครั้ง หากต้องการเพิ่มประสิทธิภาพการใช้โควต้า BigQuery ให้เลือกเฉพาะคอลัมน์ที่คุณต้องการในคำค้นหา

การค้นหาจะเร็วขึ้นหากคุณจัดเก็บละติจูดและลองจิจูดเป็นทศนิยมแทนสตริง

ส่งออกผลลัพธ์ที่น่าสนใจ

ตัวอย่างที่แสดงที่นี่กำหนดให้ผู้ใช้ปลายทางต้องได้รับการตรวจสอบสิทธิ์กับตาราง BigQuery ซึ่งอาจไม่เหมาะกับกรณีการใช้งานบางอย่าง เมื่อพบรูปแบบที่น่าสนใจ คุณอาจแชร์รูปแบบเหล่านี้กับกลุ่มเป้าหมายในวงกว้างได้ง่ายขึ้นโดยการส่งออกผลลัพธ์จาก BigQuery และสร้างชุดข้อมูลแบบคงที่โดยใช้เลเยอร์ข้อมูล Google Maps

โปรดทราบข้อกำหนดในการให้บริการของ Google Maps Platform ดูรายละเอียดเพิ่มเติมเกี่ยวกับราคาของ Google Maps Platform ได้ที่เอกสารประกอบออนไลน์

เล่นกับข้อมูลเพิ่มเติม

BigQuery มีชุดข้อมูลสาธารณะจำนวนมากที่มีคอลัมน์ละติจูดและลองจิจูด เช่น ชุดข้อมูลแท็กซี่ในนิวยอร์กตั้งแต่ปี 2009-2016, ข้อมูลการเดินทางของ Uber และ Lyft ในนิวยอร์ก และชุดข้อมูล GDELT

15. ยินดีด้วย

เราหวังว่าข้อมูลนี้จะช่วยให้คุณเริ่มต้นใช้งานการค้นหาทางภูมิศาสตร์กับตาราง BigQuery ได้อย่างรวดเร็ว เพื่อให้คุณค้นพบรูปแบบและแสดงภาพรูปแบบเหล่านั้นบน Google Maps ได้ ขอให้สนุกกับการแมป

ขั้นตอนถัดไปคือ

หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับ Google Maps Platform หรือ BigQuery โปรดดูคำแนะนำต่อไปนี้

ดูข้อมูลเพิ่มเติมเกี่ยวกับบริการคลังข้อมูลแบบ Serverless ระดับเพตะไบต์ของ Google ได้ที่BigQuery คืออะไร

ดูคำแนะนำวิธีใช้เพื่อสร้างแอปพลิเคชันอย่างง่ายโดยใช้ BigQuery API

ดูรายละเอียดเพิ่มเติมเกี่ยวกับการเปิดใช้การโต้ตอบของผู้ใช้เพื่อวาดรูปร่างบน Google Maps ได้ที่คู่มือนักพัฒนาซอฟต์แวร์สำหรับไลบรารีการวาด

ดูวิธีอื่นๆ ในการแสดงข้อมูลเป็นภาพใน Google Maps

ดูคู่มือเริ่มต้นใช้งานสำหรับ Javascript Client API เพื่อทำความเข้าใจแนวคิดพื้นฐานของการใช้ Client API เพื่อเข้าถึง Google API อื่นๆ