1. 개요
지도는 어떤 식으로든 위치와 관련된 데이터 세트의 패턴을 시각화할 때 매우 강력한 도구가 될 수 있습니다. 이 관계는 장소 이름, 특정 위도 및 경도 값 또는 인구 조사 지역이나 우편번호와 같은 특정 경계가 있는 지역의 이름일 수 있습니다.
이러한 데이터 세트가 매우 커지면 기존 도구를 사용하여 쿼리하고 시각화하기 어려울 수 있습니다. Google BigQuery를 사용하여 데이터를 쿼리하고 Google Maps API를 사용하여 쿼리를 구성하고 출력을 시각화하면 설정이나 코딩을 거의 하지 않고도, 대규모 데이터 세트를 저장하는 시스템을 관리하지 않고도 데이터의 지리적 패턴을 빠르게 탐색할 수 있습니다.
빌드할 항목
이 Codelab에서는 BigQuery를 사용하여 매우 큰 공개 데이터 세트에 위치 기반 통계를 제공하는 방법을 보여주는 쿼리를 작성하고 실행합니다. 또한 Google Maps Platform JavaScript API를 사용하여 지도를 로드한 다음 JavaScript용 Google API 클라이언트 라이브러리 및 BigQuery API를 사용하여 동일한 매우 큰 공개 데이터 세트에 대해 공간 쿼리를 실행하고 시각화하는 웹페이지를 빌드합니다.
학습할 내용
- SQL 쿼리, 사용자 정의 함수 , BigQuery API를 사용하여 BigQuery에서 페타바이트 규모의 위치 데이터 세트를 몇 초 만에 쿼리하는 방법
- Google Maps Platform을 사용하여 웹페이지에 Google 지도를 추가하고 사용자가 지도에 도형을 그릴 수 있도록 하는 방법
- 아래 예시 이미지와 같이 엠파이어 스테이트 빌딩 주변 블록에서 시작된 여정의 2016년 택시 하차 위치 밀도를 보여주는 Google 지도에서 대규모 데이터 세트에 대한 쿼리를 시각화하는 방법
필요한 항목
- HTML, CSS, JavaScript, SQL, Chrome DevTools에 대한 기본 지식
- 최신 버전의 Chrome, Firefox, Safari, Edge와 같은 최신 웹브라우저
- 원하는 텍스트 편집기 또는 IDE
기술
BigQuery
BigQuery는 매우 큰 데이터 세트를 위한 Google의 데이터 분석 서비스입니다. RESTful API가 있으며 SQL로 작성된 쿼리를 지원합니다. 위도 및 경도 값이 있는 데이터가 있는 경우 위치별로 데이터를 쿼리하는 데 사용할 수 있습니다. 서버나 데이터베이스 인프라를 관리하지 않고도 매우 큰 데이터 세트를 시각적으로 탐색하여 패턴을 살펴볼 수 있다는 장점이 있습니다. BigQuery의 대규모 확장성과 관리형 인프라를 사용하면 테이블이 얼마나 커지든 몇 초 만에 질문에 대한 답변을 얻을 수 있습니다.
Google Maps Platform
Google Maps Platform은 Google의 지도, 장소, 경로 데이터에 대한 프로그래매틱 액세스를 제공합니다. 현재 2백만 개가 넘는 웹사이트와 앱에서 이를 사용하여 사용자에게 삽입된 지도와 위치 기반 쿼리를 제공하고 있습니다.
Google Maps Platform JavaScript API 그리기 레이어를 사용하면 지도에 도형을 그릴 수 있습니다. 이러한 값은 열에 위도 및 경도 값이 저장된 BigQuery 테이블에 대해 쿼리를 실행하기 위한 입력으로 변환할 수 있습니다.
시작하려면 BigQuery 및 Maps API가 사용 설정된 Google Cloud Platform 프로젝트가 필요합니다.
2. 설정하기
Google 계정
아직 Google 계정(Gmail 또는 Google Apps)이 없으면 계정을 만들어야 합니다.
프로젝트 만들기
Google Cloud Platform 콘솔 ( console.cloud.google.com)에 로그인하고 새 프로젝트를 만듭니다. 화면 상단에 프로젝트 드롭다운 메뉴가 있습니다.
이 프로젝트 드롭다운 메뉴를 클릭하면 새 프로젝트를 만들 수 있는 메뉴 항목이 표시됩니다.
'프로젝트의 새 이름을 입력하세요'라는 상자에 새 프로젝트의 이름을 입력합니다(예: 'BigQuery Codelab').
프로젝트 ID가 생성됩니다. 프로젝트 ID는 모든 Google Cloud 프로젝트에서 고유한 이름입니다. 나중에 사용할 수 있도록 프로젝트 ID를 기억해 둡니다. 위의 이름은 이미 사용되었으므로 사용할 수 없습니다. 이 Codelab에서 YOUR_PROJECT_ID가 표시되는 곳에 자신의 프로젝트 ID를 삽입합니다.
결제 사용 설정
BigQuery에 가입하려면 이전 단계에서 선택하거나 만든 프로젝트를 사용하세요. 이 프로젝트에 결제가 사용 설정되어 있어야 합니다. 결제가 사용 설정되면 BigQuery API를 사용 설정할 수 있습니다.
결제 사용 설정 방법은 새 프로젝트를 만들거나 기존 프로젝트의 결제를 다시 사용 설정하는지에 따라 다릅니다.
Google에서는 최대 $300 상당의 Google Cloud Platform 사용량에 대해 12개월 무료 체험을 제공하며, 이 Codelab에 사용할 수 있습니다. 자세한 내용은 https://cloud.google.com/free/에서 확인하세요.
신규 프로젝트
새 프로젝트를 만들 때는 프로젝트에 연결할 결제 계정을 선택하라는 메시지가 표시됩니다. 결제 계정이 하나만 있으면 계정이 프로젝트에 자동으로 연결됩니다.
결제 계정이 없으면 계정을 만들고 프로젝트에 결제를 사용 설정한 후에야 여러 Google Cloud Platform 기능을 사용할 수 있습니다. 새 결제 계정을 만들고 프로젝트에 결제를 사용 설정하려면 새 결제 계정 만들기의 안내를 따르세요.
기존 프로젝트
일시적으로 결제를 사용 중지한 프로젝트가 있는 경우 결제를 다시 사용 설정할 수 있습니다.
- Cloud Platform 콘솔로 이동합니다.
- 프로젝트 목록에서 결제를 다시 사용 설정하려는 프로젝트를 선택합니다.
- 콘솔 왼쪽 메뉴를 열고 결제
를 선택합니다. 결제 계정을 선택하라는 메시지가 표시됩니다.
- 계정 설정을 클릭합니다.
새 결제 계정 만들기
새 결제 계정을 만드는 방법은 다음과 같습니다.
- Cloud Platform Console로 이동하여 로그인하거나, 아직 계정이 없으면 가입합니다.
- 콘솔 왼쪽 메뉴를 열고 결제 를 선택합니다.
- 새 결제 계정 버튼을 클릭합니다. (이 계정이 첫 번째 결제 계정이 아닌 경우, 먼저 페이지 위쪽에 있는 기존 결제 계정의 이름을 클릭한 후 결제 계정 관리를 클릭하여 결제 계정 목록을 열어야 합니다.)
- 결제 계정의 이름과 결제 정보를 입력합니다. 표시되는 옵션은 청구서 수신 주소의 국가에 따라 다릅니다. 미국 계정의 경우 계정을 만든 후에는 세금 상태를 변경할 수 없습니다.
- 제출 및 결제 사용 설정을 클릭합니다.
기본적으로 결제 계정을 만든 사람이 계정의 결제 관리자입니다.
은행 계좌 인증 및 백업 결제 수단 추가에 대한 자세한 내용은 결제 수단 추가, 삭제 또는 업데이트를 참고하세요.
BigQuery API 사용 설정
프로젝트에서 BigQuery API를 사용 설정하려면 콘솔의 BigQuery API 페이지 마켓으로 이동하여 파란색 '사용 설정' 버튼을 클릭합니다.
3. BigQuery에서 위치 데이터 쿼리
BigQuery에 위도, 경도 값으로 저장된 위치 데이터를 쿼리하는 방법에는 세 가지가 있습니다.
- 사각형 쿼리: 관심 영역을 최소 및 최대 위도와 경도 범위 내의 모든 행을 선택하는 쿼리로 지정합니다.
- 반경 쿼리: Haversine 공식과 수학 함수를 사용하여 지구의 모양을 모델링하여 점 주위의 원을 계산하여 관심 영역을 지정합니다.
- 다각형 쿼리: 맞춤 도형을 지정하고 사용자 정의 함수를 사용하여 각 행의 위도와 경도가 도형 내에 있는지 테스트하는 데 필요한 점-다각형 논리를 표현합니다.
시작하려면 Google Cloud Platform 콘솔의 BigQuery 섹션에 있는 쿼리 편집기를 사용하여 NYC 택시 데이터에 대해 다음 쿼리를 실행하세요.
표준 SQL과 Legacy SQL 비교
BigQuery는 Legacy SQL과 표준 SQL이라는 두 가지 버전의 SQL을 지원합니다. 후자는 2011년 ANSI 표준입니다. 이 튜토리얼에서는 표준 준수가 더 우수한 표준 SQL을 사용합니다.
BigQuery 편집기에서 기존 SQL을 실행하려면 다음 단계를 따르세요.
- '더보기' 버튼을 클릭합니다.
- 드롭다운 메뉴에서 '쿼리 설정'을 선택합니다.
- 'SQL 언어'에서 'Legacy' 라디오 버튼을 선택합니다.
- '저장' 버튼을 클릭합니다.
직사각형 쿼리
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
두 쿼리의 결과를 보면 두 지역의 평균 이동 거리, 요금, 팁에 큰 차이가 있음을 알 수 있습니다.
Manhattan
avg_tip | avg_fare | avg_distance | avg_tip_pc | avg_fare_mile |
2.52 | 12.03 | 9.97 | 22.39 | 5.97 |
JFK
avg_tip | avg_fare | avg_distance | avg_tip_pc | avg_fare_mile |
9.22 | 48.49 | 41.19 | 22.48 | 4.36 |
반경 쿼리
약간의 수학 지식이 있다면 SQL에서 반경 쿼리를 쉽게 구성할 수도 있습니다. BigQuery의 Legacy SQL 수학 함수를 사용하면 지구 표면의 원형 영역 또는 구면을 근사하는 Haversine 공식을 사용하여 SQL 쿼리를 구성할 수 있습니다.
다음은 중심이 40.73943, -73.99585
이고 반지름이 0.1km인 원 쿼리의 BigQuery SQL 문의 예입니다.
1도를 나타내는 거리를 근사치로 나타내기 위해 111.045km의 상수 값을 사용합니다.
이는 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
Haversine 공식의 SQL은 복잡해 보이지만 원의 중심 좌표, 반지름, BigQuery의 프로젝트, 데이터 세트, 테이블 이름을 입력하기만 하면 됩니다.
다음은 엠파이어 스테이트 빌딩에서 100m 이내의 픽업에 대한 평균 이동 통계를 계산하는 쿼리의 예입니다. 이 쿼리를 복사하여 BigQuery 웹 콘솔에 붙여넣어 결과를 확인합니다. 위도와 경도를 변경하여 브롱스의 위치와 같은 다른 지역과 비교합니다.
#standardSQL
CREATE TEMPORARY FUNCTION Degrees(radians FLOAT64) RETURNS FLOAT64 AS
(
(radians*180)/(22/7)
);
CREATE TEMPORARY FUNCTION Radians(degrees FLOAT64) AS (
(degrees*(22/7))/180
);
CREATE TEMPORARY FUNCTION DistanceKm(lat FLOAT64, lon FLOAT64, lat1 FLOAT64, lon1 FLOAT64) AS (
Degrees(
ACOS(
COS( Radians(lat1) ) *
COS( Radians(lat) ) *
COS( Radians(lon1 ) -
Radians( lon ) ) +
SIN( Radians(lat1) ) *
SIN( Radians( lat ) )
)
) * 111.045
);
SELECT
ROUND(AVG(tip_amount),2) as avg_tip,
ROUND(AVG(fare_amount),2) as avg_fare,
ROUND(AVG(trip_distance),2) as avg_distance,
ROUND(AVG(tip_proportion), 2) as avg_tip_pc,
ROUND(AVG(fare_per_mile),2) as avg_fare_mile
FROM
-- EMPIRE STATE BLDG 40.748459, -73.985731
-- BRONX 40.895597, -73.856085
(SELECT pickup_latitude, pickup_longitude, tip_amount, fare_amount, trip_distance, tip_amount/fare_amount*100 as tip_proportion, fare_amount / trip_distance as fare_per_mile, DistanceKm(pickup_latitude, pickup_longitude, 40.748459, -73.985731)
FROM `bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2015`
WHERE
DistanceKm(pickup_latitude, pickup_longitude, 40.748459, -73.985731) < 0.1
AND fare_amount > 0 and trip_distance > 0
)
WHERE fare_amount < 100
쿼리 결과는 아래와 같습니다. 평균 팁, 요금, 이동 거리, 요금에 대한 팁의 비율, 주행 거리당 평균 요금에 큰 차이가 있음을 확인할 수 있습니다.
엠파이어 스테이트 빌딩:
avg_tip | avg_fare | avg_distance | avg_tip_pc | avg_fare_mile |
1.17 | 11.08 | 45.28 | 10.53 | 6.42 |
브롱스
avg_tip | avg_fare | avg_distance | avg_tip_pc | avg_fare_mile |
0.52 | 17.63 | 4.75 | 4.74 | 10.9 |
다각형 쿼리
SQL은 직사각형과 원 이외의 임의의 모양을 사용한 쿼리를 지원하지 않습니다. BigQuery에는 기본 도형 데이터 유형이나 공간 색인이 없으므로 다각형 모양을 사용하여 쿼리를 실행하려면 간단한 SQL 쿼리와 다른 접근 방식이 필요합니다. 한 가지 방법은 JavaScript에서 geometry 함수를 정의하고 BigQuery에서 사용자 정의 함수 (UDF)로 실행하는 것입니다.
많은 기하 도형 작업을 JavaScript로 작성할 수 있으므로 위도 및 경도 값이 포함된 BigQuery 테이블에 대해 작업을 쉽게 실행할 수 있습니다. UDF를 통해 맞춤 다각형을 전달하고 각 행에 대해 테스트를 실행하여 위도와 경도가 다각형 내에 있는 행만 반환해야 합니다. BigQuery 참조에서 UDF에 대해 자세히 알아보기
Point In Polygon 알고리즘
JavaScript에서 점이 다각형 내에 있는지 계산하는 방법은 다양합니다. 다음은 광선 추적 알고리즘을 사용하여 무한히 긴 선이 도형의 경계를 교차하는 횟수를 계산하여 점이 다각형 내부에 있는지 외부에 있는지 확인하는 잘 알려진 구현을 C에서 포팅한 것입니다. 코드 몇 줄만 있으면 됩니다.
function pointInPoly(nvert, vertx, verty, testx, testy){
var i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
JavaScript로 포팅
이 알고리즘의 JavaScript 버전은 다음과 같습니다.
/* This function includes a port of C code to calculate point in polygon
* see http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html for license
*/
function pointInPoly(polygon, point){
// Convert a JSON poly into two arrays and a vertex count.
let vertx = [],
verty = [],
nvert = 0,
testx = point[0],
testy = point[1];
for (let coord of polygon){
vertx[nvert] = coord[0];
verty[nvert] = coord[1];
nvert ++;
}
// The rest of this function is the ported implementation.
for (let i = 0, let j = nvert - 1; i < nvert; j = i++) {
if ( ((verty[i] > testy) != (verty[j] > testy)) &&
(testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
BigQuery에서 표준 SQL을 사용하는 경우 UDF 접근 방식에는 단일 문만 필요하지만 UDF는 문에서 임시 함수로 정의해야 합니다. 다음 예를 참고하세요. 아래 SQL 문을 쿼리 편집기 창에 붙여넣습니다.
CREATE TEMPORARY FUNCTION pointInPolygon(latitude FLOAT64, longitude FLOAT64)
RETURNS BOOL LANGUAGE js AS """
let polygon=[[-73.98925602436066,40.743249676056955],[-73.98836016654968,40.74280666503313],[-73.98915946483612,40.741676770346295],[-73.98967981338501,40.74191656974406]];
let vertx = [],
verty = [],
nvert = 0,
testx = longitude,
testy = latitude,
c = false,
j = nvert - 1;
for (let coord of polygon){
vertx[nvert] = coord[0];
verty[nvert] = coord[1];
nvert ++;
}
// The rest of this function is the ported implementation.
for (let i = 0; i < nvert; j = i++) {
if ( ((verty[i] > testy) != (verty[j] > testy)) &&
(testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]) ) {
c = !c;
}
}
return c;
""";
SELECT pickup_latitude, pickup_longitude, dropoff_latitude, dropoff_longitude, pickup_datetime
FROM `bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2016`
WHERE pointInPolygon(pickup_latitude, pickup_longitude) = TRUE
AND (pickup_datetime BETWEEN CAST("2016-01-01 00:00:01" AS DATETIME) AND CAST("2016-02-28 23:59:59" AS DATETIME))
LIMIT 1000
축하합니다.
이제 BigQuery를 사용하여 세 가지 유형의 공간 쿼리를 실행했습니다. 보시다시피 위치는 이 데이터 세트에 대한 쿼리의 결과 데이터에 큰 영향을 미치지만, 쿼리를 실행할 위치를 추측하지 않는 한 SQL 쿼리만으로는 임시로 공간 패턴을 파악하기 어렵습니다.
지도에서 데이터를 시각화하고 관심 영역을 임의로 정의하여 데이터를 탐색할 수 있다면 얼마나 좋을까요? Google 지도 API를 사용하면 이 작업을 할 수 있습니다. 먼저 지도 API를 사용 설정하고, 로컬 머신에서 실행되는 간단한 웹페이지를 설정하고, BigQuery API를 사용하여 웹페이지에서 쿼리를 전송해야 합니다.
4. Google 지도 API 작업
간단한 공간 쿼리를 실행했으므로 다음 단계는 출력을 시각화하여 패턴을 확인하는 것입니다. 이렇게 하려면 지도 API를 사용 설정하고, 지도에서 BigQuery로 쿼리를 전송한 다음 지도에 결과를 그리는 웹페이지를 빌드합니다.
Maps JavaScript API 사용 설정
이 Codelab에서는 프로젝트에서 Google Maps Platform의 Maps JavaScript API를 사용 설정해야 합니다. 이 작업을 수행하려면 다음과 같이 하세요.
- Google Cloud Platform 콘솔에서 Marketplace로 이동합니다.
- 마켓에서 'Maps JavaScript API'를 검색합니다.
- 검색 결과에서 Maps JavaScript API 타일을 클릭합니다.
- '사용' 버튼을 클릭합니다.
API 키 생성
Google Maps Platform에 요청하려면 API 키를 생성하여 모든 요청과 함께 전송해야 합니다. API 키를 생성하려면 다음 단계를 따르세요.
- Google Cloud Platform 콘솔에서 햄버거 메뉴를 클릭하여 왼쪽 탐색 메뉴를 엽니다.
- 'API 및 서비스' > '사용자 인증 정보'를 선택합니다.
- '사용자 인증 정보 만들기' 버튼을 클릭한 다음 'API 키'를 선택합니다.
- 새 API 키 복사
코드를 다운로드하고 웹 서버 설정
다음 버튼을 클릭하여 이 Codelab의 모든 코드를 다운로드합니다.
다운로드한 ZIP 파일의 압축을 해제합니다. 그러면 이 Codelab의 단계별로 폴더 하나씩 포함된 루트 폴더 (bigquery
)와 필요한 모든 리소스가 압축 해제됩니다.
stepN
폴더에는 Codelab의 각 단계에서 도달하고자 하는 최종 상태가 포함되어 있으며, 참고용으로 제공됩니다. 모든 코딩 작업은 work
디렉터리에서 진행합니다.
로컬 웹 서버 설정
자체 웹 서버를 사용할 수 있지만 이 Codelab은 Chrome 웹 서버와 잘 작동하도록 설계되었습니다. 아직 앱을 설치하지 않았다면 Chrome 웹 스토어에서 설치할 수 있습니다.
설치가 완료되면 앱을 엽니다. Chrome에서는 다음과 같이 할 수 있습니다.
- Chrome 열기
- 상단의 주소 표시줄에 chrome://apps를 입력합니다.
- Enter 키를 누르세요.
- 열린 창에서 웹 서버 아이콘을 클릭합니다. 앱을 마우스 오른쪽 버튼으로 클릭하여 일반 탭, 고정 탭, 전체 화면 또는 새 창에서 열 수도 있습니다.
그다음 이 대화상자가 표시되면 로컬 웹 서버를 구성할 수 있습니다.
- '폴더 선택'을 클릭하고 코드랩 샘플 파일을 다운로드한 위치를 선택합니다.
- '옵션' 섹션에서 'index.html 자동 표시' 옆에 있는 체크박스를 선택합니다.
- '웹 서버: 시작됨'이라고 표시된 전환 버튼을 왼쪽으로 슬라이드한 다음 다시 오른쪽으로 슬라이드하여 웹 서버를 중지한 후 다시 시작합니다.
5. 지도 및 그리기 도구 로드
기본 지도 페이지 만들기
Maps JavaScript API와 몇 줄의 JavaScript를 사용하여 Google 지도를 로드하는 간단한 HTML 페이지로 시작합니다. Google Maps Platform의 간단한 지도 샘플의 코드를 시작점으로 삼는 것이 좋습니다. 여기에서 복사하여 원하는 텍스트 편집기나 IDE에 붙여넣거나 다운로드한 저장소에서 index.html
을 열어 찾을 수 있습니다.
index.html
을 저장소의 로컬 복사본에 있는work
폴더에 복사합니다.- 저장소의 로컬 복사본에 있는 work/ 폴더에 img/ 폴더를 복사합니다.
- 텍스트 편집기 또는 IDE에서 work/
index.html
를 엽니다. YOUR_API_KEY
를 이전에 만든 API 키로 바꿉니다.
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"
async defer></script>
- 브라우저에서
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>
그런 다음 브라우저에서 지도를 새로고침하여 결과를 확인합니다.
그리기 및 시각화 라이브러리 로드
지도에 그리기 기능을 추가하려면 Google Maps Platform에 그리기 라이브러리를 사용 설정하도록 지시하는 선택적 매개변수를 추가하여 Maps JavaScript API를 로드하는 스크립트를 변경합니다.
이 Codelab에서는 HeatmapLayer
도 사용하므로 시각화 라이브러리를 요청하도록 스크립트도 업데이트합니다. 이렇게 하려면 libraries
매개변수를 추가하고 visualization
및 drawing
라이브러리를 쉼표로 구분된 값으로 지정합니다(예: libraries=
visualization,drawing
).
예를 들면 다음과 같습니다.
<script src='http://maps.googleapis.com/maps/api/js?libraries=visualization,drawing&callback=initMap&key=YOUR_API_KEY' async defer></script>
DrawingManager 추가
사용자가 그린 도형을 쿼리의 입력으로 사용하려면 Circle
, Rectangle
, Polygon
도구를 사용 설정하여 DrawingManager
를 지도에 추가합니다.
DrawingManager
설정 코드를 모두 새 함수에 넣는 것이 좋습니다. index.html 사본에서 다음을 실행하세요.
- 다음 코드를 사용하여
DrawingManager
를 만들고 페이지의 지도 객체를 참조하도록map
속성을 설정하는setUpDrawingTools()
함수를 추가합니다.
google.maps.drawing.DrawingManager(options)
에 전달된 옵션은 그려진 도형의 기본 도형 그리기 유형과 표시 옵션을 설정합니다. 쿼리로 전송할 지도 영역을 선택하는 경우 도형의 불투명도는 0이어야 합니다. 사용 가능한 옵션에 대한 자세한 내용은 DrawingManager 옵션을 참고하세요.
function setUpDrawingTools() {
// Initialize drawing manager
drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.CIRCLE,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_LEFT,
drawingModes: [
google.maps.drawing.OverlayType.CIRCLE,
google.maps.drawing.OverlayType.POLYGON,
google.maps.drawing.OverlayType.RECTANGLE
]
},
circleOptions: {
fillOpacity: 0
},
polygonOptions: {
fillOpacity: 0
},
rectangleOptions: {
fillOpacity: 0
}
});
drawingManager.setMap(map);
}
- 지도 객체가 생성된 후
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();
}
- index.html을 새로고침하고 그리기 도구가 표시되는지 확인합니다. 또한 원, 직사각형, 다각형을 그릴 수 있는지 확인합니다.
클릭하고 드래그하여 원과 사각형을 그릴 수 있지만 다각형은 각 꼭짓점을 클릭하고 모양을 완성하려면 더블클릭해야 합니다.
그리기 이벤트 처리
사용자가 도형 그리기를 완료할 때 발생하는 이벤트를 처리하는 코드가 필요합니다. SQL 쿼리를 구성하는 데 그려진 도형의 좌표가 필요한 것과 마찬가지입니다.
이 코드는 나중에 추가할 예정이지만 지금은 rectanglecomplete
, circlecomplete
, polygoncomplete
이벤트를 처리하기 위해 빈 이벤트 핸들러 3개를 스텁으로 만듭니다. 이 단계에서 핸들러는 코드를 실행하지 않아도 됩니다.
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 클라이언트 API를 사용하면 요청을 빌드하고, 응답을 파싱하고, 인증을 처리하는 데 필요한 상용구 코드를 많이 작성하지 않아도 됩니다. 브라우저 기반 애플리케이션을 개발할 것이므로 이 Codelab에서는 JavaScript용 Google API 클라이언트 라이브러리를 통해 BigQuery API를 사용합니다.
다음으로 웹페이지에서 이 API를 로드하고 BigQuery와 상호작용하는 데 사용할 코드를 추가합니다.
JavaScript용 Google 클라이언트 API 추가
JavaScript용 Google 클라이언트 API를 사용하여 BigQuery에 대해 쿼리를 실행합니다. index.html
사본 (work
폴더에 있음)에서 다음과 같은 <script>
태그를 사용하여 API를 로드합니다. Maps API를 로드하는 <script>
태그 바로 아래에 태그를 배치합니다.
<script src='https://apis.google.com/js/client.js'></script>
Google 클라이언트 API를 로드한 후 사용자가 BigQuery의 데이터에 액세스하도록 승인합니다. 이를 위해 OAuth 2.0을 사용할 수 있습니다. 먼저 Google Cloud 콘솔 프로젝트에서 사용자 인증 정보를 설정해야 합니다.
OAuth 2.0 사용자 인증 정보 만들기
- Google Cloud 콘솔의 탐색 메뉴에서 API 및 서비스 > 사용자 인증 정보를 선택합니다.
인증 정보를 설정하려면 애플리케이션의 최종 사용자가 애플리케이션이 사용자를 대신하여 BigQuery 데이터에 액세스하도록 승인할 때 표시되는 승인 화면에 대한 구성을 추가해야 합니다.
이렇게 하려면 OAuth 동의 화면 탭을 클릭합니다. 2. 이 토큰의 범위에 BigQuery API를 추가해야 합니다. Google API 범위 섹션에서 범위 추가 버튼을 클릭합니다. 3. 목록에서 ../auth/bigquery
범위가 있는 BigQuery API 항목 옆의 체크박스를 선택합니다. 4. 추가를 클릭합니다. 5. '애플리케이션 이름' 필드에 이름을 입력합니다. 6. 저장을 클릭하여 설정을 저장합니다. 7. 다음으로 OAuth 클라이언트 ID를 만듭니다. 이렇게 하려면 사용자 인증 정보 만들기를 클릭합니다.
- 드롭다운 메뉴에서 OAuth 클라이언트 ID를 클릭합니다.
- 애플리케이션 유형에서 웹 애플리케이션을 선택합니다.
- '애플리케이션 이름' 필드에 프로젝트 이름을 입력합니다. 예: 'BigQuery 및 지도'
- 제한의 승인된 JavaScript 원본 필드에 포트 번호를 포함한 localhost의 URL을 입력합니다. 예를 들면
http://localhost:8887
입니다.
- 만들기 버튼을 클릭합니다.
클라이언트 ID와 클라이언트 보안 비밀번호가 팝업으로 표시됩니다. BigQuery에 대해 인증을 수행하려면 클라이언트 ID가 필요합니다. 이를 복사하여 work/index.html
에 clientId
이라는 새 전역 JavaScript 변수로 붙여넣습니다.
let clientId = 'YOUR_CLIENT_ID';
7. 승인 및 초기화
지도를 초기화하기 전에 웹페이지에서 사용자가 BigQuery에 액세스할 수 있도록 승인해야 합니다. 이 예에서는 JavaScript 클라이언트 API 문서의 승인 섹션에 설명된 대로 OAuth 2.0을 사용합니다. OAuth 클라이언트 ID와 프로젝트 ID를 사용하여 쿼리를 전송해야 합니다.
웹페이지에 Google 클라이언트 API가 로드되면 다음 단계를 실행해야 합니다.
- 사용자를 승인합니다.
- 승인된 경우 BigQuery API를 로드합니다.
- 지도를 로드하고 초기화합니다.
완성된 HTML 페이지의 모양은 step3/map.html을 참고하세요.
사용자 승인
애플리케이션의 최종 사용자는 애플리케이션이 자신을 대신하여 BigQuery의 데이터에 액세스하도록 승인해야 합니다. 이를 위해 JavaScript용 Google 클라이언트 API가 OAuth 로직을 처리합니다.
실제 애플리케이션에서는 승인 단계를 통합하는 방법이 다양합니다.
예를 들어 버튼과 같은 UI 요소에서 authorize()
를 호출하거나 페이지가 로드될 때 호출할 수 있습니다. 여기서는 gapi.load()
메서드에서 콜백 함수를 사용하여 JavaScript용 Google 클라이언트 API가 로드된 후 사용자를 승인하도록 선택했습니다.
<script>
태그 바로 뒤에 JavaScript용 Google 클라이언트 API를 로드하여 클라이언트 라이브러리와 인증 모듈을 모두 로드하는 코드를 작성하여 사용자를 바로 인증할 수 있습니다.
<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
함수도 추가합니다.
함수에 전달된 authResult
객체가 있고 객체의 error
속성 값이 false
인 경우 loadApi()
을 호출하는 로직을 handleAuthResult()
함수에 추가합니다.
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');
}
지도 로드
마지막 단계는 지도를 초기화하는 것입니다. 이렇게 하려면 논리의 순서를 약간 변경해야 합니다. 현재는 Maps API JavaScript가 로드될 때 초기화됩니다.
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를 사용하여 쿼리를 전송하는 JavaScript 함수와 쿼리할 테이블이 포함된 BigQuery 데이터 세트 및 프로젝트의 값을 저장하는 변수, 요금이 청구될 프로젝트 ID를 work/index.html
에 추가합니다.
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
메서드를 수정합니다. 작업 ID를 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 호출을 사용하여 쿼리 결과를 가져옵니다. jobId
매개변수를 허용하는 getQueryResults()
라는 함수를 페이지에 추가합니다.
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의 데이터에 대해 공간 쿼리를 실행하는 방법에는 세 가지가 있습니다.
- 직사각형 (경계 상자라고도 함)으로 선택
- 반경별 선택을 선택하고
- 강력한 사용자 정의 함수 기능을 사용하세요.
BigQuery legacy SQL 참조의 수학 함수 섹션에 있는 '고급 예'에는 경계 상자 및 반경 쿼리의 예가 있습니다.
경계 상자 및 반경 쿼리의 경우 BigQuery API query
메서드를 호출하면 됩니다. 각 쿼리의 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
입니다.
NYC 택시 이동에는 다양한 테이블이 있습니다. 이를 확인하려면 BigQuery 웹 콘솔로 이동하여 '공개 데이터 세트' 메뉴 항목을 펼칩니다. new_york
라는 데이터 세트를 찾아 펼쳐 테이블을 확인합니다. 옐로캡 택시 운행 테이블(bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2016
)을 선택합니다.
프로젝트 ID 지정
API 호출에서 청구 목적으로 Google Cloud Platform 프로젝트의 이름을 지정해야 합니다. 이 Codelab에서는 테이블이 포함된 프로젝트와 동일한 프로젝트가 아닙니다. 데이터를 업로드하여 자체 프로젝트에서 만든 테이블을 사용하고 있다면 이 프로젝트 ID는 SQL 문에 있는 ID와 동일합니다.
쿼리하는 테이블이 포함된 공개 데이터 세트 프로젝트에 대한 참조와 테이블 이름 및 데이터 세트 이름을 보유하도록 코드에 JavaScript 변수를 추가합니다. 자체 결제 프로젝트 ID를 참조하는 별도의 변수도 필요합니다.
index.html 사본에 billingProjectId, publicProjectId, datasetId
및 tableName
이라는 전역 JavaScript 변수를 추가합니다.
BigQuery 공개 데이터 세트 프로젝트의 세부정보를 사용하여 변수 'publicProjectId'
, 'datasetId'
, 'tableName'
를 초기화합니다. billingProjectId
를 자체 프로젝트 ID('설정'에서 만든 ID)로 초기화합니다.
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 쿼리와 지도에서 위치를 집계하는 방법은 다양하며 쿼리에서 반환되는 결과를 제한할 수 있습니다.
이 단계의 전체 코드는 step5/map.html에서 확인할 수 있습니다.
이 Codelab에서 웹페이지로 전송되는 데이터의 양을 적절한 크기로 유지하려면 rectangleSQL()
함수를 수정하여 응답을 10, 000개 행으로 제한하는 문을 추가하세요. 아래 예에서는 모든 쿼리 함수가 동일한 값을 사용할 수 있도록 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
배열을 히트맵을 생성하는 doHeatMap()
라는 새 JavaScript 함수에 전달합니다.
각 행에는 열 배열인 f
라는 속성이 있습니다. 각 열에는 값이 포함된 v
속성이 있습니다.
코드는 각 행의 열을 반복하여 값을 추출해야 합니다.
SQL 쿼리에서 택시 승차 지점의 위도와 경도 값만 요청했으므로 응답에는 두 개의 열만 있습니다.
위치 배열을 히트맵 레이어에 할당한 후에는 히트맵 레이어에서 setMap()
를 호출해야 합니다. 이렇게 하면 지도에 표시됩니다.
예를 들면 다음과 같습니다.
function getQueryResults(jobId){
let request = gapi.client.bigquery.jobs.getQueryResults({
'projectId': billingProjectId,
'jobId': jobId
});
request.execute(response => doHeatMap(response.result.rows))
}
let heatmap;
function doHeatMap(rows){
let heatmapData = [];
if (heatmap != null){
heatmap.setMap(null);
}
for (let i = 0; i < rows.length; i++) {
let f = rows[i].f;
let coords = { lat: parseFloat(f[0].v), lng: parseFloat(f[1].v) };
let latLng = new google.maps.LatLng(coords);
heatmapData.push(latLng);
}
heatmap = new google.maps.visualization.HeatmapLayer({
data: heatmapData
});
heatmap.setMap(map);
}
이제 다음 작업을 할 수 있습니다.
- 페이지를 열고 BigQuery에 대해 승인
- 뉴욕의 아무 곳에나 사각형을 그립니다.
- 결과 쿼리 결과가 히트맵으로 시각화됩니다.
다음은 2016년 NYC Yellow Taxi 데이터에 대한 사각형 쿼리의 결과를 히트맵으로 그린 예입니다. 다음은 7월 토요일에 엠파이어 스테이트 빌딩 주변에서 이루어진 픽업의 분포를 보여줍니다.
11. 점을 중심으로 한 반경으로 쿼리
반경 쿼리는 매우 유사합니다. BigQuery의 기존 SQL 수학 함수를 사용하면 지구 표면의 원형 영역을 근사하는 Haversine 공식을 사용하여 SQL 쿼리를 구성할 수 있습니다.
사각형에 동일한 기법을 사용하여 OverlayComplete
이벤트를 처리하여 사용자가 그린 원의 중심과 반지름을 가져오고 동일한 방식으로 쿼리의 SQL을 빌드할 수 있습니다.
이 단계의 작업 코드 예는 코드 저장소에 step6/map.html로 포함되어 있습니다.
drawingManager.addListener('circlecomplete', circle => circleQuery(circle));
index.html 사본에 circleQuery()
및 haversineSQL()
이라는 두 개의 빈 함수를 추가합니다.
그런 다음 중심과 반지름을 circleQuery().
이라는 새 함수에 전달하는 circlecomplete
이벤트 핸들러를 추가합니다.
circleQuery()
함수는 haversineSQL()
를 호출하여 쿼리의 SQL을 구성한 다음 다음 예시 코드에 따라 sendQuery()
함수를 호출하여 쿼리를 전송합니다.
function circleQuery(circle){
let queryString = haversineSQL(circle.getCenter(), circle.radius);
sendQuery(queryString);
}
// Calculate a circular area on the surface of a sphere based on a center and radius.
function haversineSQL(center, radius){
let queryString;
let centerLat = center.lat();
let centerLng = center.lng();
let kmPerDegree = 111.045;
queryString = 'CREATE TEMPORARY FUNCTION Degrees(radians FLOAT64) RETURNS FLOAT64 LANGUAGE js AS ';
queryString += '""" ';
queryString += 'return (radians*180)/(22/7);';
queryString += '"""; ';
queryString += 'CREATE TEMPORARY FUNCTION Radians(degrees FLOAT64) RETURNS FLOAT64 LANGUAGE js AS';
queryString += '""" ';
queryString += 'return (degrees*(22/7))/180;';
queryString += '"""; ';
queryString += 'SELECT pickup_latitude, pickup_longitude '
queryString += 'FROM `' + publicProjectId +'.' + datasetId + '.' + tableName + '` ';
queryString += 'WHERE '
queryString += '(' + kmPerDegree + ' * DEGREES( ACOS( COS( RADIANS('
queryString += centerLat;
queryString += ') ) * COS( RADIANS( pickup_latitude ) ) * COS( RADIANS( ' + centerLng + ' ) - RADIANS('
queryString += ' pickup_longitude ';
queryString += ') ) + SIN( RADIANS('
queryString += centerLat;
queryString += ') ) * SIN( RADIANS( pickup_latitude ) ) ) ) ) ';
queryString += ' < ' + radius/1000;
queryString += ' LIMIT ' + recordLimit;
return queryString;
}
사용해 보기
위 코드를 추가하고 '원' 도구를 사용하여 지도 영역을 선택해 보세요. 결과는 다음과 같이 표시됩니다.
12. 임의의 도형 쿼리
요약: SQL은 직사각형과 원 이외의 임의의 모양을 사용한 쿼리를 지원하지 않습니다. BigQuery에는 기본 도형 데이터 유형이 없으므로 다각형 모양을 사용하여 쿼리를 실행하려면 간단한 SQL 쿼리와 다른 접근 방식이 필요합니다.
이를 위해 사용할 수 있는 매우 강력한 BigQuery 기능 중 하나는 사용자 정의 함수 (UDF)입니다. UDF는 SQL 쿼리 내에서 JavaScript 코드를 실행합니다.
이 단계의 작업 코드는 step7/map.html에 있습니다.
BigQuery API의 UDF
UDF에 대한 BigQuery API 접근 방식은 웹 콘솔과 약간 다릅니다. jobs.insert method
를 호출해야 합니다.
API를 통한 표준 SQL 쿼리의 경우 사용자 정의 함수를 사용하는 데 SQL 문 하나만 필요합니다. useLegacySql
의 값은 false
로 설정해야 합니다. 아래 JavaScript 예시에서는 새 작업을 삽입하는 요청 객체를 만드는 함수를 보여줍니다. 이 경우 사용자 정의 함수가 있는 쿼리입니다.
이 접근 방식의 실제 적용된 예는 step7/map.html에 있습니다.
function polygonQuery(polygon) {
let request = gapi.client.bigquery.jobs.insert({
'projectId' : billingProjectId,
'resource' : {
'configuration':
{
'query':
{
'query': polygonSql(polygon),
'useLegacySql': false
}
}
}
});
request.execute(response => checkJobStatus(response.jobReference.jobId));
}
SQL 쿼리는 다음과 같이 구성됩니다.
function polygonSql(poly){
let queryString = 'CREATE TEMPORARY FUNCTION pointInPolygon(latitude FLOAT64, longitude FLOAT64) ';
queryString += 'RETURNS BOOL LANGUAGE js AS """ ';
queryString += 'var polygon=' + JSON.stringify(poly) + ';';
queryString += 'var vertx = [];';
queryString += 'var verty = [];';
queryString += 'var nvert = 0;';
queryString += 'var testx = longitude;';
queryString += 'var testy = latitude;';
queryString += 'for(coord in polygon){';
queryString += ' vertx[nvert] = polygon[coord][0];';
queryString += ' verty[nvert] = polygon[coord][1];';
queryString += ' nvert ++;';
queryString += '}';
queryString += 'var i, j, c = 0;';
queryString += 'for (i = 0, j = nvert-1; i < nvert; j = i++) {';
queryString += ' if ( ((verty[i]>testy) != (verty[j]>testy)) &&(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ){';
queryString += ' c = !c;';
queryString += ' }';
queryString += '}';
queryString += 'return c;';
queryString += '"""; ';
queryString += 'SELECT pickup_latitude, pickup_longitude, dropoff_latitude, dropoff_longitude, pickup_datetime ';
queryString += 'FROM `' + publicProjectId + '.' + datasetId + '.' + tableName + '` ';
queryString += 'WHERE pointInPolygon(pickup_latitude, pickup_longitude) = TRUE ';
queryString += 'LIMIT ' + recordLimit;
return queryString;
}
여기에는 두 가지 사항이 있습니다. 먼저 코드는 지정된 점이 다각형 내부에 있는지 확인하는 JavaScript 코드를 캡슐화하는 CREATE TEMPORARY FUNCTION
문을 만듭니다. 다각형 좌표는 JSON.stringify(poly)
메서드 호출을 사용하여 삽입됩니다. 이 메서드는 x,y 좌표 쌍의 JavaScript 배열을 문자열로 변환합니다. 다각형 객체는 SQL을 빌드하는 함수에 인수로 전달됩니다.
둘째, 코드는 기본 SQL SELECT
문을 빌드합니다. 이 예시에서는 WHERE
표현식에서 UDF가 호출됩니다.
Maps API와 통합
Maps API 그리기 라이브러리와 함께 사용하려면 사용자가 그린 다각형을 저장하고 SQL 쿼리의 UDF 부분에 전달해야 합니다.
먼저 polygoncomplete
그리기 이벤트를 처리하여 모양의 좌표를 경도 및 위도 쌍의 배열로 가져와야 합니다.
drawingManager.addListener('polygoncomplete', polygon => {
let path = polygon.getPaths().getAt(0);
let queryPolygon = path.map(element => {
return [element.lng(), element.lat()];
});
polygonQuery(queryPolygon);
});
그러면 polygonQuery
함수가 UDF JavaScript 함수를 문자열로 구성할 수 있을 뿐만 아니라 UDF 함수를 호출할 SQL 문도 구성할 수 있습니다.
작동하는 예는 step7/map.html을 참고하세요.
출력 예
다음은 자유형 다각형을 사용하여 BigQuery의 2016년 NYC TLC 노란색 택시 데이터에서 승차 위치를 쿼리한 결과의 예입니다. 선택한 데이터는 히트맵으로 그려집니다.
13. 더 나아가기
이 Codelab을 확장하여 데이터의 다른 측면을 살펴볼 수 있는 몇 가지 제안사항이 있습니다. 코드 저장소의 step8/map.html에서 이러한 아이디어의 작동하는 예시를 확인할 수 있습니다.
하차 매핑
지금까지는 픽업 위치만 매핑했습니다. dropoff_latitude
및 dropoff_longitude
열을 요청하고 히트맵 코드를 수정하여 대신 이러한 열을 표시하면 특정 위치에서 시작된 택시 여정의 목적지를 확인할 수 있습니다.
예를 들어 엠파이어 스테이트 빌딩 주변에서 택시를 요청할 때 택시가 사람들을 어디에 내려주는지 살펴보겠습니다.
polygonSql()
의 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;
}
그러면 doHeatMap
함수가 대신 드롭오프 값을 사용할 수 있습니다. 결과 객체에는 배열에서 이러한 열의 위치를 찾기 위해 검사할 수 있는 스키마가 있습니다. 이 경우 색인 위치는 2와 3이 됩니다. 이러한 색인은 변수에서 읽어 코드를 더 쉽게 관리할 수 있습니다. 히트맵의 maxIntensity
은 최대 픽셀당 20개의 이탈 밀도를 표시하도록 설정됩니다.
히트맵 데이터에 사용할 열을 변경할 수 있도록 변수를 추가합니다.
// Show query results as a Heatmap.
function doHeatMap(rows){
let latCol = 2;
let lngCol = 3;
let heatmapData = [];
if (heatmap!=null){
heatmap.setMap(null);
}
for (let i = 0; i < rows.length; i++) {
let f = rows[i].f;
let coords = { lat: parseFloat(f[latCol].v), lng: parseFloat(f[lngCol].v) };
let latLng = new google.maps.LatLng(coords);
heatmapData.push(latLng);
}
heatmap = new google.maps.visualization.HeatmapLayer({
data: heatmapData,
maxIntensity: 20
});
heatmap.setMap(map);
}
다음은 2016년 엠파이어 스테이트 빌딩 주변에서 바로 이루어진 모든 하차의 분포를 보여주는 히트맵입니다. 미드타운의 목적지가 특히 타임스 스퀘어 주변과 23번가와 14번가 사이의 5번가를 따라 많이 분포 (빨간색 블롭)되어 있습니다. 이 확대/축소 수준에서는 라과르디아 공항, JFK 공항, 세계 무역 센터, 배터리 파크와 같은 고밀도 위치가 표시되지 않습니다.
기본 지도 스타일 지정
Maps JavaScript API를 사용하여 Google 지도를 만들 때 JSON 객체를 사용하여 지도 스타일을 설정할 수 있습니다. 데이터 시각화의 경우 지도에서 색상을 음소거하는 것이 유용할 수 있습니다. mapstyle.withgoogle.com에서 Google 지도 API 스타일 마법사를 사용하여 지도 스타일을 만들고 사용해 볼 수 있습니다.
지도 객체를 초기화할 때 또는 그 이후 언제든지 지도 스타일을 설정할 수 있습니다. 다음은 initMap()
함수에 맞춤 스타일을 추가하는 방법입니다.
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 40.744593, lng: -73.990370}, // Manhattan, New York.
zoom: 12,
styles: [
{
"elementType": "geometry",
"stylers": [
{
"color": "#f5f5f5"
}
]
},
{
"elementType": "labels.icon",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "water",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
}
]
});
setUpDrawingTools();
}
아래 샘플 스타일은 관심 장소 라벨이 있는 그레이스케일 지도를 보여줍니다.
[
{
"elementType": "geometry",
"stylers": [
{
"color": "#f5f5f5"
}
]
},
{
"elementType": "labels.icon",
"stylers": [
{
"visibility": "on"
}
]
},
{
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#616161"
}
]
},
{
"elementType": "labels.text.stroke",
"stylers": [
{
"color": "#f5f5f5"
}
]
},
{
"featureType": "administrative.land_parcel",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#bdbdbd"
}
]
},
{
"featureType": "poi",
"elementType": "geometry",
"stylers": [
{
"color": "#eeeeee"
}
]
},
{
"featureType": "poi",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#757575"
}
]
},
{
"featureType": "poi.park",
"elementType": "geometry",
"stylers": [
{
"color": "#e5e5e5"
}
]
},
{
"featureType": "poi.park",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
},
{
"featureType": "road",
"elementType": "geometry",
"stylers": [
{
"color": "#ffffff"
}
]
},
{
"featureType": "road.arterial",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#757575"
}
]
},
{
"featureType": "road.highway",
"elementType": "geometry",
"stylers": [
{
"color": "#dadada"
}
]
},
{
"featureType": "road.highway",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#616161"
}
]
},
{
"featureType": "road.local",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
},
{
"featureType": "transit.line",
"elementType": "geometry",
"stylers": [
{
"color": "#e5e5e5"
}
]
},
{
"featureType": "transit.station",
"elementType": "geometry",
"stylers": [
{
"color": "#eeeeee"
}
]
},
{
"featureType": "water",
"elementType": "geometry",
"stylers": [
{
"color": "#c9c9c9"
}
]
},
{
"featureType": "water",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9e9e9e"
}
]
}
]
사용자에게 의견 제공
BigQuery는 일반적으로 몇 초 안에 응답을 제공하지만 쿼리가 실행되는 동안 사용자에게 진행 중인 사항을 표시하는 것이 유용한 경우가 있습니다.
checkJobStatus()
함수의 응답을 표시하는 UI와 쿼리가 진행 중임을 나타내는 애니메이션 그래픽을 웹페이지에 추가합니다.
표시할 수 있는 정보에는 쿼리 기간, 반환된 데이터 양, 처리된 데이터 양이 포함됩니다.
지도 <div>
뒤에 HTML을 추가하여 쿼리에서 반환된 행 수, 쿼리에 걸린 시간, 처리된 데이터 양을 표시하는 패널을 페이지에 만듭니다.
<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;
}
애니메이션 그래픽을 페이지에 추가할 수 있지만 필요할 때까지 숨겨져 있으며 BigQuery 작업이 실행될 때 표시하는 데 사용되는 일부 JavaScript 및 CSS 코드가 있습니다.
애니메이션 그래픽을 표시하는 HTML을 추가합니다. 코드 저장소의 img
폴더에 loader.gif
라는 이미지 파일이 있습니다.
<img id="spinner" src="img/loader.gif">
이미지를 배치하고 필요할 때까지 기본적으로 숨기도록 CSS를 추가합니다.
#spinner {
position: absolute;
top: 50%;
left: 50%;
margin-left: -32px;
margin-top: -32px;
opacity: 0;
z-index: -1000;
}
마지막으로 JavaScript를 추가하여 쿼리가 실행될 때 상태 패널을 업데이트하고 그래픽을 표시하거나 숨깁니다. response
객체를 사용하여 사용 가능한 정보에 따라 패널을 업데이트할 수 있습니다.
현재 작업을 확인할 때 사용할 수 있는 response.statistics
속성이 있습니다. 작업이 완료되면 response.totalRows
및 response.totalBytesProcessed
속성에 액세스할 수 있습니다. 아래 코드 샘플과 같이 밀리초를 초로, 바이트를 기가바이트로 변환하여 표시하면 사용자에게 유용합니다.
function updateStatus(response){
if(response.statistics){
let durationMs = response.statistics.endTime - response.statistics.startTime;
let durationS = durationMs/1000;
let suffix = (durationS ==1) ? '':'s';
let durationTd = document.getElementById("duration");
durationTd.innerHTML = durationS + ' second' + suffix;
}
if(response.totalRows){
let rowsTd = document.getElementById("rowCount");
rowsTd.innerHTML = response.totalRows;
}
if(response.totalBytesProcessed){
let bytesTd = document.getElementById("bytes");
bytesTd.innerHTML = (response.totalBytesProcessed/1073741824) + ' GB';
}
}
checkJobStatus()
호출에 대한 응답이 있고 쿼리 결과를 가져올 때 이 메서드를 호출합니다. 예를 들면 다음과 같습니다.
// Poll a job to see if it has finished executing.
function checkJobStatus(jobId){
let request = gapi.client.bigquery.jobs.get({
'projectId': billingProjectId,
'jobId': jobId
});
request.execute(response => {
//Show progress to the user
updateStatus(response);
if (response.status.errorResult){
// Handle any errors.
console.log(response.status.error);
return;
}
if (response.status.state == 'DONE'){
// Get the results.
clearTimeout(jobCheckTimer);
getQueryResults(jobId);
return;
}
// Not finished, check again in a moment.
jobCheckTimer = setTimeout(checkJobStatus, 500, [jobId]);
});
}
// When a BigQuery job has completed, fetch the results.
function getQueryResults(jobId){
let request = gapi.client.bigquery.jobs.getQueryResults({
'projectId': billingProjectId,
'jobId': jobId
});
request.execute(response => {
doHeatMap(response.result.rows);
updateStatus(response);
})
}
애니메이션 그래픽을 전환하려면 공개 상태를 제어하는 함수를 추가합니다. 이 함수는 전달된 HTML DOM 요소의 불투명도를 전환합니다.
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);
})
}
페이지는 다음과 같이 표시됩니다.
step8/map.html의 전체 예시를 살펴보세요.
14. 고려사항
마커가 너무 많음
초대형 테이블을 사용하는 경우 쿼리가 지도에 효율적으로 표시하기에는 너무 많은 행을 반환할 수도 있습니다. WHERE
절이나 LIMIT
문을 추가하여 결과를 제한합니다.
마커를 많이 그리면 지도를 읽지 못할 수 있습니다. HeatmapLayer
를 사용하여 밀도를 표시하거나 클러스터당 단일 기호를 사용하여 많은 데이터 포인트가 있는 위치를 나타내는 마커를 클러스터링하는 것이 좋습니다. 자세한 내용은 마커 클러스터링 튜토리얼을 참고하세요.
쿼리 최적화
BigQuery는 모든 쿼리로 전체 테이블을 검색합니다. BigQuery 할당량 사용을 최적화하려면 쿼리에 필요한 열만 선택하세요.
위도와 경도를 문자열이 아닌 부동 소수점으로 저장하면 쿼리가 더 빨라집니다.
흥미로운 결과 내보내기
여기에 나온 예시에서는 최종 사용자가 BigQuery 테이블에 대해 인증해야 하므로 모든 사용 사례에 적합하지는 않습니다. 흥미로운 패턴을 발견한 경우 BigQuery에서 결과를 내보내고 Google 지도 데이터 레이어를 사용하여 정적 데이터 세트를 만들어 더 많은 사용자와 공유하는 것이 더 쉬울 수 있습니다.
지루한 법적 내용
Google Maps Platform 서비스 약관을 참고하세요. Google Maps Platform 가격에 대한 자세한 내용은 온라인 설명서를 참고하세요.
더 많은 데이터로 플레이하세요.
BigQuery에는 위도 및 경도 열이 있는 공개 데이터 세트가 많이 있습니다. 예를 들어 2009~2016년의 NYC 택시 데이터 세트, Uber 및 Lyft NYC 여행 데이터, GDELT 데이터 세트가 있습니다.
15. 축하합니다.
BigQuery 테이블에 대한 지리 쿼리를 빠르게 실행하여 패턴을 파악하고 Google 지도에 시각화하는 데 도움이 되기를 바랍니다. 즐겁게 매핑하세요!
다음 단계
Google Maps Platform 또는 BigQuery에 대해 자세히 알아보려면 다음 제안사항을 참고하세요.
Google의 서버리스 페타바이트 규모 데이터 웨어하우스 서비스에 대해 자세히 알아보려면 BigQuery란 무엇인가요?를 참고하세요.
BigQuery API를 사용하여 간단한 애플리케이션을 만드는 방법 가이드를 참고하세요.
Google 지도에 도형을 그리는 사용자 상호작용을 사용 설정하는 방법에 관한 자세한 내용은 그리기 라이브러리 개발자 가이드를 참고하세요.
Google 지도에서 데이터를 시각화하는 다른 방법을 살펴보세요.
클라이언트 API를 사용하여 다른 Google API에 액세스하는 기본 개념을 이해하려면 JavaScript 클라이언트 API 시작 가이드를 참고하세요.