Google Sheets와 Slides를 사용하여 빅데이터에서 유용한 정보 도출하기

데이터 과학자가 빅데이터 분석을 수행할 수 있는 도구는 많지만 결국에는 경영진에게 결과를 정당화해야 하지 않나요? 종이나 데이터베이스에 있는 많은 숫자는 주요 이해관계자에게 거의 표시되지 않습니다. 이 중급 Google Apps Script Codelab에서는 Google의 개발자 플랫폼인 G SuiteGoogle Cloud Platform (GCP)을 활용하여 마지막 단계를 완료할 수 있도록 지원합니다.

Google Cloud의 개발자 도구를 사용하면 심층적인 데이터 분석을 실행한 다음 결과를 스프레드시트에 입력하고 해당 데이터로 슬라이드 프레젠테이션을 생성하여 경영진에게 결과를 전달하기에 더 적합한 단계를 제공할 수 있습니다. 이 Codelab에서는 GCP의 BigQuery API (Apps Script 고급 서비스)와 Google SheetsGoogle Slides기본 제공 Apps Script 서비스를 다룹니다.

동기/선행 기술

이 Codelab의 샘플 앱은 다음 코드 샘플에서 영감을 받았습니다.

Slides API Codelab 샘플 앱에도 BigQuery와 Slides가 포함되어 있지만 다음과 같은 여러 면에서 이 Codelab의 샘플 앱과 다릅니다.

  • Node.js 앱과 Apps Script 앱 비교
  • Apps Script 서비스를 사용하는 동안 REST API를 사용합니다.
  • Google Drive를 사용하지만 Google Sheets는 사용하지 않습니다. 이 앱은 Sheets를 사용하지만 Drive는 사용하지 않습니다.

이 Codelab에서는 실제 사용 사례와 더 유사한 방식으로 Google Cloud 전반의 기능과 API를 보여주면서 최대한 많은 기술을 하나의 앱으로 통합하고자 했습니다. 목표는 상상력을 발휘하고 GCP와 G Suite를 모두 활용하여 조직 또는 고객의 어려운 문제를 해결하도록 영감을 주는 것입니다.

학습할 내용

  • 여러 Google (GCP 및 G Suite) 서비스와 함께 Google Apps Script를 사용하는 방법
  • Google BigQuery를 사용하여 빅데이터 분석을 수행하는 방법
  • Google 시트를 만들고 데이터를 채우는 방법
  • Sheets에서 새 차트를 만드는 방법
  • Sheets의 차트와 데이터를 Google Slides 프레젠테이션으로 전송하는 방법

필요한 항목

  • 인터넷 및 웹브라우저 액세스
  • Google 계정(G Suite 계정의 경우 관리자 승인이 필요할 수 있음)
  • 기본 JavaScript 기술
  • Apps Script 개발에 대한 지식이 있으면 도움이 되지만 필수는 아님

이 Codelab/튜토리얼을 어떻게 사용할 예정인가요?

정보를 위해 읽고 기술 동료에게 전달할 수 있음 가능한 한 많이 살펴보고 최대한 많은 연습을 시도함 어떤 일이 있어도 전체 Codelab을 완료함

G Suite 개발자 도구 및 API 사용 경험을 평가해 주세요.

초급 중급 고급

Apps Script 사용 경험을 어떻게 평가하시겠어요?

초급 중급 고급

GCP 개발자 도구 및 API 사용 경험을 평가해 주세요.

초급 중급 고급

이 Codelab의 내용을 알았으니 이제 정확히 무엇을 할 건가요?

  1. 기존 Apps Script-BigQuery 샘플을 가져와 작동하도록 합니다.
  2. 이 샘플에서 BigQuery에 쿼리를 전송하고 결과를 가져오는 방법을 알아봅니다.
  3. Google Sheets를 만들고 BigQuery의 결과를 채웁니다.
  4. 반환되고 시트에 추가되는 데이터를 약간 변경하도록 코드를 수정합니다.
  5. Apps Script의 Sheets 서비스를 사용하여 BigQuery의 데이터로 차트 만들기
  6. Slides 서비스를 사용하여 새 슬라이드 프레젠테이션 만들기
  7. 모든 새 슬라이드 덱에 자동으로 생성되는 기본 제목 슬라이드에 제목과 부제목 추가
  8. 데이터 표가 포함된 새 슬라이드를 만든 다음 시트의 데이터 셀을 가져옵니다.
  9. 새 슬라이드를 하나 더 추가하고 스프레드시트 차트를 추가합니다.

Apps Script, BigQuery, Sheets, Slides에 관한 배경 정보를 살펴보겠습니다.

Google Apps Script 및 BigQuery

Google Apps Script는 Google REST API를 사용하는 것보다 상위 수준으로 작동하는 G Suite 개발 플랫폼입니다. 다양한 개발자 기술 수준에서 액세스할 수 있는 서버리스 개발 및 애플리케이션 호스팅 환경입니다. 한 문장으로 표현하면 'Apps Script는 G Suite 자동화, 확장, 통합을 위한 서버리스 JavaScript 런타임입니다.'

Node.js와 유사한 서버 측 JavaScript이지만 빠른 비동기 이벤트 기반 애플리케이션 호스팅보다는 G Suite 및 기타 Google 서비스와의 긴밀한 통합에 중점을 둡니다. 또한 평소 사용하던 것과 완전히 다른 개발 환경이 있습니다. Apps Script를 사용하면 다음 작업을 할 수 있습니다.

  • 브라우저 기반 코드 편집기에서 개발하지만 Apps Script용 명령줄 배포 도구인 clasp를 사용하는 경우 로컬에서 개발할 수 있음
  • G Suite 및 기타 Google 또는 외부 서비스 (Apps Script URLfetch 또는 Jdbc 서비스를 통해)에 액세스하도록 맞춤설정된 특수 버전의 JavaScript로 코딩
  • Apps Script에서 승인 코드를 처리하므로 승인 코드를 작성하지 않아도 됨
  • 앱을 호스팅할 필요가 없습니다. 앱은 클라우드의 Google 서버에서 실행됩니다.

