پرس و جو و تجسم داده های مکان در BigQuery با پلتفرم نقشه های گوگل (جاوا اسکریپت)

1. بررسی اجمالی

هنگام تجسم الگوهای موجود در یک مجموعه داده که به نوعی با مکان مرتبط هستند، نقشه ها می توانند ابزار بسیار قدرتمندی باشند. این رابطه می‌تواند نام یک مکان، یک مقدار طول و عرض جغرافیایی خاص، یا نام منطقه‌ای باشد که دارای مرز مشخصی مانند تراکت سرشماری یا کد پستی است.

هنگامی که این مجموعه داده ها بسیار بزرگ می شوند، پرس و جو و تجسم آنها با استفاده از ابزارهای معمولی دشوار است. با استفاده از Google BigQuery برای پرس و جو از داده ها و Google Maps API برای ساخت پرس و جو و تجسم خروجی، می توانید به سرعت الگوهای جغرافیایی در داده های خود را با تنظیمات یا کدگذاری بسیار کم و بدون نیاز به مدیریت یک سیستم برای ذخیره مجموعه داده های بسیار بزرگ کاوش کنید.

چیزی که خواهی ساخت

در این نرم افزار کد، شما چند پرس و جو می نویسید و اجرا می کنید که نشان می دهد چگونه می توان بینش های مبتنی بر مکان را در مجموعه داده های عمومی بسیار بزرگ با استفاده از BigQuery ارائه کرد. همچنین یک صفحه وب خواهید ساخت که با استفاده از API جاوا اسکریپت پلتفرم Google Maps، نقشه را بارگیری می کند، سپس پرس و جوهای فضایی را در برابر همان مجموعه داده های عمومی بسیار بزرگ با استفاده از Google APIs Client Library برای جاوا اسکریپت و BigQuery API اجرا می کند و تجسم می کند.

چیزی که یاد خواهید گرفت

  • نحوه پرس و جو از مجموعه داده های مکان در مقیاس پتابایت در چند ثانیه با BigQuery ، با استفاده از پرس و جوهای SQL ، توابع تعریف شده توسط کاربر و BigQuery API
  • چگونه می توان از پلتفرم نقشه های گوگل برای افزودن نقشه گوگل به یک صفحه وب استفاده کرد و کاربران را قادر ساخت تا شکل هایی را روی آن بکشند
  • نحوه تجسم پرس و جوها در برابر مجموعه داده های بزرگ در نقشه گوگل، مانند تصویر مثال زیر، که تراکم مکان های تاکسی را در سال 2016 از سفرهایی که از بلوک اطراف ساختمان امپایر استیت شروع شده را نشان می دهد.

اسکرین شات 09/05/2017 در ساعت 11.01.12.png

آنچه شما نیاز دارید

  • دانش اولیه HTML، CSS، جاوا اسکریپت، SQL، و ابزار توسعه کروم
  • یک مرورگر وب مدرن، مانند نسخه‌های اخیر کروم، فایرفاکس، سافاری یا اج.
  • یک ویرایشگر متن یا IDE به انتخاب شما

فناوری

BigQuery

BigQuery سرویس تجزیه و تحلیل داده های گوگل برای مجموعه داده های بسیار بزرگ است. دارای یک API RESTful است و از پرس و جوهای نوشته شده در SQL پشتیبانی می کند. اگر داده‌هایی با مقادیر طول و عرض جغرافیایی دارید، می‌توان از آنها برای جست‌وجوی داده‌های شما بر اساس مکان استفاده کرد. مزیت این است که شما می توانید به صورت بصری مجموعه داده های بسیار بزرگ را برای مشاهده الگوها بدون نیاز به مدیریت زیرساخت سرور یا پایگاه داده کاوش کنید. با استفاده از مقیاس‌پذیری عظیم BigQuery و زیرساخت مدیریت‌شده، می‌توانید در چند ثانیه به سؤالات خود پاسخ دهید.

پلتفرم نقشه های گوگل

پلتفرم نقشه های گوگل دسترسی برنامه ریزی شده به نقشه، مکان و داده های مسیر گوگل را فراهم می کند. بیش از 2 میلیون وب سایت و برنامه در حال حاضر از آن برای ارائه نقشه های جاسازی شده و جستجوهای مبتنی بر مکان به کاربران خود استفاده می کنند.

لایه طراحی جاوا اسکریپت API پلتفرم Google Maps به شما امکان می دهد شکل ها را روی نقشه بکشید. اینها را می توان به ورودی برای اجرای پرس و جوها در برابر جداول BigQuery که مقادیر طول و عرض جغرافیایی در ستون ها ذخیره شده اند تبدیل کرد.

برای شروع به یک پروژه Google Cloud Platform با فعال بودن BigQuery و Maps API نیاز دارید.

2. راه اندازی

حساب گوگل

اگر قبلاً یک حساب Google (Gmail یا Google Apps) ندارید، باید یک حساب ایجاد کنید .

یک پروژه ایجاد کنید

به کنسول Google Cloud Platform ( consol.cloud.google.com ) وارد شوید و یک پروژه جدید ایجاد کنید. در بالای صفحه شما، یک منوی کشویی Project وجود دارد:

f2a353c3301dc649.png

هنگامی که روی منوی کشویی این پروژه کلیک کنید، یک آیتم منو دریافت خواهید کرد که به شما امکان می دهد یک پروژه جدید ایجاد کنید:

56a42dfa7ac27a35.png

در کادری که می گوید «نام جدیدی برای پروژه خود وارد کنید»، نامی برای پروژه جدید خود وارد کنید، به عنوان مثال «BigQuery Codelab»:

