Google মানচিত্র প্ল্যাটফর্ম (জাভাস্ক্রিপ্ট) দিয়ে BigQuery-এ অবস্থানের ডেটা ক্যোয়ারী এবং ভিজ্যুয়ালাইজ করুন

1। সংক্ষিপ্ত বিবরণ

মানচিত্র একটি খুব শক্তিশালী হাতিয়ার হতে পারে যখন একটি ডেটাসেটে নিদর্শনগুলিকে ভিজ্যুয়ালাইজ করে যা কোনওভাবে অবস্থানের সাথে সম্পর্কিত। এই সম্পর্কটি হতে পারে একটি স্থানের নাম, একটি নির্দিষ্ট অক্ষাংশ এবং দ্রাঘিমাংশের মান, অথবা একটি এলাকার নাম যার একটি নির্দিষ্ট সীমানা আছে যেমন একটি আদমশুমারী ট্র্যাক্ট বা একটি পোস্টাল কোড।

যখন এই ডেটাসেটগুলি খুব বড় হয়, তখন প্রচলিত সরঞ্জামগুলি ব্যবহার করে অনুসন্ধান করা এবং কল্পনা করা কঠিন হতে পারে। ডেটা অনুসন্ধান করার জন্য Google BigQuery ব্যবহার করে এবং Google মানচিত্র APIs ক্যোয়ারী তৈরি করতে এবং আউটপুট কল্পনা করে, আপনি খুব কম সেটআপ বা কোডিং সহ আপনার ডেটাতে ভৌগলিক নিদর্শনগুলি দ্রুত অন্বেষণ করতে পারেন এবং খুব বড় ডেটাসেটগুলি সংরক্ষণ করার জন্য একটি সিস্টেম পরিচালনা না করেই .

আপনি কি নির্মাণ করবেন

এই কোডল্যাবে, আপনি কিছু ক্যোয়ারী লিখবেন এবং চালাবেন যা দেখায় কিভাবে BigQuery ব্যবহার করে খুব বড় পাবলিক ডেটাসেটে অবস্থান ভিত্তিক অন্তর্দৃষ্টি প্রদান করা যায়। আপনি একটি ওয়েব পৃষ্ঠাও তৈরি করবেন যা Google মানচিত্র প্ল্যাটফর্ম জাভাস্ক্রিপ্ট API ব্যবহার করে একটি মানচিত্র লোড করে, তারপর জাভাস্ক্রিপ্ট এবং BigQuery API- এর জন্য Google APIs ক্লায়েন্ট লাইব্রেরি ব্যবহার করে একই খুব বড় পাবলিক ডেটাসেটের বিরুদ্ধে স্থানিক প্রশ্নগুলি চালায় এবং ভিজ্যুয়ালাইজ করে।

আপনি কি শিখবেন

  • এসকিউএল কোয়েরি , ইউজার ডিফাইন্ড ফাংশন এবং BigQuery API ব্যবহার করে BigQuery- এর মাধ্যমে পেটাবাইট-স্কেল লোকেশন ডেটাসেটগুলিকে সেকেন্ডের মধ্যে কোয়েরি করতে হয়
  • একটি ওয়েব পৃষ্ঠায় একটি Google মানচিত্র যুক্ত করতে এবং ব্যবহারকারীদের এটিতে আকার আঁকতে সক্ষম করতে কীভাবে Google মানচিত্র প্ল্যাটফর্ম ব্যবহার করবেন
  • নিচের উদাহরণের চিত্রের মতো Google ম্যাপে বড় ডেটাসেটের বিরুদ্ধে প্রশ্নগুলি কীভাবে কল্পনা করা যায়, যা এম্পায়ার স্টেট বিল্ডিংয়ের চারপাশের ব্লক থেকে শুরু হওয়া যাত্রা থেকে 2016 সালে ট্যাক্সি ড্রপ অফ অবস্থানের ঘনত্ব দেখায়।

স্ক্রীন শট 2017-05-09 11.01.12 AM.png

আপনি কি প্রয়োজন হবে

  • HTML, CSS, JavaScript, SQL, এবং Chrome DevTools এর প্রাথমিক জ্ঞান
  • একটি আধুনিক ওয়েব ব্রাউজার, যেমন ক্রোম, ফায়ারফক্স, সাফারি বা এজ এর সাম্প্রতিক সংস্করণ।
  • আপনার পছন্দের একটি পাঠ্য সম্পাদক বা IDE

প্রযুক্তি

BigQuery

BigQuery হল অনেক বড় ডেটাসেটের জন্য Google-এর ডেটা অ্যানালিটিক্স পরিষেবা৷ এটির একটি RESTful API রয়েছে এবং SQL এ লেখা প্রশ্নগুলিকে সমর্থন করে৷ আপনার যদি অক্ষাংশ এবং দ্রাঘিমাংশের মান সহ ডেটা থাকে তবে সেগুলি অবস্থান অনুসারে আপনার ডেটা অনুসন্ধান করতে ব্যবহার করা যেতে পারে। সুবিধা হল আপনি কোন সার্ভার বা ডাটাবেস পরিকাঠামো পরিচালনা না করেই নিদর্শনগুলি দেখতে খুব বড় ডেটাসেটগুলিকে দৃশ্যত অন্বেষণ করতে পারেন৷ BigQuery এর বিশাল মাপযোগ্যতা এবং পরিচালিত পরিকাঠামো ব্যবহার করে আপনার টেবিল যত বড় হোক না কেন আপনি কয়েক সেকেন্ডের মধ্যে আপনার প্রশ্নের উত্তর পেতে পারেন।

গুগল ম্যাপ প্ল্যাটফর্ম

Google মানচিত্র প্ল্যাটফর্ম Google এর মানচিত্র, স্থান এবং রুট ডেটাতে প্রোগ্রাম্যাটিক অ্যাক্সেস প্রদান করে। 2 মিলিয়নেরও বেশি ওয়েবসাইট এবং অ্যাপ বর্তমানে তাদের ব্যবহারকারীদের এমবেডেড মানচিত্র এবং অবস্থান ভিত্তিক প্রশ্ন প্রদান করতে এটি ব্যবহার করে।

Google মানচিত্র প্ল্যাটফর্ম জাভাস্ক্রিপ্ট API অঙ্কন স্তর আপনাকে মানচিত্রে আকার আঁকতে দেয়। কলামে সংরক্ষিত অক্ষাংশ এবং দ্রাঘিমাংশের মান রয়েছে এমন BigQuery টেবিলের বিরুদ্ধে কোয়েরি চালানোর জন্য এগুলিকে ইনপুটে রূপান্তর করা যেতে পারে।

শুরু করার জন্য আপনার একটি Google ক্লাউড প্ল্যাটফর্ম প্রজেক্ট প্রয়োজন যাতে BigQuery এবং Maps API সক্রিয় থাকে।

2. সেট আপ করা হচ্ছে

গুগল অ্যাকাউন্ট

আপনার যদি ইতিমধ্যে একটি Google অ্যাকাউন্ট না থাকে (Gmail বা Google Apps), তাহলে আপনাকে অবশ্যই একটি তৈরি করতে হবে।

একটি প্রকল্প তৈরি করুন

Google ক্লাউড প্ল্যাটফর্ম কনসোলে সাইন ইন করুন ( console.cloud.google.com ) এবং একটি নতুন প্রকল্প তৈরি করুন৷ আপনার স্ক্রিনের শীর্ষে, একটি প্রকল্প ড্রপ ডাউন মেনু রয়েছে:

f2a353c3301dc649.png

একবার আপনি এই প্রকল্পের ড্রপ ডাউন মেনুতে ক্লিক করলে, আপনি একটি মেনু আইটেম পাবেন যা আপনাকে একটি নতুন প্রকল্প তৈরি করতে দেয়:

56a42dfa7ac27a35.png