참고: Apps Script를 가르치는 것은 이 Codelab의 범위를 벗어납니다. 이를 위해 정말 많은 온라인 리소스가 존재합니다. 공식 문서에는 빠른 시작이 포함된 개요, 튜토리얼, 동영상도 있습니다. 마지막으로 이 Codelab을 시작하기 전에 완료해야 하는 Apps Script 소개 Codelab도 잊지 마세요.

Apps Script는 다음과 같은 두 가지 방법으로 다른 Google 기술과 인터페이스합니다.

  • 내장/네이티브 서비스
  • 고급 서비스

내장 서비스는 G Suite 또는 Google 제품 데이터에 액세스하거나 기타 유용한 유틸리티 메서드에 액세스하는 데 사용할 수 있는 상위 수준 메서드를 제공합니다. 고급 서비스는 G Suite 또는 Google REST API를 래핑하는 얇은 래퍼일 뿐입니다. 고급 서비스는 REST API를 완전히 지원하며 내장 서비스보다 더 많은 작업을 할 수 있는 경우가 많지만 코드 복잡성이 더 높습니다 (REST API 자체보다 사용하기는 더 쉬움). 고급 서비스를 사용하려면 먼저 스크립트 프로젝트에서 사용 설정해야 합니다.

가능한 경우 개발자는 고급 서비스보다 사용하기 쉽고 더 많은 작업을 수행하는 내장 서비스를 선호해야 합니다. 하지만 일부 Google API에는 내장 서비스가 없으므로 고급 서비스가 유일한 옵션일 수 있습니다. Google BigQuery가 그 예입니다. 기본 제공 서비스는 사용할 수 없지만 BigQuery 고급 서비스있습니다. (서비스가 없는 것보다는 낫죠?) BigQuery를 처음 사용하는 경우 BigQuery는 매우 큰 데이터 코퍼스 (예: 수 테라바이트)에 대해 간단한 쿼리 또는 복잡한 쿼리를 실행할 수 있지만 결과를 몇 초 만에 제공할 수 있는 GCP 서비스입니다.

Apps Script에서 Google Sheets 및 Slides에 액세스하기

BigQuery와 달리 Google Sheets와 Slides에는 기본 제공 서비스 (API에서만 제공되는 기능에 액세스하는 데만 사용하는 고급 서비스 포함)가 있습니다. 코드로 바로 이동하기 전에 기본 제공 SheetsSlides 서비스에 관한 문서를 확인하세요. 고급 서비스에 관한 문서도 있습니다. SheetsSlides에 관한 문서는 각각 여기에서 확인할 수 있습니다.

소개

첫 번째 작업으로 이 Codelab의 많은 부분을 다룰 것입니다. 여기까지 완료하면 전체 Codelab의 절반 정도를 완료한 것입니다. 여러 하위 섹션으로 나뉘어 있으며 다음 작업을 수행합니다.

  • 새 Google Apps Script 프로젝트 시작
  • BigQuery 고급 서비스에 대한 액세스 사용 설정
  • 개발 편집기로 이동하여 애플리케이션 소스 코드를 입력합니다.
  • 앱 승인 프로세스 (OAuth2) 진행
  • BigQuery에 요청을 전송하는 애플리케이션 실행
  • BigQuery의 결과로 생성된 새로운 Google Sheets 보기

설정

  1. a) script.google.com로 이동하여 새 Apps Script 프로젝트를 만듭니다 . G Suite 제품 라인은 여러 가지가 있으며, 사용 중인 버전에 따라 새 프로젝트를 만드는 방법이 다를 수 있습니다. Gmail 계정만 사용하고 프로젝트 개발을 처음 시작하는 경우 첫 번째 프로젝트를 만드는 버튼과 함께 빈 화면이 표시됩니다.


b) 그렇지 않으면 모든 프로젝트와 왼쪽 상단에 큰 +새로 만들기 버튼이 표시될 수 있으므로 클릭합니다.



c) 위의 두 가지 모두에 해당하지 않으면 화면이 아래와 같이 표시될 수 있습니다. 이 경우 왼쪽 상단에서 햄버거 메뉴 아이콘을 찾아 +새 스크립트를 선택합니다.



d) 명령줄을 선호하는 경우 도구는 clasp이며, 특히 clasp create 명령어를 실행합니다.