Codelab - ایجاد پروژه (1).png

شناسه پروژه برای شما ایجاد خواهد شد. شناسه پروژه یک نام منحصر به فرد در تمام پروژه های Google Cloud است. ID پروژه خود را به خاطر بسپارید، زیرا بعداً از آن استفاده خواهید کرد. نام فوق قبلاً گرفته شده است و برای شما کار نخواهد کرد. شناسه پروژه خود را در هر جایی که YOUR_PROJECT_ID را در این آزمایشگاه کد مشاهده کردید وارد کنید.

فعال کردن صورتحساب

برای ثبت نام در BigQuery، از پروژه انتخاب شده یا ایجاد شده در مرحله قبل استفاده کنید. صورتحساب باید در این پروژه فعال باشد. پس از فعال شدن صورتحساب، می توانید BigQuery API را فعال کنید.

نحوه فعال کردن صورت‌حساب بستگی به این دارد که آیا در حال ایجاد یک پروژه جدید هستید یا در حال فعال کردن مجدد صورت‌حساب برای یک پروژه موجود هستید.

Google یک دوره آزمایشی رایگان 12 ماهه را به ارزش حداکثر 300 دلار از پلتفرم Google Cloud ارائه می دهد که ممکن است بتوانید برای این Codelab از آن استفاده کنید، جزئیات بیشتر را در https://cloud.google.com/free/ بیابید.

پروژه های جدید

هنگامی که یک پروژه جدید ایجاد می کنید، از شما خواسته می شود که انتخاب کنید کدام یک از حساب های صورتحساب خود را می خواهید به پروژه پیوند دهید. اگر فقط یک حساب صورت‌حساب دارید، آن حساب به طور خودکار به پروژه شما مرتبط می‌شود.

اگر حساب صورت‌حساب ندارید، قبل از اینکه بتوانید از بسیاری از ویژگی‌های Google Cloud Platform استفاده کنید، باید حسابی ایجاد کنید و صورت‌حساب را برای پروژه خود فعال کنید. برای ایجاد یک حساب صورت‌حساب جدید و فعال کردن صورت‌حساب برای پروژه خود، دستورالعمل‌های موجود در ایجاد یک حساب صورت‌حساب جدید را دنبال کنید.

پروژه های موجود

اگر پروژه‌ای دارید که به‌طور موقت صدور صورت‌حساب را غیرفعال کرده‌اید، می‌توانید صورت‌حساب را دوباره فعال کنید:

  1. به کنسول Cloud Platform بروید.
  2. از لیست پروژه ها، پروژه ای را برای فعال کردن مجدد صورتحساب انتخاب کنید.
  3. منوی سمت چپ کنسول را باز کرده و Billing را انتخاب کنید Billing . از شما خواسته می شود یک حساب صورتحساب را انتخاب کنید.
  4. روی تنظیم حساب کلیک کنید.

یک حساب صورتحساب جدید ایجاد کنید

برای ایجاد یک حساب صورتحساب جدید:

  1. به کنسول Cloud Platform بروید و وارد شوید یا اگر قبلاً حساب ندارید، ثبت نام کنید.
  2. منوی سمت چپ کنسول را باز کرده و Billing را انتخاب کنید Billing
  3. روی دکمه حساب صورت‌حساب جدید کلیک کنید. (توجه داشته باشید که اگر این اولین حساب صورت‌حساب شما نیست، ابتدا باید فهرست حساب‌های صورت‌حساب را با کلیک کردن روی نام حساب صورت‌حساب موجود در بالای صفحه، و سپس روی مدیریت حساب‌های صورت‌حساب ، باز کنید.)
  4. نام حساب صورتحساب را وارد کنید و اطلاعات صورتحساب خود را وارد کنید. گزینه هایی که مشاهده می کنید به کشور آدرس صورتحساب شما بستگی دارد. توجه داشته باشید که برای حساب های ایالات متحده، نمی توانید وضعیت مالیات را پس از ایجاد حساب تغییر دهید.
  5. روی ارسال کلیک کنید و صورتحساب را فعال کنید .

به‌طور پیش‌فرض، شخصی که حساب صورت‌حساب را ایجاد می‌کند، سرپرست صورت‌حساب برای حساب است.

برای اطلاعات در مورد تأیید حساب‌های بانکی و افزودن روش‌های پرداخت پشتیبان، به افزودن، حذف یا به‌روزرسانی روش پرداخت مراجعه کنید.

BigQuery API را فعال کنید

برای فعال کردن BigQuery API در پروژه خود، به صفحه BigQuery API Marketplace در کنسول بروید و روی دکمه آبی «Enable» کلیک کنید.

3. جستجوی داده های مکان در BigQuery

سه راه برای جستجوی داده های مکان ذخیره شده به عنوان مقادیر طول و عرض جغرافیایی در BigQuery وجود دارد.

  • پرس و جوهای مستطیلی : ناحیه مورد نظر را به عنوان پرس و جوی مشخص کنید که همه ردیف ها را در محدوده حداقل و حداکثر طول و عرض جغرافیایی انتخاب می کند.
  • پرس و جوهای شعاع : ناحیه مورد نظر را با محاسبه یک دایره به دور یک نقطه با استفاده از فرمول هاورسین و توابع ریاضی برای مدل سازی شکل زمین مشخص کنید.
  • پرس و جوهای چند ضلعی : یک شکل سفارشی را مشخص کنید و از یک تابع تعریف شده توسط کاربر برای بیان منطق نقطه در چند ضلعی مورد نیاز برای آزمایش اینکه آیا طول و عرض جغرافیایی هر ردیف در داخل شکل قرار می گیرد یا خیر، استفاده کنید.