"আপনার প্রকল্পের জন্য একটি নতুন নাম লিখুন" বলা বাক্সে, আপনার নতুন প্রকল্পের জন্য একটি নাম লিখুন, উদাহরণস্বরূপ "BigQuery Codelab":

কোডল্যাব - প্রজেক্ট তৈরি করুন (1).png

আপনার জন্য একটি প্রকল্প আইডি তৈরি করা হবে। প্রোজেক্ট আইডি হল সমস্ত Google ক্লাউড প্রোজেক্ট জুড়ে একটি অনন্য নাম। আপনার প্রজেক্ট আইডি মনে রাখবেন, কারণ আপনি এটি পরে ব্যবহার করবেন। উপরে নাম ইতিমধ্যে নেওয়া হয়েছে এবং আপনার জন্য কাজ করবে না. এই কোডল্যাবে যেখানেই আপনি YOUR_PROJECT_ID দেখতে পাবেন সেখানে আপনার নিজস্ব প্রজেক্ট আইডি ঢোকান।

বিলিং সক্ষম করুন৷

BigQuery-এ সাইন আপ করতে, আগের ধাপে নির্বাচিত বা তৈরি করা প্রোজেক্ট ব্যবহার করুন। এই প্রকল্পে বিলিং সক্রিয় করা আবশ্যক। একবার বিলিং সক্ষম হয়ে গেলে, আপনি BigQuery API সক্ষম করতে পারেন৷

আপনি কীভাবে বিলিং সক্ষম করবেন তা নির্ভর করে আপনি একটি নতুন প্রকল্প তৈরি করছেন বা আপনি একটি বিদ্যমান প্রকল্পের জন্য বিলিং পুনরায় সক্ষম করছেন কিনা।

Google $300 মূল্যের Google ক্লাউড প্ল্যাটফর্ম ব্যবহারের জন্য একটি 12 মাসের বিনামূল্যের ট্রায়াল অফার করে যা আপনি এই কোডল্যাবের জন্য ব্যবহার করতে সক্ষম হতে পারেন, https://cloud.google.com/free/ এ আরও বিশদ জানুন।

নতুন প্রকল্প

আপনি যখন একটি নতুন প্রকল্প তৈরি করেন, তখন আপনাকে আপনার বিলিং অ্যাকাউন্টগুলির মধ্যে কোনটি প্রকল্পের সাথে লিঙ্ক করতে চান তা চয়ন করতে বলা হবে৷ আপনার যদি শুধুমাত্র একটি বিলিং অ্যাকাউন্ট থাকে, তাহলে সেই অ্যাকাউন্টটি স্বয়ংক্রিয়ভাবে আপনার প্রকল্পের সাথে লিঙ্ক হয়ে যাবে।

আপনার যদি একটি বিলিং অ্যাকাউন্ট না থাকে, আপনি অনেকগুলি Google ক্লাউড প্ল্যাটফর্ম বৈশিষ্ট্য ব্যবহার করার আগে আপনাকে অবশ্যই একটি তৈরি করতে হবে এবং আপনার প্রকল্পের জন্য বিলিং সক্ষম করতে হবে৷ একটি নতুন বিলিং অ্যাকাউন্ট তৈরি করতে এবং আপনার প্রকল্পের জন্য বিলিং সক্ষম করতে, একটি নতুন বিলিং অ্যাকাউন্ট তৈরি করুন এর নির্দেশাবলী অনুসরণ করুন।

বিদ্যমান প্রকল্প

আপনার যদি এমন একটি প্রকল্প থাকে যার জন্য আপনি সাময়িকভাবে বিলিং অক্ষম করেছেন, আপনি বিলিং পুনরায় সক্ষম করতে পারেন:

  1. ক্লাউড প্ল্যাটফর্ম কনসোলে যান।
  2. প্রকল্পের তালিকা থেকে, বিলিং পুনরায় সক্ষম করতে প্রকল্পটি নির্বাচন করুন৷
  3. কনসোল বাম পাশের মেনু খুলুন এবং বিলিং নির্বাচন করুন Billing . আপনাকে একটি বিলিং অ্যাকাউন্ট নির্বাচন করতে বলা হচ্ছে।
  4. অ্যাকাউন্ট সেট করুন ক্লিক করুন।

একটি নতুন বিলিং অ্যাকাউন্ট তৈরি করুন

একটি নতুন বিলিং অ্যাকাউন্ট তৈরি করতে:

  1. ক্লাউড প্ল্যাটফর্ম কনসোলে যান এবং সাইন ইন করুন বা, আপনার যদি ইতিমধ্যে একটি অ্যাকাউন্ট না থাকে তবে সাইন আপ করুন৷
  2. কনসোল বাম পাশের মেনু খুলুন এবং বিলিং নির্বাচন করুন Billing
  3. নতুন বিলিং অ্যাকাউন্ট বোতামে ক্লিক করুন। (মনে রাখবেন যে এটি যদি আপনার প্রথম বিলিং অ্যাকাউন্ট না হয়, তাহলে প্রথমে আপনাকে পৃষ্ঠার শীর্ষে থাকা আপনার বিদ্যমান বিলিং অ্যাকাউন্টের নামে ক্লিক করে বিলিং অ্যাকাউন্টের তালিকা খুলতে হবে এবং তারপরে বিলিং অ্যাকাউন্ট পরিচালনা করুন ক্লিক করুন।)
  4. বিলিং অ্যাকাউন্টের নাম লিখুন এবং আপনার বিলিং তথ্য লিখুন। আপনি যে বিকল্পগুলি দেখছেন তা আপনার বিলিং ঠিকানার দেশের উপর নির্ভর করে৷ মনে রাখবেন যে ইউনাইটেড স্টেটস অ্যাকাউন্টগুলির জন্য, অ্যাকাউন্ট তৈরি হওয়ার পরে আপনি ট্যাক্স স্থিতি পরিবর্তন করতে পারবেন না।
  5. জমা দিন এবং বিলিং সক্ষম করুন ক্লিক করুন।

ডিফল্টরূপে, যে ব্যক্তি বিলিং অ্যাকাউন্ট তৈরি করেন তিনি অ্যাকাউন্টের জন্য একজন বিলিং প্রশাসক।

ব্যাঙ্ক অ্যাকাউন্ট যাচাইকরণ এবং অর্থপ্রদানের ব্যাকআপ পদ্ধতি যোগ করার বিষয়ে তথ্যের জন্য , একটি অর্থপ্রদানের পদ্ধতি যোগ করুন, সরান বা আপডেট করুন দেখুন।

BigQuery API সক্ষম করুন

আপনার প্রজেক্টে BigQuery API সক্ষম করতে, কনসোলের BigQuery API পৃষ্ঠা মার্কেটপ্লেসে যান এবং নীল 'সক্ষম' বোতামে ক্লিক করুন।

3. BigQuery-এ অবস্থান ডেটা জিজ্ঞাসা করা

BigQuery-এ অক্ষাংশ, দ্রাঘিমাংশের মান হিসাবে সংরক্ষিত অবস্থানের ডেটা জিজ্ঞাসা করার তিনটি উপায় রয়েছে৷

  • আয়তক্ষেত্রের প্রশ্ন : একটি ক্যোয়ারী হিসাবে আগ্রহের ক্ষেত্রটি নির্দিষ্ট করুন যা ন্যূনতম এবং সর্বোচ্চ অক্ষাংশ এবং দ্রাঘিমাংশের মধ্যে সমস্ত সারি নির্বাচন করে।
  • ব্যাসার্ধের প্রশ্ন : পৃথিবীর আকৃতির মডেল করার জন্য হ্যাভারসাইন সূত্র এবং গণিত ফাংশন ব্যবহার করে একটি বিন্দুর চারপাশে একটি বৃত্ত গণনা করে আগ্রহের ক্ষেত্রটি নির্দিষ্ট করুন।
  • বহুভুজ প্রশ্ন : একটি কাস্টম আকৃতি নির্দিষ্ট করুন এবং প্রতিটি সারির অক্ষাংশ এবং দ্রাঘিমাংশ আকৃতির ভিতরে পড়ে কিনা তা পরীক্ষা করার জন্য প্রয়োজনীয় পয়েন্ট-ইন-পলিগন যুক্তি প্রকাশ করতে একটি ব্যবহারকারী সংজ্ঞায়িত ফাংশন ব্যবহার করুন।