e) 새 스크립트 프로젝트를 만드는 마지막 방법은 바로가기 링크인 https://script.google.com/create로 이동하는 것입니다.

  1. 새 프로젝트를 시작하는 데 사용한 기술과 관계없이 Apps Script 코드 편집기(다음과 같은 화면)로 이동해야 합니다.


  2. File > Save를 클릭하고 프로젝트 이름을 지정합니다.
  3. 다음으로 BigQuery 쿼리를 실행하려면 Google Cloud 콘솔 프로젝트를 만들어야 합니다.
  1. 새 프로젝트 만들기를 클릭하고 이름을 지정한 다음 결제 계정을 선택하고 만들기를 클릭합니다.
  1. 프로젝트 생성이 완료되면 페이지 우측 상단에 알림이 나타납니다. 프로젝트 만들기: <프로젝트 이름> 항목을 클릭하여 프로젝트를 엽니다.
  2. 왼쪽 상단의 메뉴 아이콘 을 클릭하고 API 및 서비스 > 사용자 인증 정보로 이동합니다. OAuth 동의 화면 탭 (직접 링크)을 클릭합니다.
  3. 애플리케이션 이름 필드에 'Big Data Codelab'을 입력하고 하단의 저장 버튼을 클릭합니다.
  4. 오른쪽 상단의 점 3개 아이콘을 클릭하여 메뉴를 펼치고 프로젝트 설정 (바로가기 링크)을 선택합니다.
  5. 프로젝트 번호 아래에 나열된 값을 복사합니다. (Codelab 후반부에서 사용할 별도의 제품 ID 필드가 있습니다.)
  6. App Script 편집기로 돌아가서 리소스 > Cloud Platform 프로젝트를 클릭합니다.
  7. 텍스트 상자에 프로젝트 번호를 입력하고 프로젝트 설정을 클릭합니다. 메시지가 표시되면 확인을 클릭합니다.
  8. 완료되면 닫기 버튼을 클릭하여 대화상자를 닫습니다.
  9. 새 프로젝트를 설정했으므로 BigQuery 고급 서비스를 사용 설정해야 합니다. 리소스 -> 고급 Google 서비스를 풀다운하고 BigQuery API의 비트를 사용으로 전환합니다.


  10. 하단에 '이 서비스는 'Google Cloud Platform API 대시보드'에도 사용 설정되어 있어야 합니다.'라는 메모가 표시되므로 링크를 클릭하여 개발자 콘솔(또는 'devconsole')을 여는 다른 브라우저 탭을 엽니다.
  11. 개발자 콘솔에서 상단의 +API 및 서비스 사용 설정 버튼을 클릭하고 'bigquery'를 검색한 후 BigQuery API (BigQuery Data Transfer API가 아님)를 선택하고 사용 설정을 클릭하여 사용 설정합니다. 이 브라우저 탭을 열어 둡니다.

    참고: API가 사용 설정된 후 이 페이지에 '이 API를 사용하려면 사용자 인증 정보를 만들어야 합니다'와 같은 메시지가 표시될 수 있지만 지금은 걱정하지 마세요. Apps Script에서 이 단계를 처리해 줍니다.


  12. 코드 편집기 브라우저 탭으로 돌아가면 고급 Google 서비스 메뉴가 표시되므로 확인을 클릭하여 대화상자를 닫고 코드 편집기로 돌아갑니다. 상단의 프로젝트 이름을 클릭하고 원하는 이름(예: 'BigQuery 데모')을 지정합니다. Google에서는 'final mile'이라고 지정했습니다.

이제 애플리케이션 코드를 입력하고, 승인 절차를 거치고, 이 애플리케이션의 첫 번째 버전을 작동시킬 수 있습니다.

애플리케이션 업로드 및 실행

  1. 아래 상자의 코드를 복사하여 코드 편집기의 모든 항목에 붙여넣습니다.
// Filename for data results
var QUERY_NAME = "Most common words in all of Shakespeare's works";
// Replace this value with your Google Cloud API project ID
var PROJECT_ID = '';
if (!PROJECT_ID) throw Error('Project ID is required in setup');

/**
 * Runs a BigQuery query; puts results into Sheet. You must enable
 * the BigQuery advanced service before you can run this code.
 * @see http://developers.google.com/apps-script/advanced/bigquery#run_query
 * @see http://github.com/googleworkspace/apps-script-samples/blob/main/advanced/bigquery.gs
 *
 * @returns {Spreadsheet} Returns a spreadsheet with BigQuery results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/spreadsheet
 */
function runQuery() {
  // Replace sample with your own BigQuery query.
  var request = {
    query:
        'SELECT ' +
            'LOWER(word) AS word, ' +
            'SUM(word_count) AS count ' +
        'FROM [bigquery-public-data:samples.shakespeare] ' +
        'GROUP BY word ' +
        'ORDER BY count ' +
        'DESC LIMIT 10'
  };
  var queryResults = BigQuery.Jobs.query(request, PROJECT_ID);
  var jobId = queryResults.jobReference.jobId;

  // Wait for BQ job completion (with exponential backoff).
  var sleepTimeMs = 500;
  while (!queryResults.jobComplete) {
    Utilities.sleep(sleepTimeMs);
    sleepTimeMs *= 2;
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId);
  }

  // Get all results from BigQuery.
  var rows = queryResults.rows;
  while (queryResults.pageToken) {
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId, {
      pageToken: queryResults.pageToken
    });
    rows = rows.concat(queryResults.rows);
  }

  // Return null if no data returned.
  if (!rows) {
    return Logger.log('No rows returned.');
  }

  // Create the new results spreadsheet.
  var spreadsheet = SpreadsheetApp.create(QUERY_NAME);
  var sheet = spreadsheet.getActiveSheet();

  // Add headers to Sheet.
  var headers = queryResults.schema.fields.map(function(field) {
    return field.name.toUpperCase();
  });
  sheet.appendRow(headers);

  // Append the results.
  var data = new Array(rows.length);
  for (var i = 0; i < rows.length; i++) {
    var cols = rows[i].f;
    data[i] = new Array(cols.length);
    for (var j = 0; j < cols.length; j++) {
      data[i][j] = cols[j].v;
    }
  }

  // Start storing data in row 2, col 1
  var START_ROW = 2;      // skip header row
  var START_COL = 1;
  sheet.getRange(START_ROW, START_COL, rows.length, headers.length).setValues(data);

  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());
}


방금 만든 파일을 저장하되 Code.gs에서 bq-sheets-slides.js로 이름을 바꿉니다. 이 코드는 어떤 역할을 할까요? BigQuery를 쿼리하고 결과를 새 Google 시트에 쓴다고 이미 말씀드렸지만 이 쿼리는 무엇일까요? runQuery() 상단에서 확인할 수 있습니다.

SELECT
    LOWER(word) AS word,
    SUM(word_count) AS count
FROM [bigquery-public-data:samples.shakespeare]
GROUP BY word
ORDER BY count
DESC LIMIT 10