برای شروع، از ویرایشگر Query در بخش Big Query کنسول Google Cloud Platform استفاده کنید تا درخواست‌های زیر را در برابر داده‌های تاکسی نیویورک اجرا کنید.

SQL استاندارد در مقابل SQL قدیمی

BigQuery از دو نسخه SQL پشتیبانی می کند: Legacy SQL و Standard SQL . مورد دوم استاندارد ANSI 2011 است. برای اهداف این آموزش، ما از استاندارد SQL استفاده خواهیم کرد زیرا مطابقت بهتری با استانداردها دارد.

اگر می خواهید Legacy SQL را در ویرایشگر BigQuery اجرا کنید، می توانید این کار را با انجام موارد زیر انجام دهید:

  1. روی دکمه "بیشتر" کلیک کنید
  2. از منوی کشویی گزینه Query settings را انتخاب کنید
  3. در زیر "گویش SQL"، دکمه رادیویی "Legacy" را انتخاب کنید
  4. روی دکمه "ذخیره" کلیک کنید

پرس و جوهای مستطیل

ساخت کوئری های مستطیل در BigQuery کاملاً ساده است. شما فقط باید یک بند WHERE اضافه کنید که نتایج بازگردانده شده را محدود به نتایجی می کند که مکان هایی بین حداقل و حداکثر مقادیر برای طول و عرض جغرافیایی دارند.

مثال زیر را در کنسول BigQuery امتحان کنید. این پرس و جو برای برخی از آمار متوسط سفر برای سواری هایی است که در یک منطقه مستطیل شکل که شامل مرکز شهر و منهتن پایینی است شروع شده است. دو مکان مختلف وجود دارد که می توانید امتحان کنید، بند دوم 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

نتایج برای دو پرس و جو نشان می دهد که تفاوت های زیادی در میانگین مسافت سفر، کرایه و انعام برای دریافت در دو مکان وجود دارد.

منهتن

avg_tip

avg_fare

میانگین_فاصله

avg_tip_pc

avg_fare_mile

2.52

12.03

9.97

22.39

5.97

جی اف کی

avg_tip

avg_fare

میانگین_فاصله

avg_tip_pc

avg_fare_mile

9.22

48.49

41.19

22.48

4.36

پرس و جوهای شعاع

اگر کمی ریاضی بدانید، پرس و جوهای Radius نیز به راحتی در SQL ساخته می شوند. با استفاده از توابع ریاضی SQL Legacy BigQuery می‌توانید با استفاده از فرمول Haversine که یک ناحیه دایره‌ای یا کلاهک کروی روی سطح زمین را تقریب می‌کند، یک پرس و جوی SQL بسازید.

در اینجا یک مثال بیانیه BigQuery SQL برای یک پرس و جو دایره ای با مرکز 40.73943, -73.99585 با شعاع 0.1 کیلومتر است.

از مقدار ثابت 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 برای فرمول Haversine پیچیده به نظر می رسد، اما تنها کاری که باید انجام دهید این است که مختصات مرکز دایره، شعاع و پروژه، مجموعه داده ها و نام جدول را برای 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

6.42

برانکس

avg_tip

avg_fare

میانگین_فاصله

avg_tip_pc

avg_fare_mile

0.52

17.63

4.75

4.74

10.9

پرس و جوهای چند ضلعی

SQL از پرس و جو با استفاده از اشکال دلخواه به جز مستطیل و دایره پشتیبانی نمی کند. BigQuery هیچ نوع داده هندسی بومی یا شاخص فضایی ندارد، بنابراین برای اجرای پرس‌و‌جوها با استفاده از اشکال چند ضلعی، به رویکرد متفاوتی برای پرس‌وجوهای ساده SQL نیاز دارید. یک روش این است که یک تابع هندسه را در جاوا اسکریپت تعریف کنیم و آن را به عنوان یک تابع تعریف شده توسط کاربر (UDF) در BigQuery اجرا کنیم.

بسیاری از عملیات هندسی را می توان در جاوا اسکریپت نوشت، بنابراین به راحتی می توان یکی را برداشت و در جدول BigQuery که حاوی مقادیر طول و عرض جغرافیایی است، اجرا کرد. شما باید چند ضلعی سفارشی را از طریق یک UDF عبور دهید و آزمایشی را در مقابل هر ردیف انجام دهید و فقط سطرهایی را که عرض و طول جغرافیایی در داخل چند ضلعی قرار می گیرند برگردانید. درباره UDF ها در مرجع BigQuery اطلاعات بیشتری کسب کنید .

الگوریتم Point In Polygon

راه های زیادی برای محاسبه قرار گرفتن یک نقطه در یک چندضلعی در جاوا اسکریپت وجود دارد. در اینجا یکی از پورت های 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;
}

هنگام استفاده از استاندارد SQL در BigQuery، رویکرد UDF فقط به یک دستور نیاز دارد، اما UDF باید به عنوان یک تابع موقت در دستور تعریف شود. در اینجا یک مثال است. عبارت SQL زیر را در پنجره Query Editor قرار دهید.

CREATE TEMPORARY FUNCTION pointInPolygon(latitude FLOAT64, longitude FLOAT64)
RETURNS BOOL LANGUAGE js AS """
  let polygon=[[-73.98925602436066,40.743249676056955],[-73.98836016654968,40.74280666503313],[-73.98915946483612,40.741676770346295],[-73.98967981338501,40.74191656974406]];

  let vertx = [],
    verty = [],
    nvert = 0,
    testx = longitude,
    testy = latitude,
    c = false,
    j = nvert - 1;

  for (let coord of polygon){
    vertx[nvert] = coord[0];
    verty[nvert] = coord[1];
    nvert ++;
  }

  // The rest of this function is the ported implementation.
  for (let i = 0; i < nvert; j = i++) {
    if ( ((verty[i] > testy) != (verty[j] > testy)) &&
 (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]) ) {
      c = !c;
    }
  }

  return c;
""";