শুরু করতে, NYC ট্যাক্সি ডেটার বিরুদ্ধে নিম্নলিখিত প্রশ্নগুলি চালানোর জন্য Google ক্লাউড প্ল্যাটফর্ম কনসোলের বিগ কোয়েরি বিভাগে ক্যোয়ারী এডিটর ব্যবহার করুন৷

স্ট্যান্ডার্ড এসকিউএল বনাম লিগ্যাসি এসকিউএল

BigQuery SQL এর দুটি সংস্করণ সমর্থন করে: Legacy SQL এবং Standard SQL । পরেরটি হল 2011 ANSI মান। এই টিউটোরিয়ালের উদ্দেশ্যে, আমরা স্ট্যান্ডার্ড এসকিউএল ব্যবহার করব কারণ এতে আরও ভাল মান সম্মতি রয়েছে।

আপনি যদি BigQuery এডিটরে Legacy SQL চালাতে চান, তাহলে আপনি নিম্নলিখিতগুলি করে তা করতে পারেন:

  1. 'আরো' বোতামে ক্লিক করুন
  2. ড্রপডাউন মেনু থেকে 'কোয়েরি সেটিংস' নির্বাচন করুন
  3. 'SQL উপভাষা'-এর অধীনে, 'লেগেসি' রেডিও বোতামটি নির্বাচন করুন
  4. 'সংরক্ষণ করুন' বোতামে ক্লিক করুন

আয়তক্ষেত্র প্রশ্ন

BigQuery-এ আয়তক্ষেত্রের প্রশ্নগুলি তৈরি করা বেশ সহজ। আপনাকে শুধুমাত্র একটি WHERE ক্লজ যোগ করতে হবে যা অক্ষাংশ এবং দ্রাঘিমাংশের জন্য ন্যূনতম এবং সর্বোচ্চ মানের মধ্যে অবস্থানগুলির সাথে ফলাফলগুলিকে সীমাবদ্ধ করে৷

BigQuery কনসোলে নিচের উদাহরণটি ব্যবহার করে দেখুন। মিডটাউন এবং নিম্ন ম্যানহাটন রয়েছে এমন একটি আয়তক্ষেত্রাকার এলাকায় শুরু হওয়া রাইডগুলির জন্য কিছু গড় ভ্রমণের পরিসংখ্যানের জন্য এই প্রশ্নগুলি৷ দুটি ভিন্ন অবস্থানে আপনি চেষ্টা করতে পারেন, JFK বিমানবন্দরে শুরু হওয়া রাইডগুলিতে প্রশ্নটি চালানোর জন্য দ্বিতীয় WHERE আনকমেন্ট করুন।

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

দুটি প্রশ্নের ফলাফল দেখায় যে দুটি স্থানে গড় ট্রিপের দূরত্ব, ভাড়া এবং পিক আপের ক্ষেত্রে বড় পার্থক্য রয়েছে৷

ম্যানহাটন

avg_tip

avg_fare

গড়_দূরত্ব

avg_tip_pc

avg_fare_mile

2.52

12.03

৯.৯৭

22.39

৫.৯৭

জেএফকে

avg_tip

avg_fare

গড়_দূরত্ব

avg_tip_pc

avg_fare_mile

9.22

৪৮.৪৯

41.19

22.48

4.36

ব্যাসার্ধ প্রশ্ন

আপনি যদি কিছুটা গণিত জানেন তবে ব্যাসার্ধের প্রশ্নগুলি এসকিউএল-এ তৈরি করা সহজ। BigQuery-এর Legacy SQL Math ফাংশন ব্যবহার করে আপনি Haversine ফর্মুলা ব্যবহার করে একটি SQL কোয়েরি তৈরি করতে পারেন যা পৃথিবীর পৃষ্ঠে একটি বৃত্তাকার এলাকা বা গোলাকার ক্যাপকে আনুমানিক করে।

0.1কিমি ব্যাসার্ধ সহ 40.73943, -73.99585 কেন্দ্রিক একটি সার্কেল কোয়েরির জন্য এখানে একটি উদাহরণ BigQuery SQL স্টেটমেন্ট।

এটি আনুমানিক এক ডিগ্রী দ্বারা উপস্থাপিত দূরত্বের জন্য 111.045 কিলোমিটারের একটি ধ্রুবক মান ব্যবহার করে।

এটি 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_tip_pc

avg_fare_mile

1.17

11.08

45.28

10.53

৬.৪২

ব্রঙ্কস

avg_tip

avg_fare

গড়_দূরত্ব

avg_tip_pc

avg_fare_mile

0.52

17.63

4.75

4.74

10.9

বহুভুজ প্রশ্ন

SQL আয়তক্ষেত্র এবং বৃত্ত ব্যতীত নির্বিচারে আকার ব্যবহার করে অনুসন্ধান সমর্থন করে না। BigQuery-এর কোনও নেটিভ জ্যামিতি ডেটা টাইপ বা স্থানিক সূচক নেই, তাই বহুভুজ আকার ব্যবহার করে কোয়েরি চালানোর জন্য আপনাকে সরল SQL কোয়েরির জন্য আলাদা পদ্ধতির প্রয়োজন। একটি পদ্ধতি হল জাভাস্ক্রিপ্টে একটি জ্যামিতি ফাংশন সংজ্ঞায়িত করা এবং এটিকে BigQuery-এ ইউজার ডিফাইন্ড ফাংশন (UDF) হিসাবে চালানো।

অনেক জ্যামিতি ক্রিয়াকলাপ জাভাস্ক্রিপ্টে লেখা যেতে পারে তাই অক্ষাংশ এবং দ্রাঘিমাংশের মান ধারণ করে এমন একটি BigQuery টেবিলের বিপরীতে একটি নেওয়া এবং এটি চালানো সহজ। আপনাকে একটি UDF এর মাধ্যমে কাস্টম বহুভুজ পাস করতে হবে এবং প্রতিটি সারির বিপরীতে একটি পরীক্ষা করতে হবে, শুধুমাত্র সেই সারিগুলি ফিরিয়ে দিতে হবে যেখানে অক্ষাংশ এবং দ্রাঘিমাংশ বহুভুজের মধ্যে পড়ে। BigQuery রেফারেন্সে UDF সম্পর্কে আরও জানুন

পলিগন অ্যালগরিদমে পয়েন্ট

জাভাস্ক্রিপ্টে একটি বিন্দু বহুভুজের মধ্যে পড়ে কিনা তা গণনা করার অনেক উপায় রয়েছে। এখানে একটি সুপরিচিত বাস্তবায়নের 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;
}

জাভাস্ক্রিপ্টে পোর্টিং

এই অ্যালগরিদমের জাভাস্ক্রিপ্ট সংস্করণটি এইরকম দেখাচ্ছে:

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

BigQuery-এ স্ট্যান্ডার্ড SQL ব্যবহার করার সময়, UDF পদ্ধতির জন্য শুধুমাত্র একটি বিবৃতি প্রয়োজন, কিন্তু UDF বিবৃতিতে একটি অস্থায়ী ফাংশন হিসাবে সংজ্ঞায়িত করা আবশ্যক। এখানে একটি উদাহরণ. Query Editor উইন্ডোতে নিচের 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

অভিনন্দন!

আপনি এখন BigQuery ব্যবহার করে তিন ধরনের স্থানিক কোয়েরি চালাচ্ছেন। আপনি যেমন দেখেছেন, অবস্থান এই ডেটাসেটের বিরুদ্ধে প্রশ্নের ফলাফলের ডেটাতে একটি বড় পার্থক্য করে, কিন্তু আপনি আপনার কোয়েরিগুলি কোথায় চালাবেন তা অনুমান না করা পর্যন্ত, শুধুমাত্র SQL ক্যোয়ারী ব্যবহার করে স্থানিক প্যাটার্ন অ্যাড-হক আবিষ্কার করা কঠিন।