이 쿼리는 BigQuery의 공개 데이터 세트에 포함된 Shakespeare의 작품을 살펴보고 모든 작품에서 가장 자주 등장하는 상위 10개 단어를 인기순으로 내림차순 정렬하여 생성합니다. 이 작업을 직접 수행하는 것이 얼마나 재미없을지 상상해 보면 BigQuery가 얼마나 유용한지 알 수 있습니다.

  1. 아직은 이 기능을 사용해 볼 준비가 되지 않았습니다. 이 코드 스니펫의 상단에서 볼 수 있듯이 유효한 프로젝트 ID가 필요하므로 애플리케이션 코드에 프로젝트 ID를 추가해야 합니다. 이 값을 확인하려면 개발자 콘솔 페이지가 있는 브라우저 창 또는 탭으로 돌아갑니다. (열어 두라고 말씀드렸죠?)
  2. Google 계정 아바타의 왼쪽 상단에 풀다운 메뉴 선택기 ()가 있습니다. 이를 클릭하고 프로젝트 설정을 선택합니다. 프로젝트 이름, ID, 번호가 표시됩니다. 프로젝트 ID를 복사하고 bq-sheets-slides.js 상단의 PROJECT_ID 변수를 개발자 콘솔에서 가져온 값으로 설정합니다. 참고: 메뉴 선택기가 고정되어 작동하지 않으면 페이지를 새로고침하세요.
  3. if 문은 프로젝트 ID가 없는 경우 애플리케이션이 더 이상 진행되지 않도록 하기 위한 것입니다. 추가한 후 파일을 저장하고 메뉴 바로 이동하여 실행 > 함수 실행 > runQuery를 선택하여 코드를 실행합니다. 권한 검토 대화상자, 이 앱은 인증되지 않았음을 클릭합니다. 아래는 다음 단계를 보여주는 애니메이션 GIF (다른 앱용)입니다.
  4. 권한 검토를 요청하면 위와 같은 새 대화상자가 표시됩니다. 스크립트를 실행할 올바른 Google 계정을 선택하고 고급을 선택한 다음 아래로 스크롤하여 '<YOUR PROJECT NAME>으로 이동(안전하지 않음)'을 클릭하여 OAuth2 애플리케이션 승인 화면으로 이동합니다. (인증 절차에 대해 자세히 알아보면 이 화면이 아래의 OAuth2 승인 대화상자와 사용자 사이에 있는 이유를 알 수 있습니다.)


    참고: 앱을 승인하면 각 실행에서 이 절차를 반복할 필요가 없습니다. 이 튜토리얼의 Task 3에 도달할 때까지는 Google Slides 프레젠테이션을 만들고 관리할 사용자 권한을 요청하는 이 대화상자 화면이 다시 표시되지 않습니다.
  5. OAuth2 대화상자 창에서 허용을 클릭하면 스크립트가 실행되기 시작하고 상단에 파스텔 노란색 대화상자가 표시됩니다. 이 스크립트는 매우 빠르게 실행되므로 실행 중이거나 실행이 완료되었음을 알지 못할 수 있습니다.

  6. 이 대화상자는 완료되면 사라지므로 표시되지 않으면 완료된 것입니다. Google Drive (drive.google.com)로 이동하여 'Most common words in all of Shakespeare's works'라는 새 Google Sheets 또는 QUERY_NAME 변수에 할당한 이름을 찾습니다.


  7. 스프레드시트를 열면 단어와 총 개수가 내림차순으로 정렬된 10개의 행이 표시됩니다.

작업 1 요약

방금 무슨 일이 일어났는지 생각해 보세요. 셰익스피어의 모든 작품을 쿼리하는 코드를 실행했습니다. 데이터가 아주 많은 것은 아니지만, 모든 희곡의 모든 단어를 살펴보고, 이러한 단어의 수를 관리하고, 등장 횟수의 내림차순으로 정렬하는 것보다 훨씬 많은 텍스트입니다. BigQuery에 이를 대신 수행하도록 요청했을 뿐만 아니라 Google Sheets용 Apps Script의 기본 제공 서비스를 사용하여 이 데이터를 쉽게 사용할 수 있도록 넣을 수 있었습니다.

위에서 붙여넣은 bq-sheets-slides.js(선택한 파일 이름)의 코드(실제 프로젝트 ID가 있어야 하는 PROJECT_ID 제외)는 이 Codelab의 GitHub 저장소(github.com/googlecodelabs/bigquery-sheets-slides)의 step1 폴더에서도 확인할 수 있습니다. 이 코드는 약간 다른 쿼리를 실행하는 BigQuery 고급 서비스 페이지의 원래 예시에서 영감을 받았습니다. 셰익스피어가 10자 이상의 가장 인기 있는 단어는 무엇일까요? GitHub 저장소에서도 샘플을 확인할 수 있습니다.

셰익스피어 작품이나 기타 공개 데이터 테이블에 대해 시도해 볼 수 있는 다른 쿼리에 관심이 있다면 이 웹페이지이 웹페이지를 확인하세요. 사용하는 쿼리와 상관없이 Apps Script에서 실행하기 전에 BigQuery 콘솔에서 쿼리를 테스트할 수 있습니다. BigQuery의 사용자 인터페이스는 bigquery.cloud.google.com에서 개발자가 사용할 수 있습니다. 예를 들어 BigQuery UI를 사용하여 쿼리를 실행하면 다음과 같이 표시됩니다.

위 단계에서는 Apps Script의 코드 편집기를 사용했지만 명령줄을 통해 로컬로 개발할 수도 있습니다. 원하는 경우 bq-sheets-slides.js라는 스크립트를 만들고 위의 코드를 붙여넣은 다음 clasp push 명령어를 사용하여 Google에 업로드합니다. (이전에 놓친 경우 clasp 링크와 사용 방법이 여기에 다시 나와 있습니다.)