SELECT pickup_latitude, pickup_longitude, dropoff_latitude, dropoff_longitude, pickup_datetime
FROM `bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2016`
WHERE pointInPolygon(pickup_latitude, pickup_longitude) = TRUE
AND (pickup_datetime BETWEEN CAST("2016-01-01 00:00:01" AS DATETIME) AND CAST("2016-02-28 23:59:59" AS DATETIME))
LIMIT 1000

تبریک می گویم!

اکنون سه نوع پرس و جو فضایی را با استفاده از BigQuery اجرا کرده اید. همانطور که مشاهده کردید، مکان تفاوت بزرگی در داده‌های نتیجه پرس‌و‌جوها در برابر این مجموعه داده ایجاد می‌کند، اما مگر اینکه حدس بزنید کجا کوئری‌های خود را اجرا کنید، کشف الگوهای فضایی ad-hoc فقط با استفاده از جستارهای SQL دشوار است.

اگر فقط می توانستیم داده ها را روی نقشه تجسم کنیم و با تعریف مناطق مورد علاقه دلخواه، داده ها را کشف کنیم! خوب، با استفاده از API های Google Maps می توانید این کار را انجام دهید. ابتدا باید Maps API را فعال کنید، یک صفحه وب ساده در حال اجرا بر روی دستگاه محلی خود راه اندازی کنید، و شروع به استفاده از BigQuery API برای ارسال درخواست ها از صفحه وب خود کنید.

4. کار با Google Maps APIs

با اجرای برخی پرس‌و‌جوهای فضایی ساده، گام بعدی تجسم خروجی برای دیدن الگوها است. برای انجام این کار، Maps API را فعال می‌کنید، یک صفحه وب ایجاد می‌کنید که پرس‌وجوها را از نقشه به BigQuery ارسال می‌کند، سپس نتایج را روی نقشه ترسیم می‌کند.

Maps JavaScript API را فعال کنید

برای این Codelab، باید API جاوا اسکریپت Maps Platform Google Maps را در پروژه خود فعال کنید. برای این کار موارد زیر را انجام دهید:

  1. در کنسول Google Cloud Platform، به Marketplace بروید
  2. در Marketplace، «Maps JavaScript API» را جستجو کنید
  3. روی کاشی Maps JavaScript API در نتایج جستجو کلیک کنید
  4. روی دکمه "فعال کردن" کلیک کنید

یک کلید API ایجاد کنید

برای درخواست به پلتفرم نقشه های گوگل، باید یک کلید API ایجاد کنید و آن را با تمام درخواست ها ارسال کنید. برای ایجاد یک کلید API، موارد زیر را انجام دهید:

  1. در کنسول Google Cloud Platform، روی منوی همبرگر کلیک کنید تا ناوبری سمت چپ باز شود
  2. «APIs & Service» > «Credentials» را انتخاب کنید
  3. روی دکمه «ایجاد اعتبارنامه» کلیک کنید، سپس «کلید API» را انتخاب کنید.
  4. کلید API جدید را کپی کنید

کد را دانلود کنید و یک وب سرور راه اندازی کنید

برای دانلود تمام کدهای این کد لبه روی دکمه زیر کلیک کنید:

فایل فشرده دانلود شده را باز کنید. با این کار یک پوشه ریشه ( bigquery ) باز می شود که شامل یک پوشه برای هر مرحله از این Codelab به همراه تمام منابعی است که شما نیاز دارید.

پوشه های stepN شامل وضعیت پایانی مطلوب هر مرحله از این کد لبه هستند. آنها برای مرجع وجود دارد. ما تمام کارهای کدنویسی خود را در دایرکتوری به نام work انجام خواهیم داد.

یک وب سرور محلی راه اندازی کنید

در حالی که شما آزاد هستید که از وب سرور خود استفاده کنید، این کد لبه برای کار با وب سرور کروم طراحی شده است. اگر هنوز آن برنامه را نصب نکرده‌اید، می‌توانید آن را از فروشگاه وب Chrome نصب کنید.

پس از نصب برنامه را باز کنید. در کروم می توانید این کار را به صورت زیر انجام دهید:

  1. کروم را باز کنید
  2. در نوار آدرس در بالا، chrome://apps را تایپ کنید
  3. Enter را فشار دهید
  4. در پنجره ای که باز می شود، روی نماد وب سرور کلیک کنید، همچنین می توانید روی یک برنامه کلیک راست کنید تا در یک برگه معمولی یا پین شده، تمام صفحه یا پنجره جدید باز شود. a3ed00e79b8bfee7.png در ادامه این گفتگو را خواهید دید که به شما امکان می دهد وب سرور محلی خود را پیکربندی کنید: 81b6151c3f60c948.png
  5. روی «انتخاب پوشه» کلیک کنید و مکانی را انتخاب کنید که فایل‌های نمونه لبه کد را در آن دانلود کرده‌اید
  6. در بخش «گزینه‌ها»، کادر کنار «نمایش خودکار index.html» را علامت بزنید: 17f4913500faa86f.png
  7. کلید ضامن با عنوان "وب سرور: شروع شد" را به سمت چپ بلغزانید و سپس به سمت راست برگردید تا متوقف شود و سپس وب سرور را مجددا راه اندازی کنید.

a5d554d0d4a91851.png

5. بارگذاری نقشه و ابزار ترسیم