যদি আমরা একটি মানচিত্রে ডেটা কল্পনা করতে পারি, এবং আগ্রহের নির্বিচারে এলাকাগুলি সংজ্ঞায়িত করে ডেটা অন্বেষণ করতে পারি! আচ্ছা, গুগল ম্যাপ এপিআই ব্যবহার করে আপনি সেটাই করতে পারেন। প্রথমে, আপনাকে মানচিত্র API সক্ষম করতে হবে, আপনার স্থানীয় মেশিনে চলমান একটি সাধারণ ওয়েব পৃষ্ঠা সেট আপ করতে হবে এবং আপনার ওয়েব পৃষ্ঠা থেকে প্রশ্ন পাঠাতে BigQuery API ব্যবহার শুরু করতে হবে৷

4. Google Maps API-এর সাথে কাজ করা

কিছু সাধারণ স্থানিক প্রশ্ন চালানোর পর, পরবর্তী ধাপ হল প্যাটার্নগুলি দেখতে আউটপুটটি কল্পনা করা। এটি করার জন্য আপনি Maps API সক্ষম করবেন, একটি ওয়েব পৃষ্ঠা তৈরি করুন যা একটি মানচিত্র থেকে BigQuery-এ প্রশ্ন পাঠায়, তারপর মানচিত্রে ফলাফলগুলি আঁকে৷

মানচিত্র জাভাস্ক্রিপ্ট API সক্ষম করুন৷

এই কোডল্যাবের জন্য, আপনাকে আপনার প্রকল্পে Google মানচিত্র প্ল্যাটফর্মের মানচিত্র জাভাস্ক্রিপ্ট API সক্ষম করতে হবে। এটি করার জন্য, নিম্নলিখিতগুলি করুন:

  1. Google ক্লাউড প্ল্যাটফর্ম কনসোলে, মার্কেটপ্লেসে যান
  2. মার্কেটপ্লেসে, 'Maps JavaScript API' অনুসন্ধান করুন
  3. অনুসন্ধান ফলাফলে মানচিত্র জাভাস্ক্রিপ্ট API-এর জন্য টাইলে ক্লিক করুন
  4. 'সক্ষম' বোতামে ক্লিক করুন

একটি API কী তৈরি করুন

Google মানচিত্র প্ল্যাটফর্মে অনুরোধ করতে, আপনাকে একটি API কী তৈরি করতে হবে এবং সমস্ত অনুরোধের সাথে এটি পাঠাতে হবে। একটি API কী তৈরি করতে, নিম্নলিখিতগুলি করুন:

  1. Google ক্লাউড প্ল্যাটফর্ম কনসোলে, বাম নেভি খুলতে হ্যামবার্গার মেনুতে ক্লিক করুন
  2. 'এপিআই এবং পরিষেবা' > 'প্রমাণপত্র' নির্বাচন করুন
  3. 'ক্রিয়েট ক্রেডেনশিয়াল' বোতামে ক্লিক করুন, তারপর 'এপিআই কী' নির্বাচন করুন
  4. নতুন API কী কপি করুন

কোডটি ডাউনলোড করুন এবং একটি ওয়েব সার্ভার সেট আপ করুন

এই কোডল্যাবের জন্য সমস্ত কোড ডাউনলোড করতে নিম্নলিখিত বোতামে ক্লিক করুন:

ডাউনলোড করা জিপ ফাইলটি আনপ্যাক করুন। এটি একটি রুট ফোল্ডার ( bigquery ) আনপ্যাক করবে, যেটিতে এই কোডল্যাবের প্রতিটি ধাপের জন্য একটি ফোল্ডার রয়েছে, আপনার প্রয়োজনীয় সমস্ত সংস্থান সহ।

stepN ফোল্ডারে এই কোডল্যাবের প্রতিটি ধাপের কাঙ্খিত শেষ অবস্থা থাকে। তারা রেফারেন্স জন্য আছে. আমরা কাজ নামক ডিরেক্টরিতে আমাদের সমস্ত কোডিং work করব।

একটি স্থানীয় ওয়েব সার্ভার সেট আপ করুন

আপনি আপনার নিজস্ব ওয়েব সার্ভার ব্যবহার করার জন্য বিনামূল্যে, এই কোডল্যাবটি Chrome ওয়েব সার্ভারের সাথে ভালভাবে কাজ করার জন্য ডিজাইন করা হয়েছে৷ আপনি যদি এখনও সেই অ্যাপটি ইনস্টল না করে থাকেন, তাহলে আপনি Chrome ওয়েব স্টোর থেকে এটি ইনস্টল করতে পারেন।

ইনস্টল হয়ে গেলে অ্যাপটি খুলুন। ক্রোমে আপনি নিম্নলিখিত হিসাবে এটি করতে পারেন:

  1. ক্রোম খুলুন
  2. উপরের ঠিকানা বারে, chrome://apps টাইপ করুন
  3. টিপুন
  4. যে উইন্ডোটি খোলে, সেখানে ওয়েব সার্ভার আইকনে ক্লিক করুন আপনি একটি নিয়মিত বা পিন করা ট্যাব, পূর্ণ স্ক্রীন বা নতুন উইন্ডোতে একটি অ্যাপ খুলতে রাইট-ক্লিক করতে পারেন a3ed00e79b8bfee7.png আপনি পরবর্তী এই ডায়ালগটি দেখতে পাবেন, যা আপনাকে আপনার স্থানীয় ওয়েব সার্ভার কনফিগার করতে দেয়: 81b6151c3f60c948.png
  5. 'ফোল্ডার চয়ন করুন'-এ ক্লিক করুন এবং আপনি কোডল্যাব নমুনা ফাইলগুলি ডাউনলোড করেছেন এমন অবস্থান নির্বাচন করুন৷
  6. 'বিকল্প' বিভাগে, 'স্বয়ংক্রিয়ভাবে index.html দেখান'-এর পাশের বাক্সটি চেক করুন: 17f4913500faa86f.png
  7. 'ওয়েব সার্ভার: STARTED' লেবেলযুক্ত টগলটিকে বামে স্লাইড করুন এবং তারপরে থামতে ডানদিকে ফিরে যান তারপর ওয়েব সার্ভার পুনরায় চালু করুন

a5d554d0d4a91851.png

5. মানচিত্র এবং অঙ্কন সরঞ্জাম লোড করা হচ্ছে

একটি মৌলিক মানচিত্র পৃষ্ঠা তৈরি করুন

একটি সাধারণ HTML পৃষ্ঠা দিয়ে শুরু করুন যা মানচিত্র জাভাস্ক্রিপ্ট API এবং জাভাস্ক্রিপ্টের কয়েকটি লাইন ব্যবহার করে একটি Google মানচিত্র লোড করে। Google মানচিত্র প্ল্যাটফর্মের সরল মানচিত্রের নমুনা থেকে কোডটি শুরু করার জন্য একটি দুর্দান্ত জায়গা। আপনার পছন্দের টেক্সট এডিটর বা IDE-এ কপি এবং পেস্ট করার জন্য এটি এখানে পুনরুত্পাদন করা হয়েছে, অথবা আপনি ডাউনলোড করা রেপো থেকে index.html খুলে এটি খুঁজে পেতে পারেন।

  1. আপনার রেপোর স্থানীয় অনুলিপিতে work ফোল্ডারে index.html অনুলিপি করুন
  2. আপনার রেপোর স্থানীয় অনুলিপিতে img/ ফোল্ডারটি work/ ফোল্ডারে অনুলিপি করুন
  3. আপনার টেক্সট এডিটর বা IDE-এ work/ index.html খুলুন
  4. আপনার আগে তৈরি করা API কী দিয়ে YOUR_API_KEY প্রতিস্থাপন করুন