runQuery()의 목적은 BigQuery와 통신하고 결과를 Sheets로 전송하는 것입니다. 이제 데이터를 사용하여 차트를 만들어야 합니다. 이를 위해 시트의 newChart() 메서드를 호출하는 createColumnChart()라는 새 함수를 만들어 보겠습니다.

  1. 차트 만들기 아래에 나온 createColumnChart() 본문을 runQuery() 바로 뒤에 bq-sheets-slides.js에 추가합니다. 데이터가 있는 시트를 가져와 모든 데이터가 포함된 열 차트를 요청합니다. 첫 번째 행에는 데이터가 아닌 열 헤더가 포함되어 있으므로 데이터 범위는 A2 셀에서 시작됩니다.
/**
 * Uses spreadsheet data to create columnar chart.
 * @param {Spreadsheet} Spreadsheet containing results data
 * @returns {EmbeddedChart} visualizing the results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/embedded-chart
 */
function createColumnChart(spreadsheet) {
  // Retrieve the populated (first and only) Sheet.
  var sheet = spreadsheet.getSheets()[0];
  // Data range in Sheet is from cell A2 to B11
  var START_CELL = 'A2';  // skip header row
  var END_CELL = 'B11';
  // Place chart on Sheet starting on cell E5.
  var START_ROW = 5;      // row 5
  var START_COL = 5;      // col E
  var OFFSET = 0;

  // Create & place chart on the Sheet using above params.
  var chart = sheet.newChart()
     .setChartType(Charts.ChartType.COLUMN)
     .addRange(sheet.getRange(START_CELL + ':' + END_CELL))
     .setPosition(START_ROW, START_COL, OFFSET, OFFSET)
     .build();
  sheet.insertChart(chart);
}
  1. 스프레드시트 반환 위에서 createColumnChart()에는 스프레드시트 객체가 필요하므로 spreadsheet 객체를 반환하도록 runQuery()를 업데이트하여 createColumnChart()에 전달해야 합니다. Google 시트가 성공적으로 생성되었음을 로깅한 후 로그 줄 바로 뒤에 있는 runQuery() 끝에서 spreadsheet 객체를 반환합니다.
  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());

  // NEW: Return the spreadsheet object for later use.
  return spreadsheet;
}
  1. 운전 createBigQueryPresentation() 기능 BigQuery와 차트 생성 기능을 논리적으로 분리하는 것이 좋습니다. 이제 runQuery()createColumnChart()를 모두 호출하여 앱을 실행하는 createBigQueryPresentation() 함수를 만들어 보겠습니다. 추가하는 코드는 다음과 같아야 합니다.
/**
 * Runs a BigQuery query, adds data and a chart in a Sheet.
 */
function createBigQueryPresentation() {
  var spreadsheet = runQuery();
  createColumnChart(spreadsheet);
}
  1. 코드의 재사용 가능성 높이기 위에서 스프레드시트 객체를 반환하고 드라이브 함수를 만드는 두 가지 중요한 단계를 거쳤습니다. 동료가 runQuery()를 재사용하고 URL이 로깅되지 않기를 원하는 경우 어떻게 해야 하나요? 일반적인 사용을 위해 runQuery()를 더 쉽게 이해할 수 있도록 하려면 해당 로그 줄을 이동해야 합니다. 가장 적절한 위치는 어디인가요? createBigQueryPresentation()을 추측했다면 정답입니다. 로그 행을 이동한 후에는 다음과 같이 표시됩니다.
/**
 * Runs a BigQuery query, adds data and a chart in a Sheet.
 */
function createBigQueryPresentation() {
  var spreadsheet = runQuery();
  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl()); // MOVED HERE
  createColumnChart(spreadsheet);
}

위의 변경사항 (PROJECT_ID 제외)에 따라 bq-sheets-slides.js은 이제 다음과 같이 표시됩니다 (GitHub 저장소의 step2 폴더에서도 확인 가능).

// Filename for data results
var QUERY_NAME = "Most common words in all of Shakespeare's works";
// Replace this value with your Google Cloud API project ID
var PROJECT_ID = '';
if (!PROJECT_ID) throw Error('Project ID is required in setup');

/**
 * Runs a BigQuery query; puts results into Sheet. You must enable
 * the BigQuery advanced service before you can run this code.
 * @see http://developers.google.com/apps-script/advanced/bigquery#run_query
 * @see http://github.com/googleworkspace/apps-script-samples/blob/main/advanced/bigquery.gs
 *
 * @returns {Sheet} Returns a sheet with results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/sheet
 */
function runQuery() {
  // Replace sample with your own BigQuery query.
  var request = {
    query:
        'SELECT ' +
            'LOWER(word) AS word, ' +
            'SUM(word_count) AS count ' +
        'FROM [bigquery-public-data:samples.shakespeare] ' +
        'GROUP BY word ' +
        'ORDER BY count ' +
        'DESC LIMIT 10'
  };
  var queryResults = BigQuery.Jobs.query(request, PROJECT_ID);
  var jobId = queryResults.jobReference.jobId;

  // Wait for BQ job completion (with exponential backoff).
  var sleepTimeMs = 500;
  while (!queryResults.jobComplete) {
    Utilities.sleep(sleepTimeMs);
    sleepTimeMs *= 2;
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId);
  }

  // Get all results from BigQuery.
  var rows = queryResults.rows;
  while (queryResults.pageToken) {
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId, {
      pageToken: queryResults.pageToken
    });
    rows = rows.concat(queryResults.rows);
  }

  // Return null if no data returned.
  if (!rows) {
    return Logger.log('No rows returned.');
  }

  // Create the new results spreadsheet.
  var spreadsheet = SpreadsheetApp.create(QUERY_NAME);
  var sheet = spreadsheet.getActiveSheet();

  // Add headers to Sheet.
  var headers = queryResults.schema.fields.map(function(field) {
    return field.name.toUpperCase();
  });
  sheet.appendRow(headers);

  // Append the results.
  var data = new Array(rows.length);
  for (var i = 0; i < rows.length; i++) {
    var cols = rows[i].f;
    data[i] = new Array(cols.length);
    for (var j = 0; j < cols.length; j++) {
      data[i][j] = cols[j].v;
    }
  }

  // Start storing data in row 2, col 1
  var START_ROW = 2;      // skip header row
  var START_COL = 1;
  sheet.getRange(START_ROW, START_COL, rows.length, headers.length).setValues(data);

  // Return the spreadsheet object for later use.
  return spreadsheet;
}