یک صفحه نقشه اولیه ایجاد کنید

با یک صفحه HTML ساده شروع کنید که نقشه گوگل را با استفاده از Maps JavaScript API و چند خط جاوا اسکریپت بارگیری می کند. کد از نمونه نقشه ساده پلتفرم نقشه های گوگل مکانی عالی برای شروع است. در اینجا بازتولید شده است تا بتوانید آن را در ویرایشگر متن یا IDE انتخابی خود کپی و جایگذاری کنید، یا می توانید با باز کردن index.html از مخزن بارگیری شده، آن را پیدا کنید.

  1. index.html در پوشه work موجود در نسخه محلی مخزن کپی کنید
  2. پوشه img/ را در پوشه work/ در نسخه محلی مخزن کپی کنید
  3. work/ 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 می‌گوید کتابخانه طراحی را فعال کند، تغییر می‌دهید.

این کد لبه همچنین از 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. برای ایجاد DrawingManager تابعی به نام setUpDrawingTools() با کد زیر اضافه کنید و ویژگی map آن را برای ارجاع به شی نقشه در صفحه تنظیم کنید.

گزینه‌های ارسال شده به google.maps.drawing.DrawingManager(options) نوع طراحی شکل پیش‌فرض و گزینه‌های نمایش شکل‌های ترسیم شده را تنظیم می‌کنند. برای انتخاب مناطق نقشه برای ارسال به عنوان پرس و جو، اشکال باید کدورت صفر داشته باشند. برای اطلاعات بیشتر در مورد گزینه های موجود، به گزینه های 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. پس از ایجاد شی نقشه در تابع initMap() 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 Client API

Google BigQuery Client API به شما کمک می‌کند تا از نوشتن تعداد زیادی کدهای مورد نیاز برای ایجاد درخواست‌ها، تجزیه پاسخ‌ها و رسیدگی به احراز هویت جلوگیری کنید. این کد لبه از BigQuery API از طریق Google APIs Client Library برای جاوا اسکریپت استفاده می کند زیرا ما در حال توسعه یک برنامه مبتنی بر مرورگر خواهیم بود.

در مرحله بعد، کدی را برای بارگذاری این API در یک صفحه وب اضافه می‌کنید و از آن برای تعامل با BigQuery استفاده می‌کنید.

Google Client API را برای جاوا اسکریپت اضافه کنید

شما از Google Client API برای جاوا اسکریپت برای اجرای پرس و جوها در برابر 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، از منوی Navigation ، APIs & Services > Credentials را انتخاب کنید.

قبل از اینکه بتوانید اعتبارنامه خود را تنظیم کنید، باید تنظیماتی را برای صفحه مجوز اضافه کنید که کاربر نهایی برنامه شما زمانی که برنامه شما را برای دسترسی به داده‌های BigQuery از طرف خود مجوز می‌دهد، ببیند.

برای انجام این کار، روی برگه صفحه رضایت OAuth کلیک کنید. 2. باید Big Query API را به محدوده های این توکن اضافه کنید. روی دکمه Add Scope در بخش Scopes for Google APIs کلیک کنید. 3. از لیست، کادر کنار ورودی Big Query API را با ../auth/bigquery scope علامت بزنید. 4. روی افزودن کلیک کنید. 5. نامی را در قسمت "نام برنامه" وارد کنید. 6. برای ذخیره تنظیمات خود روی Save کلیک کنید. 7. در مرحله بعد شما OAuth Client ID خود را ایجاد می کنید. برای انجام این کار، روی Create Credentials کلیک کنید:

4d18a965fc760e39.png

  1. در منوی کشویی، روی OAuth Client ID کلیک کنید. 1f8b36a1c27c75f0.png
  2. در قسمت Application Type، Web application را انتخاب کنید.
  3. در قسمت Application Name یک نام برای پروژه خود تایپ کنید. به عنوان مثال "BigQuery and Maps".
  4. در قسمت Restrictions ، در قسمت Authorized JavaScript Origins، URL لوکال هاست شامل شماره پورت را وارد کنید. به عنوان مثال: http://localhost:8887
  1. روی دکمه Create کلیک کنید.

یک پاپ آپ شناسه مشتری و راز مشتری را به شما نشان می دهد. برای انجام احراز هویت در برابر BigQuery به شناسه مشتری نیاز دارید. آن را کپی کرده و به عنوان یک متغیر جهانی جاوا اسکریپت جدید به نام clientId در work/index.html قرار دهید.

let clientId = 'YOUR_CLIENT_ID';

7. مجوز و مقداردهی اولیه

صفحه وب شما باید قبل از شروع اولیه نقشه، به کاربر اجازه دسترسی به BigQuery را بدهد. در این مثال ما از OAuth 2.0 همانطور که در بخش مجوز اسناد JavaScript Client API توضیح داده شده است استفاده می کنیم. شما باید از شناسه مشتری OAuth و شناسه پروژه خود برای ارسال پرس و جو استفاده کنید.

هنگامی که Google Client API در صفحه وب بارگیری می شود، باید مراحل زیر را انجام دهید:

  • اجازه دادن به کاربر
  • در صورت مجوز، BigQuery API را بارگیری کنید.
  • نقشه را بارگیری و مقداردهی اولیه کنید.

برای مثالی از نحوه ظاهر صفحه تمام شده HTML به step3/map.html مراجعه کنید.

اجازه دادن به کاربر

کاربر نهایی برنامه باید به برنامه اجازه دسترسی به داده ها در BigQuery از طرف خود را بدهد. Google Client API برای جاوا اسکریپت منطق OAuth را برای انجام این کار مدیریت می کند.