<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 কী সঠিক এবং আপনার স্থানীয় ওয়েব সার্ভার সক্রিয় আছে কিনা তা পরীক্ষা করুন৷

ডিফল্ট অবস্থান এবং জুম স্তর পরিবর্তন করুন

যে কোডটি অবস্থান এবং জুম স্তর সেট করে তা index.html এর 27 এবং 28 লাইনে রয়েছে এবং বর্তমানে অস্ট্রেলিয়ার সিডনিতে কেন্দ্রীভূত রয়েছে:

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

এর পরে, ফলাফলগুলি দেখতে আপনার ব্রাউজারে মানচিত্রটি পুনরায় লোড করুন৷

অঙ্কন এবং ভিজ্যুয়ালাইজেশন লাইব্রেরি লোড করুন

আপনার মানচিত্রে অঙ্কন ক্ষমতা যোগ করতে, আপনি একটি ঐচ্ছিক প্যারামিটার যোগ করে ম্যাপ জাভাস্ক্রিপ্ট API লোড করে এমন স্ক্রিপ্ট পরিবর্তন করবেন যা অঙ্কন লাইব্রেরি সক্ষম করতে Google মানচিত্র প্ল্যাটফর্মকে বলে৷

এই কোডল্যাবটি 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 আকারগুলি ব্যবহার করতে, Circle , Rectangle এবং Polygon সরঞ্জামগুলি সক্ষম করে আপনার মানচিত্রে অঙ্কন ব্যবস্থাপক যোগ করুন।

সমস্ত DrawingManager সেট আপ কোড একটি নতুন ফাংশনে রাখা একটি ভাল ধারণা, তাই index.html এর আপনার অনুলিপিতে, নিম্নলিখিতগুলি করুন:

  1. ড্রয়িং ম্যানেজার তৈরি করতে নিম্নলিখিত কোড সহ DrawingManager setUpDrawingTools() নামে একটি ফাংশন যোগ করুন এবং পৃষ্ঠায় মানচিত্র বস্তুর উল্লেখ করার জন্য এর map বৈশিষ্ট্য সেট করুন।

google.maps.drawing.DrawingManager(options) -এ পাস করা বিকল্পগুলি ডিফল্ট আকৃতি অঙ্কন প্রকার এবং আঁকা আকৃতির জন্য প্রদর্শন বিকল্পগুলি সেট করে। ক্যোয়ারী হিসাবে পাঠানোর জন্য মানচিত্রের ক্ষেত্রগুলি নির্বাচন করার জন্য, আকারগুলির অস্বচ্ছতা শূন্য হওয়া উচিত। উপলব্ধ বিকল্পগুলি সম্পর্কে আরও তথ্যের জন্য, ড্রয়িং ম্যানেজার বিকল্পগুলি দেখুন।

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. মানচিত্র অবজেক্ট তৈরি হওয়ার পরে আপনার initMap() ফাংশনে setUpDrawingTools( setUpDrawingTools() কল করুন
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 কোয়েরি তৈরি করতে আপনার আঁকা আকৃতির স্থানাঙ্কের প্রয়োজন হয়।

আমরা পরবর্তী ধাপে এর জন্য কোড যোগ করব, কিন্তু আপাতত আমরা 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 ক্লায়েন্ট API ব্যবহার করা

Google BigQuery ক্লায়েন্ট API আপনাকে অনুরোধগুলি তৈরি করতে, প্রতিক্রিয়া পার্স করতে এবং প্রমাণীকরণ পরিচালনার জন্য প্রয়োজনীয় প্রচুর বয়লারপ্লেট কোড লেখা এড়াতে সহায়তা করবে৷ এই কোডল্যাবটি জাভাস্ক্রিপ্টের জন্য Google APIs ক্লায়েন্ট লাইব্রেরির মাধ্যমে BigQuery API ব্যবহার করে যেহেতু আমরা একটি ব্রাউজার ভিত্তিক অ্যাপ্লিকেশন তৈরি করব৷

এরপর, আপনি একটি ওয়েব পৃষ্ঠায় এই API লোড করার জন্য কোড যোগ করবেন এবং BigQuery-এর সাথে ইন্টারঅ্যাক্ট করতে এটি ব্যবহার করবেন।

জাভাস্ক্রিপ্টের জন্য Google ক্লায়েন্ট API যোগ করুন

আপনি BigQuery-এর বিরুদ্ধে প্রশ্ন চালাতে Javascript-এর জন্য Google ক্লায়েন্ট API ব্যবহার করবেন। আপনার index.html এর অনুলিপিতে (আপনার work ফোল্ডারে), এরকম একটি <script> ট্যাগ ব্যবহার করে API লোড করুন। মানচিত্র API লোড করে এমন <script> ট্যাগের ঠিক নিচে ট্যাগটি রাখুন:

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

Google ক্লায়েন্ট API লোড করার পরে, ব্যবহারকারীকে BigQuery-এ ডেটা অ্যাক্সেস করার অনুমতি দিন। এটি করতে আপনি OAuth 2.0 ব্যবহার করতে পারেন। প্রথমে, আপনাকে আপনার Google ক্লাউড কনসোল প্রকল্পে কিছু শংসাপত্র সেট আপ করতে হবে।

OAuth 2.0 শংসাপত্র তৈরি করুন

  1. Google ক্লাউড কনসোলে, নেভিগেশন মেনু থেকে, APIs & Services > Credentials নির্বাচন করুন।

আপনি আপনার শংসাপত্রগুলি সেট আপ করার আগে, আপনাকে অনুমোদন স্ক্রীনের জন্য কিছু কনফিগারেশন যোগ করতে হবে যা আপনার অ্যাপ্লিকেশনের শেষ ব্যবহারকারীরা দেখতে পাবেন যখন তারা আপনার অ্যাপকে তাদের পক্ষ থেকে BigQuery ডেটা অ্যাক্সেস করার অনুমোদন দেয়।

এটি করতে, OAuth সম্মতি স্ক্রীন ট্যাবে ক্লিক করুন। 2. এই টোকেনের জন্য স্কোপগুলিতে আপনাকে Big Query API যোগ করতে হবে। Google APIs বিভাগে স্কোপ যোগ করুন বাটনে ক্লিক করুন। 3. তালিকা থেকে, ../auth/bigquery স্কোপ সহ Big Query API এন্ট্রির পাশের বাক্সটি চেক করুন। 4. যোগ করুন ক্লিক করুন । 5. 'অ্যাপ্লিকেশন নাম' ক্ষেত্রে একটি নাম লিখুন। 6. আপনার সেটিংস সংরক্ষণ করতে সংরক্ষণ ক্লিক করুন. 7. এরপর আপনি আপনার OAuth ক্লায়েন্ট আইডি তৈরি করবেন। এটি করতে, শংসাপত্র তৈরি করুন ক্লিক করুন:

4d18a965fc760e39.png

  1. ড্রপডাউন মেনুতে, OAuth ক্লায়েন্ট আইডি -তে ক্লিক করুন। 1f8b36a1c27c75f0.png
  2. অ্যাপ্লিকেশন প্রকারের অধীনে ওয়েব অ্যাপ্লিকেশন নির্বাচন করুন।
  3. অ্যাপ্লিকেশন নাম ক্ষেত্রে, আপনার প্রকল্পের জন্য একটি নাম টাইপ করুন। যেমন "BigQuery এবং Maps"।
  4. বিধিনিষেধের অধীনে, অনুমোদিত জাভাস্ক্রিপ্ট অরিজিন ক্ষেত্রে, পোর্ট নম্বর সহ লোকালহোস্টের URL লিখুন। উদাহরণস্বরূপ: http://localhost:8887
  1. Create বাটনে ক্লিক করুন।

একটি পপ আপ আপনাকে ক্লায়েন্ট আইডি এবং ক্লায়েন্ট গোপন দেখায়। BigQuery-এর বিরুদ্ধে প্রমাণীকরণ করতে আপনার ক্লায়েন্ট আইডি প্রয়োজন। এটিকে কপি করুন এবং এটিকে একটি নতুন গ্লোবাল জাভাস্ক্রিপ্ট ভেরিয়েবল হিসাবে work/index.html এ পেস্ট করুন যার নাম clientId

let clientId = 'YOUR_CLIENT_ID';

7. অনুমোদন এবং সূচনা

ম্যাপ শুরু করার আগে আপনার ওয়েব পৃষ্ঠাটিকে ব্যবহারকারীকে BigQuery অ্যাক্সেস করার অনুমতি দিতে হবে। এই উদাহরণে আমরা জাভাস্ক্রিপ্ট ক্লায়েন্ট API ডকুমেন্টেশনের অনুমোদন বিভাগে বর্ণিত OAuth 2.0 ব্যবহার করি। ক্যোয়ারী পাঠাতে আপনাকে OAuth ক্লায়েন্ট আইডি এবং আপনার প্রোজেক্ট আইডি ব্যবহার করতে হবে।

যখন Google ক্লায়েন্ট API ওয়েব পৃষ্ঠায় লোড হয় তখন আপনাকে নিম্নলিখিত পদক্ষেপগুলি সম্পাদন করতে হবে:

  • ব্যবহারকারীকে অনুমোদন করুন।
  • অনুমোদিত হলে, BigQuery API লোড করুন।
  • মানচিত্রটি লোড করুন এবং শুরু করুন।

সমাপ্ত HTML পৃষ্ঠাটি কেমন হবে তার উদাহরণের জন্য step3/map.html দেখুন।

ব্যবহারকারীকে অনুমোদন করুন

অ্যাপ্লিকেশনটির শেষ ব্যবহারকারীকে তাদের পক্ষে BigQuery-এ ডেটা অ্যাক্সেস করার জন্য অ্যাপ্লিকেশনটিকে অনুমোদন করতে হবে। জাভাস্ক্রিপ্টের জন্য Google ক্লায়েন্ট API এটি করার জন্য OAuth লজিক পরিচালনা করে।

একটি বাস্তব-বিশ্বের অ্যাপ্লিকেশনে অনুমোদনের ধাপকে কীভাবে একীভূত করা যায় সে সম্পর্কে আপনার কাছে অনেক পছন্দ রয়েছে।

উদাহরণস্বরূপ, আপনি একটি বোতামের মতো একটি UI উপাদান থেকে authorize() কল করতে পারেন, অথবা পৃষ্ঠাটি লোড হয়ে গেলে এটি করতে পারেন। এখানে আমরা gapi.load() পদ্ধতিতে একটি কলব্যাক ফাংশন ব্যবহার করে JavaScript-এর জন্য Google ক্লায়েন্ট API লোড হওয়ার পরে ব্যবহারকারীকে অনুমোদন করতে বেছে নিয়েছি।

<script> ট্যাগের পরে কিছু কোড লিখুন যা জাভাস্ক্রিপ্টের জন্য Google ক্লায়েন্ট API লোড করে ক্লায়েন্ট লাইব্রেরি এবং auth মডিউল উভয়ই লোড করতে যাতে আমরা সরাসরি ব্যবহারকারীকে প্রমাণীকরণ করতে পারি।

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

অনুমোদনের সময়, BigQuery API লোড করুন

ব্যবহারকারী অনুমোদিত হওয়ার পরে, BigQuery API লোড করুন।

প্রথমত, আপনি আগের ধাপে যোগ করা ক্লায়েন্টআইডি ভেরিয়েবলের সাথে clientId gapi.auth.authorize() কল করুন। handleAuthResult নামক একটি কলব্যাক ফাংশনে প্রতিক্রিয়া পরিচালনা করুন।

immediate প্যারামিটার নিয়ন্ত্রণ করে যে ব্যবহারকারীকে একটি পপ আপ দেখানো হবে কিনা। ব্যবহারকারী ইতিমধ্যে অনুমোদিত হলে অনুমোদন পপ আপ দমন করতে এটি true সেট করুন।

আপনার পৃষ্ঠায় handleAuthResult() নামে একটি ফাংশন যোগ করুন। ফাংশনটির একটি authresult প্যারামিটার নিতে হবে, যা আপনাকে ব্যবহারকারী সফলভাবে অনুমোদিত কিনা তার উপর নির্ভর করে যুক্তির প্রবাহ নিয়ন্ত্রণ করতে দেবে।

এছাড়াও ব্যবহারকারী সফলভাবে অনুমোদিত হলে BigQuery API লোড করতে loadApi নামক একটি ফাংশন যোগ করুন।

loadApi() কল করার জন্য loadApi() handleAuthResult() ফাংশনে লজিক যোগ করুন যদি ফাংশনে একটি authResult অবজেক্ট পাস করা থাকে এবং যদি অবজেক্টের error বৈশিষ্ট্যের মান false থাকে।

gapi.client.load() পদ্ধতি ব্যবহার করে BigQuery API লোড করতে loadApi() ফাংশনে কোড যোগ করুন।

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

মানচিত্র লোড করুন

চূড়ান্ত ধাপ হল মানচিত্র শুরু করা। এটি করার জন্য আপনাকে যুক্তির ক্রম কিছুটা পরিবর্তন করতে হবে। বর্তমানে এটি শুরু হয় যখন মানচিত্র API জাভাস্ক্রিপ্ট লোড হয়।

আপনি gapi.client অবজেক্টে load() ) পদ্ধতির পরে then() পদ্ধতি থেকে initMap() ফাংশন কল করে এটি করতে পারেন।

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