/**
 * Uses spreadsheet data to create columnar chart.
 * @param {Spreadsheet} Spreadsheet containing results data
 * @returns {EmbeddedChart} visualizing the results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/embedded-chart
 */
function createColumnChart(spreadsheet) {
  // Retrieve the populated (first and only) Sheet.
  var sheet = spreadsheet.getSheets()[0];
  // Data range in Sheet is from cell A2 to B11
  var START_CELL = 'A2';  // skip header row
  var END_CELL = 'B11';
  // Place chart on Sheet starting on cell E5.
  var START_ROW = 5;      // row 5
  var START_COL = 5;      // col E
  var OFFSET = 0;

  // Create & place chart on the Sheet using above params.
  var chart = sheet.newChart()
     .setChartType(Charts.ChartType.COLUMN)
     .addRange(sheet.getRange(START_CELL + ':' + END_CELL))
     .setPosition(START_ROW, START_COL, OFFSET, OFFSET)
     .build();
  sheet.insertChart(chart);
}

/**
 * Runs a BigQuery query, adds data and a chart in a Sheet.
 */
function createBigQueryPresentation() {
  var spreadsheet = runQuery();
  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());
  createColumnChart(spreadsheet);
}

파일을 저장한 다음 코드 편집기 상단으로 이동하여 runQuery() 대신 createBigQueryPresentation()를 실행하도록 전환합니다. 실행하면 또 다른 Google 시트가 표시되는데, 이번에는 시트에 데이터 옆에 차트가 표시됩니다.

코드랩의 마지막 부분에서는 새 Google Slides 프레젠테이션을 만들고, 제목 슬라이드에 제목과 부제목을 입력한 다음, 데이터 셀 각각에 대해 하나씩, 차트에 대해 하나씩 총 2개의 새 슬라이드를 추가합니다.

  1. 슬라이드 자료 만들기 슬라이드 자료에 관한 모든 작업은 createSlidePresentation()에서 이루어지며, createSlidePresentation()createColumnChart() 바로 뒤에 bq-sheets-slides.js에 추가할 예정입니다. 먼저 새 슬라이드 덱을 만든 다음 모든 새 프레젠테이션에 제공되는 기본 제목 슬라이드에 제목과 부제목을 추가해 보겠습니다.
/**
 * Create presentation with spreadsheet data & chart
 * @param {Spreadsheet} Spreadsheet with results data
 * @param {EmbeddedChart} Sheets chart to embed on slide
 * @returns {Presentation} Slide deck with results
 */
function createSlidePresentation(spreadsheet, chart) {
  // Create the new presentation.
  var deck = SlidesApp.create(QUERY_NAME);

  // Populate the title slide.
  var [title, subtitle] = deck.getSlides()[0].getPageElements();
  title.asShape().getText().setText(QUERY_NAME);
  subtitle.asShape().getText().setText('via GCP and G Suite APIs:\n' +
    'Google Apps Script, BigQuery, Sheets, Slides');
  1. 데이터 표 추가 createSlidePresentation()의 다음 단계는 Google 시트의 셀 데이터를 새 슬라이드에 가져오는 것입니다. 이 코드 스니펫을 함수에 추가합니다.
  // Data range to copy is from cell A1 to B11
  var START_CELL = 'A1';  // include header row
  var END_CELL = 'B11';
  // Add the table slide and insert an empty table on it of
  // the dimensions of the data range; fails if Sheet empty.
  var tableSlide = deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
  var sheetValues = spreadsheet.getSheets()[0].getRange(
      START_CELL + ':' + END_CELL).getValues();
  var table = tableSlide.insertTable(sheetValues.length, sheetValues[0].length);

  // Populate the table with spreadsheet data.
  for (var i = 0; i < sheetValues.length; i++) {
    for (var j = 0; j < sheetValues[0].length; j++) {
      table.getCell(i, j).getText().setText(String(sheetValues[i][j]));
    }
  }
  1. 차트 가져오기 createSlidePresentation()의 마지막 단계는 슬라이드를 하나 더 만들고 스프레드시트에서 차트를 가져와 Presentation 객체를 반환하는 것입니다. 다음 최종 스니펫을 함수에 추가합니다.
  // Add a chart slide and insert the chart on it.
  var chartSlide = deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
  chartSlide.insertSheetsChart(chart);

  // Return the presentation object for later use.
  return deck;
}
  1. 차트 반환 이제 최종 함수가 완성되었으므로 서명을 다시 살펴보세요. 예, createSlidePresentation()에는 스프레드시트와 차트 객체가 모두 필요합니다. Spreadsheet 객체를 반환하도록 runQuery()를 이미 조정했지만 이제 차트 (EmbeddedChart) 객체를 반환하도록 createColumnChart()를 유사하게 변경해야 합니다. 애플리케이션으로 돌아가 코드에서 createColumnChart() 끝에 다음 줄을 추가하여 이를 실행합니다.
  // NEW: Return chart object for later use
  return chart;
}
  1. createBigQueryPresentation() 업데이트 createColumnChart()는 차트를 반환하므로 차트를 변수에 저장한 다음 스프레드시트와 차트를 createSlidePresentation()모두 전달해야 합니다. 새로 생성된 스프레드시트의 URL을 로깅하므로 새 슬라이드 프레젠테이션의 URL도 로깅해 보겠습니다. createBigQueryPresentation()를 다음과 같이 업데이트합니다.
/**
 * Runs a BigQuery query, adds data and a chart in a Sheet,
 * and adds the data and chart to a new slide presentation.
 */