در یک برنامه دنیای واقعی، انتخاب های زیادی در مورد نحوه ادغام مرحله مجوز دارید.

برای مثال، می‌توانید authorize() از یک عنصر UI مانند یک دکمه فراخوانی کنید، یا این کار را زمانی که صفحه بارگذاری شد انجام دهید. در اینجا ما انتخاب کرده‌ایم که پس از بارگیری Google Client API برای جاوا اسکریپت، با استفاده از تابع callback در متد gapi.load() ، به کاربر اجازه دهیم.

بلافاصله بعد از تگ <script> کدی بنویسید که Google Client 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 بگیرد که به شما امکان می دهد جریان منطق را بسته به اینکه کاربر با موفقیت مجاز شده است یا خیر کنترل کنید.

همچنین تابعی به نام loadApi برای بارگیری BigQuery API در صورتی که کاربر با موفقیت مجاز شد، اضافه کنید.

اگر یک شی authResult به تابع ارسال شده باشد، و اگر ویژگی error شی دارای مقدار false باشد، منطق تابع handleAuthResult() را برای فراخوانی loadApi() اضافه کنید.

برای بارگذاری BigQuery API با استفاده از متد gapi.client.load() کد را به تابع 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');
}

نقشه را بارگیری کنید

مرحله آخر، مقداردهی اولیه نقشه است. برای این کار باید ترتیب منطق را کمی تغییر دهید. در حال حاضر زمانی که Maps API جاوا اسکریپت بارگیری می شود، مقداردهی اولیه می شود.

می توانید این کار را با فراخوانی تابع initMap() از متد then() بعد از متد load() روی شی gapi.client انجام دهید.

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

8. مفاهیم API BigQuery

فراخوان‌های BigQuery API معمولاً در چند ثانیه اجرا می‌شوند اما ممکن است فوراً پاسخی دریافت نکنند. برای نظرسنجی BigQuery برای اطلاع از وضعیت مشاغل طولانی مدت نیاز به منطق دارید و فقط زمانی که کار کامل شد نتایج را دریافت کنید.

کد کامل این مرحله در step4/map.html است.

ارسال درخواست

یک تابع جاوا اسکریپت به 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 در زیر نشان می‌دهد که چگونه می‌توان وضعیت یک کار را به صورت دوره‌ای، با استفاده از متد 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]);    
  });
}

متد 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 وجود دارد:

  • انتخاب با مستطیل (در غیر این صورت به عنوان جعبه محدود شناخته می شود)،
  • انتخاب بر اساس شعاع، و
  • ویژگی قدرتمند توابع تعریف شده توسط کاربر .

در بخش توابع ریاضی در مرجع 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 است. در Legacy SQL project.dataset.tablename است.

جداول زیادی از سفرهای تاکسی نیویورک موجود است. برای دیدن آنها، به کنسول وب BigQuery بروید و آیتم منو "مجموعه داده های عمومی" را گسترش دهید. مجموعه داده ای به نام new_york را پیدا کنید و آن را برای دیدن جداول گسترش دهید. جدول سفرهای تاکسی زرد را انتخاب کنید: bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2016 ).

تعیین شناسه پروژه

در تماس API، باید نام پروژه Google Cloud Platform خود را برای اهداف صورت‌حساب مشخص کنید. در این کد لبه، این پروژه مشابه پروژه حاوی جدول نیست . اگر با جدولی کار می‌کردید که در پروژه خود با آپلود داده‌ها ایجاد کرده بودید، این شناسه پروژه مانند آنچه در دستور SQL شما است، خواهد بود.

متغیرهای جاوا اسکریپت را به کد خود اضافه کنید تا ارجاعاتی را به پروژه مجموعه داده های عمومی که شامل جدولی است که در حال پرس و جو هستید، به اضافه نام جدول و نام مجموعه داده می شود. همچنین برای ارجاع به شناسه پروژه صورتحساب خود به یک متغیر جداگانه نیاز دارید.

متغیرهای جاوا اسکریپت جهانی به نام های billingProjectId, publicProjectId, datasetId و tableName را به نسخه index.html خود اضافه کنید.

متغیرهای 'publicProjectId' ، 'datasetId' و 'tableName' را با جزئیات پروژه BigQuery Public Datasets راه اندازی کنید. billingProjectId با شناسه پروژه خود (هونی که قبلاً در "Getting Set Up" در این Codelab ایجاد کردید) راه اندازی کنید.

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. تجسم پاسخ

جداول BigQuery می تواند بسیار بزرگ باشد - گلهای داده داده - و می توانند صدها هزار ردیف در ثانیه رشد کنند. بنابراین مهم است که مقدار داده های برگشتی را محدود کنید تا بتوانید روی نقشه ترسیم شود. ترسیم محل هر ردیف در یک مجموعه نتیجه بسیار بزرگ (ده ها هزار ردیف یا بیشتر) منجر به یک نقشه غیرقابل خواندن خواهد شد. تکنیک های زیادی برای جمع آوری مکان ها هم در پرس و جو SQL و چه در نقشه وجود دارد ، و می توانید نتیجه ای را که یک پرس و جو باز می گردد محدود کنید.

کد کامل این مرحله در مرحله 5/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 ، شما فقط از ارزش عرض جغرافیایی و طول جغرافیایی وانت تاکسی خواسته اید ، بنابراین فقط دو ستون در پاسخ وجود خواهد داشت.

فراموش نکنید که وقتی آرایه موقعیت ها را به آن اختصاص داده اید ، setMap() در لایه heatmap تماس بگیرید. این کار را در نقشه قابل مشاهده می کند.