8. BigQuery API ধারণা

BigQuery API কলগুলি সাধারণত সেকেন্ডের মধ্যে কার্যকর হয় কিন্তু অবিলম্বে প্রতিক্রিয়া নাও পেতে পারে। দীর্ঘদিন ধরে চলমান চাকরির অবস্থা জানতে BigQuery পোল করার জন্য আপনার কিছু যুক্তির প্রয়োজন, এবং কাজ সম্পূর্ণ হলেই ফলাফল আনুন।

এই ধাপের সম্পূর্ণ কোড step4/map.html এ রয়েছে।

একটি অনুরোধ পাঠানো হচ্ছে

API ব্যবহার করে একটি ক্যোয়ারী পাঠাতে work/index.html এ একটি Javascript ফাংশন যোগ করুন এবং 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 ফাংশনটি দেখায় কিভাবে একটি কাজের স্থিতি পর্যায়ক্রমে চেক করতে হয়, get API পদ্ধতি ব্যবহার করে এবং মূল ক্যোয়ারী অনুরোধের দ্বারা ফিরে আসা 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]);    
  });
}

request.execute() কলে একটি কলব্যাক হিসাবে checkJobStatus() পদ্ধতিতে কল করতে sendQuery পদ্ধতিটি সংশোধন করুন। জব 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));
}

একটি প্রশ্নের ফলাফল পাওয়া

একটি কোয়েরি চালানো শেষ হলে তার ফলাফল পেতে, jobs.getQueryResults API কল ব্যবহার করুন। 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-এর মাধ্যমে অবস্থানের ডেটা জিজ্ঞাসা করা

BigQuery-এ ডেটার বিরুদ্ধে স্থানিক কোয়েরি চালানোর জন্য SQL ব্যবহার করার তিনটি উপায় রয়েছে:

  • আয়তক্ষেত্র দ্বারা নির্বাচন করুন (অন্যথায় বাউন্ডিং বক্স হিসাবে পরিচিত),
  • ব্যাসার্ধ দ্বারা নির্বাচন করুন, এবং
  • শক্তিশালী ব্যবহারকারী সংজ্ঞায়িত ফাংশন বৈশিষ্ট্য.