function createBigQueryPresentation() {
  var spreadsheet = runQuery();
  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());
  var chart = createColumnChart(spreadsheet); // UPDATED
  var deck = createSlidePresentation(spreadsheet, chart); // NEW
  Logger.log('Results slide deck created: %s', deck.getUrl()); // NEW
}
  1. 저장하고 createBigQueryPresentation()을 다시 실행합니다. 하지만 실행되기 전에 앱에서 Google Slides 프레젠테이션을 보고 관리하려면 사용자로부터 권한이 하나 더 필요하다는 점을 알아야 합니다. 이 권한을 허용하면 이전과 같이 실행됩니다.
  2. 이제 생성된 시트 외에도 아래와 같이 슬라이드 3개 (제목, 데이터 표, 데이터 차트)가 포함된 새 Slides 프레젠테이션도 표시됩니다.

축하합니다. 이제 Google의 공개 데이터 세트 중 하나를 쿼리하는 Google BigQuery 요청을 실행하고, 결과를 저장할 새 Google Sheets를 만들고, 방금 검색한 데이터를 기반으로 차트를 추가하고, 마지막으로 스프레드시트의 결과와 차트를 모두 포함하는 Google Slides 프레젠테이션을 만들어 Google Cloud의 양쪽을 모두 활용하는 애플리케이션을 만들었습니다.

기술적으로는 그렇게 한 것입니다. 간단히 말해 빅데이터 분석에서 이해관계자에게 발표할 수 있는 결과까지 모두 코드로, 모두 자동화된 방식으로 진행했습니다. 이 샘플이 여러분의 프로젝트에 맞게 맞춤설정하는 데 도움이 되기를 바랍니다. 이 Codelab이 끝나면 이 샘플 앱을 추가로 개선할 수 있는 몇 가지 제안사항을 제공해 드립니다.

마지막 작업의 변경사항 (PROJECT_ID 제외)에 따라 bq-sheets-slides.js은 이제 다음과 같이 표시됩니다 (GitHub 저장소의 final 폴더에서도 확인 가능).

bq-sheets-slides.js

/**
 * Copyright 2018 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Filename for data results
var QUERY_NAME = "Most common words in all of Shakespeare's works";
// Replace this value with your Google Cloud API project ID
var PROJECT_ID = '';
if (!PROJECT_ID) throw Error('Project ID is required in setup');

/**
 * Runs a BigQuery query; puts results into Sheet. You must enable
 * the BigQuery advanced service before you can run this code.
 * @see http://developers.google.com/apps-script/advanced/bigquery#run_query
 * @see http://github.com/googleworkspace/apps-script-samples/blob/main/advanced/bigquery.gs
 *
 * @returns {Spreadsheet} Returns a spreadsheet with BigQuery results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/spreadsheet
 */
function runQuery() {
  // Replace sample with your own BigQuery query.
  var request = {
    query:
        'SELECT ' +
            'LOWER(word) AS word, ' +
            'SUM(word_count) AS count ' +
        'FROM [bigquery-public-data:samples.shakespeare] ' +
        'GROUP BY word ' +
        'ORDER BY count ' +
        'DESC LIMIT 10'
  };
  var queryResults = BigQuery.Jobs.query(request, PROJECT_ID);
  var jobId = queryResults.jobReference.jobId;

  // Wait for BQ job completion (with exponential backoff).
  var sleepTimeMs = 500;
  while (!queryResults.jobComplete) {
    Utilities.sleep(sleepTimeMs);
    sleepTimeMs *= 2;
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId);
  }

  // Get all results from BigQuery.
  var rows = queryResults.rows;
  while (queryResults.pageToken) {
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId, {
      pageToken: queryResults.pageToken
    });
    rows = rows.concat(queryResults.rows);
  }

  // Return null if no data returned.
  if (!rows) {
    return Logger.log('No rows returned.');
  }

  // Create the new results spreadsheet.
  var spreadsheet = SpreadsheetApp.create(QUERY_NAME);
  var sheet = spreadsheet.getActiveSheet();

  // Add headers to Sheet.
  var headers = queryResults.schema.fields.map(function(field) {
    return field.name.toUpperCase();
  });
  sheet.appendRow(headers);

  // Append the results.
  var data = new Array(rows.length);
  for (var i = 0; i < rows.length; i++) {
    var cols = rows[i].f;
    data[i] = new Array(cols.length);
    for (var j = 0; j < cols.length; j++) {
      data[i][j] = cols[j].v;
    }
  }

  // Start storing data in row 2, col 1
  var START_ROW = 2;      // skip header row
  var START_COL = 1;
  sheet.getRange(START_ROW, START_COL, rows.length, headers.length).setValues(data);

  // Return the spreadsheet object for later use.
  return spreadsheet;
}

/**
 * Uses spreadsheet data to create columnar chart.
 * @param {Spreadsheet} Spreadsheet containing results data
 * @returns {EmbeddedChart} visualizing the results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/embedded-chart
 */
function createColumnChart(spreadsheet) {
  // Retrieve the populated (first and only) Sheet.
  var sheet = spreadsheet.getSheets()[0];
  // Data range in Sheet is from cell A2 to B11
  var START_CELL = 'A2';  // skip header row
  var END_CELL = 'B11';
  // Place chart on Sheet starting on cell E5.
  var START_ROW = 5;      // row 5
  var START_COL = 5;      // col E
  var OFFSET = 0;

  // Create & place chart on the Sheet using above params.
  var chart = sheet.newChart()
     .setChartType(Charts.ChartType.COLUMN)
     .addRange(sheet.getRange(START_CELL + ':' + END_CELL))
     .setPosition(START_ROW, START_COL, OFFSET, OFFSET)
     .build();
  sheet.insertChart(chart);

  // Return the chart object for later use.
  return chart;
}