در اینجا یک مثال است:

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 مجاز باشید
  • مستطیل را در جایی در NYC بکشید
  • نتایج پرس و جو حاصل را به عنوان یک نقشه گرما مشاهده کنید.

در اینجا نمونه ای از نتیجه از یک پرس و جو مستطیل در برابر داده های تاکسی زرد NYC 2016 ، که به عنوان یک نقشه گرما تهیه شده است ، آورده شده است. این نشان می دهد توزیع وانت در اطراف ساختمان امپراتوری ایالت در یک شنبه در ماه ژوئیه:

7b1face0e7c71c78.png

11. پرس و جو توسط شعاع در اطراف یک نقطه

نمایش داده های شعاع بسیار مشابه است. با استفاده از توابع ریاضی SQL Legacy BigQuy می توانید با استفاده از فرمول Haversine که یک منطقه دایره ای را روی سطح زمین تقریبی می کند ، یک پرس و جو SQL ایجاد کنید.

با استفاده از همین تکنیک برای مستطیل ها ، می توانید یک رویداد OverlayComplete برای به دست آوردن مرکز و شعاع یک دایره کاربر کشیده شده انجام دهید و SQL را برای پرس و جو به همان روش بسازید.

یک نمونه کار از کد برای این مرحله در مخزن کد به عنوان مرحله 6/map.html گنجانده شده است.

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

در کپی خود از index.html ، دو کارکرد خالی جدید اضافه کنید: circleQuery() و haversineSQL() .

سپس ، یک کنترل کننده رویداد circlecomplete که از مرکز و شعاع عبور می کند به عملکرد جدیدی به نام circleQuery().

تابع circleQuery() برای ساخت SQL برای پرس و جو ، haversineSQL() را فراخوانی می کند و سپس با فراخوانی عملکرد 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. پرس و جو اشکال دلخواه

recap: SQL از پرس و جو با استفاده از اشکال دلخواه غیر از مستطیل ها و دایره ها پشتیبانی نمی کند. BigQuery هیچ نوع داده هندسه بومی ندارد ، بنابراین برای اجرای نمایش داده ها با استفاده از اشکال چند ضلعی ، به یک روش متفاوت برای نمایش داده های SQL ساده نیاز دارید.

یکی از ویژگی های بسیار قدرتمند BigQuery که می تواند برای این کار استفاده شود ، توابع تعریف شده کاربر (UDF) است. UDF ها کد JavaScript را در یک پرس و جو SQL اجرا می کنند.

کد کار برای این مرحله در مرحله 7/map.html است.

UDFS در API BigQuery

رویکرد API BigQuery برای UDFS با کنسول وب کمی متفاوت است: شما باید با jobs.insert method تماس بگیرید.

برای پرس و جوهای استاندارد SQL از طریق API ، فقط یک عبارت SQL برای استفاده از یک تابع تعریف شده کاربر لازم است. مقدار useLegacySql باید روی false تنظیم شود. مثال JavaScript در زیر تابعی را نشان می دهد که یک شی درخواست را برای وارد کردن یک کار جدید ایجاد و ارسال می کند ، در این حالت یک پرس و جو با یک عملکرد تعریف شده کاربر.

یک نمونه کار از این رویکرد در مرحله 7/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;
}

اینجا دو چیز در جریان است. در مرحله اول ، کد در حال ایجاد بیانیه CREATE TEMPORARY FUNCTION است که کد JavaScript را محصور می کند تا اگر یک نقطه معین در یک چند ضلعی باشد ، کار کند. مختصات چند ضلعی با استفاده از روش JSON.stringify(poly) برای تبدیل یک آرایه JavaScript از جفت های X ، Y به یک رشته درج می شوند. شیء چند ضلعی به عنوان یک آرگومان برای عملکردی که SQL را ایجاد می کند ، منتقل می شود.

ثانیا ، کد عبارت اصلی SQL SELECT را ایجاد می کند. UDF در عبارت WHERE در این مثال خوانده می شود.

ادغام با API نقشه ها

برای استفاده از این با کتابخانه نقشه نقشه 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 را فراخوانی می کند ، بسازد.

برای مثال کاری از این مورد به مرحله 7/map.html مراجعه کنید.

نمونه خروجی

در اینجا نمونه ای از پرس و جو وانت از داده های تاکسی زرد NYC TLC 2016 با استفاده از چند ضلعی آزاد ، با داده های انتخاب شده به عنوان نقشه گرما تهیه شده است.

صفحه نمایش 2017-05-09 در ساعت 10.00.48 am.png

13.

در اینجا چند پیشنهاد برای راه های گسترش این CodeLab برای بررسی جنبه های دیگر داده ها آورده شده است. می توانید یک نمونه کار از این ایده ها را در Step8/map.html در مخزن کد پیدا کنید.

قطره نقشه برداری

تاکنون ما فقط مکانهای انتخابی را نقشه برداری کرده ایم. با درخواست ستون های dropoff_latitude و dropoff_longitude و اصلاح کد Heatmap برای ترسیم این موارد ، می توانید مقصد سفرهای تاکسی را که در یک مکان خاص شروع شده است ، مشاهده کنید.

به عنوان مثال ، بیایید ببینیم که تاکسی ها هنگام درخواست انتخاب در اطراف ساختمان امپراتوری ایالتی ، مردم را رها می کنند.

کد عبارت 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 قرار بگیرند. این شاخص ها را می توان از یک متغیر خواند تا کد قابل کنترل تر شود. NB maxIntensity نقشه گرما تنظیم شده است تا چگالی 20 قطره در هر پیکسل را به عنوان حداکثر نشان دهد.

برخی از متغیرها را اضافه کنید تا به شما امکان دهد ستون هایی را که برای داده های Heatmap استفاده می کنید تغییر دهید.