BigQuery লিগ্যাসি SQL রেফারেন্সের গাণিতিক ফাংশন বিভাগে 'উন্নত উদাহরণ'-এর অধীনে বাউন্ডিং বক্স এবং ব্যাসার্ধের প্রশ্নের উদাহরণ রয়েছে।

বাউন্ডিং বক্স এবং ব্যাসার্ধের প্রশ্নের জন্য, আপনি BigQuery API query পদ্ধতিতে কল করতে পারেন। প্রতিটি প্রশ্নের জন্য এসকিউএল তৈরি করুন এবং পূর্ববর্তী ধাপে আপনার তৈরি করা sendQuery ফাংশনে এটি পাস করুন।

এই ধাপের কোডের একটি কার্যকরী উদাহরণ হল step4/map.html

আয়তক্ষেত্র প্রশ্ন

একটি মানচিত্রে BigQuery ডেটা প্রদর্শন করার সবচেয়ে সহজ উপায় হল সমস্ত সারি যেখানে অক্ষাংশ এবং দ্রাঘিমাংশ একটি আয়তক্ষেত্রের মধ্যে পড়ে, তুলনার চেয়ে কম এবং বড় ব্যবহার করে অনুরোধ করা। এটি বর্তমান মানচিত্র দৃশ্য বা মানচিত্রে আঁকা একটি আকৃতি হতে পারে।

ব্যবহারকারীর আঁকা একটি আকৃতি ব্যবহার করতে, একটি আয়তক্ষেত্র সম্পূর্ণ হলে অঙ্কন ইভেন্টটি পরিচালনা করতে index.html এ কোডটি পরিবর্তন করুন। এই উদাহরণে কোডটি আয়তক্ষেত্র বস্তুতে getBounds() ব্যবহার করে মানচিত্রের স্থানাঙ্কে আয়তক্ষেত্রের সীমার প্রতিনিধিত্বকারী একটি বস্তু পেতে এবং এটিকে rectangleQuery নামক একটি ফাংশনে প্রেরণ করে:

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

আপনার BigQuery টেবিলের প্রতিটি সারির তুলনায় কম/বৃহত্তর নির্মাণের জন্য rectangleQuery ফাংশনটি শুধুমাত্র উপরের ডান (উত্তর পূর্ব) এবং নীচের বাম (দক্ষিণ পশ্চিম) স্থানাঙ্ক ব্যবহার করতে হবে। এখানে একটি উদাহরণ দেওয়া হল যা একটি টেবিলকে জিজ্ঞাসা করে যেখানে 'pickup_latitude' এবং 'pickup_longitude' নামক কলাম রয়েছে যা অবস্থানের মানগুলিকে সঞ্চয় করে।

BigQuery টেবিল নির্দিষ্ট করা হচ্ছে

BigQuery API ব্যবহার করে একটি টেবিলের জন্য প্রশ্ন করার জন্য আপনাকে আপনার SQL ক্যোয়ারীতে সম্পূর্ণ যোগ্য আকারে টেবিলের নাম সরবরাহ করতে হবে। স্ট্যান্ডার্ড এসকিউএল-এর বিন্যাস হল project.dataset.tablename । লিগ্যাসি এসকিউএল-এ এটি হল project.dataset.tablename

NYC ট্যাক্সি ট্রিপের অনেক টেবিল পাওয়া যায়। সেগুলি দেখতে, BigQuery ওয়েব কনসোলে যান এবং "পাবলিক ডেটাসেট" মেনু আইটেমটি প্রসারিত করুন৷ new_york নামক ডেটাসেটটি খুঁজুন এবং টেবিলগুলি দেখতে এটি প্রসারিত করুন। হলুদ ট্যাক্সি ট্রিপ টেবিল চয়ন করুন: bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2016 )।

প্রজেক্ট আইডি উল্লেখ করা

API কলে, আপনাকে বিলিংয়ের উদ্দেশ্যে আপনার Google ক্লাউড প্ল্যাটফর্ম প্রকল্পের নাম উল্লেখ করতে হবে। এই কোডল্যাবে, এটি টেবিলের মতো একই প্রকল্প নয় । আপনি যদি ডেটা আপলোড করে আপনার নিজের প্রকল্পে তৈরি করা একটি টেবিলের সাথে কাজ করেন, তাহলে এই প্রকল্প আইডিটি আপনার SQL স্টেটমেন্টের মতোই হবে।

আপনার কোডে JavaScript ভেরিয়েবল যোগ করুন পাবলিক ডেটাসেট প্রজেক্টের রেফারেন্স ধারণ করতে যাতে আপনি যে টেবিলটি অনুসন্ধান করছেন সেটি ধারণ করে, সাথে টেবিলের নাম এবং ডেটাসেটের নাম। আপনার নিজের বিলিং প্রকল্প আইডি উল্লেখ করার জন্য আপনাকে একটি পৃথক পরিবর্তনশীল প্রয়োজন।

আপনার index.html এর কপিতে billingProjectId, publicProjectId, datasetId এবং tableName নামক গ্লোবাল জাভাস্ক্রিপ্ট ভেরিয়েবল যোগ করুন।

BigQuery পাবলিক ডেটাসেট প্রকল্প থেকে বিশদ বিবরণ সহ 'publicProjectId' , 'datasetId' এবং 'tableName' ভেরিয়েবলগুলি শুরু করুন। আপনার নিজস্ব প্রজেক্ট আইডি দিয়ে billingProjectId শুরু করুন (এই কোডল্যাবে আগে "সেট আপ করা" এ আপনি যেটি তৈরি করেছেন)।

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

এখন আপনার কোডে দুটি ফাংশন যোগ করুন SQL তৈরি করতে এবং আপনার আগের ধাপে তৈরি করা sendQuery ফাংশনটি ব্যবহার করে BigQuery-এ ক্যোয়ারী পাঠানোর জন্য।

প্রথম ফাংশনটিকে rectangleSQL() বলা উচিত এবং দুটি আর্গুমেন্ট গ্রহণ করতে হবে, google.Maps.LatLng বস্তুর একটি জোড়া যা মানচিত্রের স্থানাঙ্কে আয়তক্ষেত্রের কোণগুলিকে প্রতিনিধিত্ব করে৷

দ্বিতীয় ফাংশন বলা উচিত 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. Visualizing the response

BigQuery tables can be very large—Petabytes of data—and can grow by hundreds of thousands of rows per second. So it's important to try and limit the amount of data returned so that it can be drawn on the map. Drawing the location of every row in a very large result set (tens of thousands of rows or greater) will result in an unreadable map. There are many techniques for aggregating the locations both in the SQL query and on the map, and you can limit the results a query will return.

Full code for this step is available in step5/map.html .

To keep the amount of data transferred to your web page down to a reasonable size for this codelab, modify the rectangleSQL() function to add a statement that limits the response to 10000 rows. In the example below this is specified in a global variable called recordLimit , so that all query functions can use the same value.

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

To visualize the density of locations you can use a heatmap. The Maps Javascript API has a HeatmapLayer class for this purpose. The HeatmapLayer takes an array of latitude, longitude coordinates so it is quite easy to convert the rows returned from the query into a heatmap.

In the getQueryResults function, pass the response.result.rows array to a new Javascript function called doHeatMap() that will create a heatmap.

Each row will have a property called f which is an array of columns. Each column will have a v property containing the value.

Your code needs to loop through the columns in each row and extract the values.

In the SQL query, you have only asked for the Latitude and Longitude values of the taxi pickups so there will only be two columns in the response.

Don't forget to call setMap() on the heatmap layer when you have assigned the array of positions to it. This will make it visible on the map.

Here's an example:

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

At this point, you should be able to:

  • Open the page and authorize against BigQuery
  • Draw a rectangle somewhere in NYC
  • See the resulting query results visualized as a heatmap.

Here is an example of the result from a rectangle query against the 2016 NYC Yellow Taxi data, drawn as a heatmap. This shows the distribution of pickups around the Empire State Building on a Saturday in July:

7b1face0e7c71c78.png

11. Querying by radius around a point