/**
 * Create presentation with spreadsheet data & chart
 * @param {Spreadsheet} Spreadsheet with results data
 * @param {EmbeddedChart} Sheets chart to embed on slide
 * @returns {Presentation} Returns a slide deck with results
 * @see http://developers.google.com/apps-script/reference/slides/presentation
 */
function createSlidePresentation(spreadsheet, chart) {
  // Create the new presentation.
  var deck = SlidesApp.create(QUERY_NAME);

  // Populate the title slide.
  var [title, subtitle] = deck.getSlides()[0].getPageElements();
  title.asShape().getText().setText(QUERY_NAME);
  subtitle.asShape().getText().setText('via GCP and G Suite APIs:\n' +
    'Google Apps Script, BigQuery, Sheets, Slides');

  // Data range to copy is from cell A1 to B11
  var START_CELL = 'A1';  // include header row
  var END_CELL = 'B11';
  // Add the table slide and insert an empty table on it of
  // the dimensions of the data range; fails if Sheet empty.
  var tableSlide = deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
  var sheetValues = spreadsheet.getSheets()[0].getRange(
      START_CELL + ':' + END_CELL).getValues();
  var table = tableSlide.insertTable(sheetValues.length, sheetValues[0].length);

  // Populate the table with spreadsheet data.
  for (var i = 0; i < sheetValues.length; i++) {
    for (var j = 0; j < sheetValues[0].length; j++) {
      table.getCell(i, j).getText().setText(String(sheetValues[i][j]));
    }
  }

  // Add a chart slide and insert the chart on it.
  var chartSlide = deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
  chartSlide.insertSheetsChart(chart);

  // Return the presentation object for later use.
  return deck;
}

/**
 * Runs a BigQuery query, adds data and a chart in a Sheet,
 * and adds the data and chart to a new slide presentation.
 */
function createBigQueryPresentation() {
  var spreadsheet = runQuery();
  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());
  var chart = createColumnChart(spreadsheet);
  var deck = createSlidePresentation(spreadsheet, chart);
  Logger.log('Results slide deck created: %s', deck.getUrl());
}

이 Codelab에서 역할을 하지 않는 것은 이 Codelab의 '두 번째 파일'인 Apps Script 매니페스트 파일 appsscript.json입니다. 코드 편집기 브라우저 탭으로 이동하여 상단의 메뉴에서 보기 > 매니페스트 파일 표시를 선택하면 액세스할 수 있습니다. 이 콘텐츠는 다음과 같이 표시됩니다.

appsscript.json

{
  "timeZone": "America/Los_Angeles",
  "dependencies": {
    "enabledAdvancedServices": [{
      "userSymbol": "BigQuery",
      "serviceId": "bigquery",
      "version": "v2"
    }]
  },
  "exceptionLogging": "STACKDRIVER"
}

매니페스트 파일은 Apps Script가 애플리케이션에 사용할 실행 환경을 파악하는 데 사용하는 시스템 수준 구성 파일입니다. 매니페스트 파일의 콘텐츠는 이 Codelab의 범위를 벗어나지만 그 역할을 파악할 수 있습니다.

아래에는 이 Codelab에서 다룬 내용을 자세히 살펴보고 Google 개발자 도구에 프로그래매틱 방식으로 액세스하는 다른 방법을 알아볼 수 있는 추가 리소스가 나와 있습니다. 이 Codelab은 저장소와 동기화된 상태를 유지하는 것을 목표로 합니다.

이 애플리케이션의 리소스

문서

기타 Codelab

초급

중급

참조 앱

아래에는 이 Codelab에서 빌드한 샘플을 개선하거나 보강할 수 있는 다양한 '코드 과제'가 나와 있습니다. 이 목록이 모든 경우를 포함하는 것은 아니지만 다음 단계로 나아갈 수 있는 아이디어를 얻는 데 도움이 될 것입니다.

  • 애플리케이션 JavaScript 사용 또는 Apps Script에서 부과하는 제한사항에 제한을 받고 싶지 않으신가요? 이 애플리케이션을 Google BigQuery, Sheets, Slides의 REST API를 사용하는 선호하는 프로그래밍 언어로 포팅합니다.
  • BigQuery. 셰익스피어 데이터 세트에 대해 다른 쿼리를 실험해 보세요. 관심 있는 쿼리를 찾아볼 수도 있습니다. 다른 샘플 쿼리는 원래 Apps Script BigQuery 샘플 앱에서 확인할 수 있습니다.
  • BigQuery. BigQuery의 다른 공개 데이터 세트를 실험해 보세요. 더 의미 있는 데이터 세트를 찾을 수도 있습니다.
  • BigQuery. 앞서 셰익스피어 작품이나 기타 공개 데이터 테이블에 대해 시도해 볼 수 있는 다른 쿼리를 언급했는데, 이 웹페이지이 웹페이지를 다시 공유해 드립니다.
  • Sheets 다른 차트 유형을 사용해 보세요.
  • Sheets 및 BigQuery 표를 뒤집어 보세요. 스프레드시트에 대규모 데이터 세트가 있을 수도 있습니다. 2016년에 BigQuery 팀은 개발자가 시트를 데이터 소스로 사용할 수 있는 기능을 도입했습니다 (자세한 내용은 블로그 게시물 12 참고).
  • Slides. 생성된 프레젠테이션에 빅데이터 분석과 관련된 이미지나 기타 애셋과 같은 슬라이드를 추가합니다. 시작하는 데 도움이 되는 Slides 내장 서비스 가이드를 참고하세요.
  • G Suite Apps Script에서 다른 G Suite 또는 Google 내장 서비스의 사용 사례를 찾습니다. Gmail, Google Drive, Calendar, Docs, 지도, 애널리틱스, YouTube 등은 물론 기타 고급 서비스 기본 서비스와 고급 서비스에 관한 자세한 내용은 참조 개요를 참고하세요.