// 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 نشان می دهد. شما می توانید غلظت های بزرگی (حباب های قرمز) مقصد های میانه شهر به ویژه در اطراف میدان تایمز را مشاهده کنید ، و همچنین در امتداد خیابان 5 بین خیابان 23 و خیابان 14th مکانهای با چگالی بالا که در این سطح زوم نشان داده نشده است شامل مرکز تجارت La Hugadia و JFK ، مرکز تجارت جهانی است. پارک باتری.

صفحه نمایش 2017-05-09 در ساعت 10.40.01 am.png

یک ظاهر طراحی شده

هنگامی که با استفاده از نقشه های JavaScript API نقشه Google ایجاد می کنید ، می توانید سبک نقشه را با استفاده از یک شیء JSON تنظیم کنید. برای تجسم داده ها می توان رنگهای موجود در نقشه را نادیده گرفت. می توانید سبک های نقشه را با استفاده از جادوگر Google Maps API یک ظاهر طراحی شده در 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();
}

سبک نمونه زیر نقشه Greyscale با برچسب های مورد علاقه را نشان می دهد.

[
  {
    "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 برای نشان دادن آن هنگام کار یک کار بزرگ استفاده می شود.

برای نشان دادن یک گرافیک متحرک مقداری 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 را اضافه کنید تا پانل وضعیت را به روز کنید و هنگام اجرای یک پرس و جو ، گرافیک را نشان دهید یا پنهان کنید. بسته به اینکه اطلاعات موجود است ، می توانید از Object response برای به روزرسانی پانل استفاده کنید.

هنگام بررسی یک کار فعلی ، یک response.statistics وجود دارد. پس از اتمام کار ، می توانید به خواص response.totalRows و پاسخ. 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);
  })
}

صفحه باید چیزی شبیه به این باشد.

صفحه نمایش 2017-05-10 در ساعت 2.32.19 بعد از ظهر. png

نگاهی به مثال کامل در مرحله 8/map.html بیندازید.

14. چیزهایی که باید در نظر بگیرید

نشانگرهای خیلی زیاد

اگر در حال کار با جداول بسیار بزرگ هستید ، ممکن است پرس و جو شما ردیف های زیادی را برای نمایش کارآمد در نقشه بازگرداند. با اضافه کردن بند WHERE یا یک بیانیه LIMIT ، نتایج را محدود کنید.

ترسیم بسیاری از نشانگرها می تواند نقشه را غیرقابل خواندن کند. با استفاده از یک HeatmapLayer برای نشان دادن چگالی یا نشانگرهای خوشه ای در نظر بگیرید تا نشان دهید که بسیاری از نقاط داده با استفاده از یک نماد واحد در هر خوشه قرار دارند. جزئیات بیشتری در آموزش خوشه بندی نشانگر ما وجود دارد.

بهینه سازی نمایش داده شد

BigQuery کل جدول را با هر پرس و جو اسکن می کند. برای بهینه سازی استفاده از سهمیه BigQuery خود ، فقط ستون های مورد نیاز خود را در پرس و جو خود انتخاب کنید.

اگر عرض جغرافیایی و طول جغرافیایی را به عنوان شناور به جای رشته ها ذخیره کنید ، نمایش داده شد.

صادرات نتایج جالب

مثالهای موجود در اینجا نیاز به تأیید اعتبار در برابر جدول BigQuery ، که متناسب با هر مورد استفاده نخواهد بود. هنگامی که برخی از الگوهای جالب را کشف کرده اید ، ممکن است با صادر کردن نتایج از BigQuery و ایجاد یک مجموعه داده استاتیک با استفاده از لایه داده Google Maps ، این موارد را با مخاطبان گسترده تر به اشتراک بگذارید.

در نظر داشته باشید شرایط خدمات پلت فرم Google Maps. برای اطلاعات بیشتر در مورد قیمت گذاری پلتفرم Google Maps ، به اسناد آنلاین مراجعه کنید.

با داده های بیشتر بازی کنید!

تعدادی از مجموعه داده های عمومی در BigQuery وجود دارد که دارای ستون های عرض جغرافیایی و طول جغرافیایی هستند ، به عنوان مثال مجموعه داده های تاکسی NYC از 2009-2016 ، داده های سفر Uber و Lyft NYC و مجموعه داده های GDELT .

15. تبریک می گویم!

ما امیدواریم که این امر به شما کمک کند تا با برخی از نمایش داده های GEO در برابر میزهای BigQuery به سرعت از خواب برخیزید و بتوانید الگوهای خود را کشف کرده و آنها را در نقشه Google تجسم کنید. نقشه برداری مبارک!

بعدش چی؟

اگر می خواهید در مورد پلت فرم Google Maps یا BigQuery اطلاعات بیشتری کسب کنید ، به پیشنهادات زیر نگاهی بیندازید.

برای کسب اطلاعات بیشتر در مورد سرویس انبار داده های بدون سرور Google ، بدون سرور Google ، مشاهده کنید.

نگاهی به راهنمای نحوه ایجاد یک برنامه ساده با استفاده از API BigQuery بیندازید.

برای اطلاعات بیشتر در مورد فعال کردن تعامل کاربر برای ترسیم اشکال در نقشه Google ، به راهنمای توسعه دهنده کتابخانه طراحی مراجعه کنید.

نگاهی به روشهای دیگر برای تجسم داده ها در نقشه Google بیندازید.

برای درک مفاهیم اساسی استفاده از API مشتری برای دسترسی به سایر API های Google ، به راهنمای شروع کار برای JavaScript Client AP I مراجعه کنید.