Radius queries are very similar. Using BigQuery's Legacy SQL Math functions you can construct a SQL query using the Haversine Formula which approximates a circular area on the earth's surface.

Using the same technique for rectangles, you can handle an OverlayComplete event to get the center and radius of a user-drawn circle, and build up the SQL for the query in the same way.

A working example of the code for this step is included in the code repository as step6/map.html .

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

In your copy of index.html, add two new empty functions: circleQuery() and haversineSQL() .

Then, add a circlecomplete event handler that passes the centre and radius to a new function called circleQuery().

The circleQuery() function will call haversineSQL() to construct the SQL for the query and then send the query by calling the sendQuery() function as per the following example code.

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

Try it!

Add the code above and try the 'Circle' tool to select an area of map. The result should look something like this:

845418166b7cc7a3.png

12. Querying arbitrary shapes

Recap: SQL doesn't support querying using arbitrary shapes other than rectangles and circles. BigQuery doesn't have any native geometry data type, so to run queries using polygon shapes you need a different approach to straightforward SQL queries.

One very powerful BigQuery feature that can be used for this is User Defined Functions (UDF). UDFs execute Javascript code inside an SQL query.

Working code for this step is in step7/map.html .

UDFs in the BigQuery API

The BigQuery API approach for UDFs is slightly different to the web console: you'll need to call the jobs.insert method .

For Standard SQL queries via the API, just a single SQL statement is needed to use a User Defined Function. The value of useLegacySql must be set to false . The JavaScript example below shows a function that creates and sends a request object to insert a new job, in this case a query with a User Defined Function.

A working example of this approach is in 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));
}

The SQL query is constructed as follows:

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

There are two things going on here. Firstly the code is creating the CREATE TEMPORARY FUNCTION statement that encapsulates the JavaScript code to work out if a given point is inside a polygon. The polygon coordinates are inserted using the JSON.stringify(poly) method call to convert a JavaScript array of x,y coordinate pairs into a string. The polygon object is passed as an argument to the function that builds the SQL.

Secondly the code builds the main SQL SELECT statement. The UDF is called in the WHERE expression in this example.

Integrating with the Maps API

To use this with the Maps API drawing library, we need to save the polygon drawn by the user and pass this into the UDF part of the SQL query.

First, we need to handle the polygoncomplete drawing event, to get the coordinates of the shape as an array of longitude and latitude pairs:

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

The polygonQuery function can then construct the UDF Javascript functions as a string, as well as the SQL statement which will call the UDF function.

See step7/map.html for a working example of this.

Example output

Here's an example result of querying pickups from The 2016 NYC TLC Yellow Taxi data in BigQuery using a freehand polygon, with the selected data drawn as a heatmap.

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

13. Taking it Further

Here are some suggestions for ways to extend this codelab to look at other aspects of the data. You can find a working example of these ideas at step8/map.html in the code repository.

Mapping drop offs

So far we've only mapped pick up locations. By requesting the dropoff_latitude and dropoff_longitude columns and modifying the heatmap code to plot these instead, you can see the destinations of taxi journeys that started at a specific location.

For example, let's see where taxis tend to drop people off when they request a pick up around the Empire State Building.

Change the code for the SQL statement in polygonSql() to request these columns in addition to the pickup location.

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

The doHeatMap function can then use the dropoff values instead. The result object has a schema that can be inspected to find the location of these columns in the array. In this case they would be at index positions 2 and 3. These indices can be read from a variable to make the code more manageable. NB the maxIntensity of the heatmap is set to show density of 20 drop offs per pixel as the maximum.

Add some variables to allow you to change which columns you use for the heatmap data.

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

Here is a heatmap showing the distribution of drop offs from all pickups immediately around the Empire State Building in 2016. You can see large concentrations (the red blobs) of midtown destinations especially around Times Square, as well as along 5th Avenue between 23rd St and 14th St. Other high density locations not shown at this zoom level include La Guardia and JFK airports, the World Trade Center and Battery Park.

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

Styling the basemap

When you create a Google Map using the Maps JavaScript API, you can set the map style using a JSON object. For data visualizations it can be useful to mute the colors in the map. You can create and try out map styles using the Google Maps API Styling Wizard at mapstyle.withgoogle.com .

You can set a map style when you initialize a map object, or at any subsequent time afterwards. Here's how you'd add a custom style in the initMap() function:

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

The sample style below shows a greyscale map with points of interest labels.

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

Giving the user feedback

Even though BigQuery will usually give a response in seconds, it is sometimes useful to show the user that something is happening while the query is running.

Add some UI to your web page that shows the response of the checkJobStatus() function, and an animated graphic to indicate that the query is in progress.

Information you can display includes query duration, amount of data returned, and amount of data processed.

Add some HTML after the map <div> to create a panel to the page that will show the number of rows returned by a query, the time the query took, and the amount of data processed.

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

The appearance and position of this panel is controlled by CSS. Add CSS to position the panel in the top left corner of the page below the map type buttons and the drawing toolbar as in the snippet below.

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

The animated graphic can be added to the page but hidden until required, and some JavaScript and CSS code used to show it when a BigQuery job is running.

Add some HTML to show an animated graphic. There is an image file called loader.gif in the img folder in the code repository.

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

Add some CSS to position the image and hide it by default until it's needed.

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

Finally add some JavaScript to update the status panel and show or hide the graphic when a query is running. You can use the response object to update the panel depending on what information is available.

When checking a current job, there is a response.statistics property you can use. When the job is complete you can access the response.totalRows and response.totalBytesProcessed properties. It is helpful to the user to convert milliseconds to seconds and bytes to gigabytes for display as shown in the code sample below.

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

Call this method when there is a response to a checkJobStatus() call and when the query results are fetched. For example:

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

To toggle the animated graphic, add a function to control its visibility. This function will toggle the opacity of any HTML DOM Element passed to it.

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

Finally, call this method before processing a query, and after the query result has come back from BigQuery.

This code calls the fadeToggle function when the user has finished drawing a rectangle.

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

When the query response has been received, call fadeToggle() again to hide the animated graphic.

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

The page should look something like this.

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

Have a look at the complete example in step8/map.html .

14. Things to Consider

Too Many Markers

If you're working with very large tables, your query may return too many rows to efficiently display on a map. Limit the results by adding a WHERE clause or a LIMIT statement.

Drawing many markers can make the map unreadable. Consider using a HeatmapLayer to show the density, or cluster markers to indicate where many data points lie using a single symbol per cluster. There are more details in our Marker Clustering tutorial .

Optimizing Queries

BigQuery will scan the entire table with every query. To optimize your BigQuery quota usage, only select the columns you need in your query.

Queries will be faster if you store latitude and longitude as floats rather than strings.

Export Interesting Results

The examples here require the end user to be authenticated against the BigQuery table, which won't suit every use case. When you have discovered some interesting patterns, it may be easier to share these with a wider audience by exporting the results from BigQuery and creating a static dataset using the Google Maps Data Layer .

Bear in mind the Google Maps Platform Terms of Service . For more details on Google Maps Platform pricing, see the online documentation .

Play With More Data!

There are a number of public datasets in BigQuery that have latitude and longitude columns, for example the NYC Taxi datasets from 2009-2016 , Uber and Lyft NYC trip data , and the GDELT dataset .

15. Congratulations!

We hope this helps you get up and running quickly with some geo queries against BigQuery tables so you can discover patterns and visualize them on a Google Map. Happy mapping!

What's next?

If you'd like to learn more about the Google Maps Platform or BigQuery, have a look at the following suggestions.

See What is BigQuery to learn more about Google's serverless, petabyte-scale data warehouse service.

Have a look at the how-to guide to create a simple application using the BigQuery API .

See the developer guide for the drawing library for more details on enabling user interaction to draw shapes on a Google Map.

Have a look at other ways to visualize data on a Google Map.

See the Getting Started guide for the Javascript Client AP I to understand the basic concepts of using the Client API to access other Google APIs.