市面上有許多工具可供資料科學家執行大數據分析,但最終您還是得向管理階層說明這些結果的合理性,不是嗎?紙上或資料庫中的大量數字,很難向主要利害關係人呈現。這項中階 Google Apps Script 程式碼研究室會運用 Google 的一對開發人員平台 (G Suite 和 Google Cloud Platform (GCP)),協助您完成最後一哩路。
Google Cloud 的開發人員工具可讓您執行深入的資料分析,然後將結果匯入試算表,並根據這些資料產生投影片簡報,以更合適的方式向管理階層呈現結果。本程式碼研究室涵蓋 GCP 的 BigQuery API (做為 Apps Script 進階服務),以及 Google 試算表和 Google 簡報的內建 Apps Script 服務。
動機/既有技術
本程式碼研究室中的範例應用程式是參考下列程式碼範例...
- Google Apps Script BigQuery 服務範例應用程式和 GitHub 上的開放原始碼
- 這部開發人員影片中介紹的範例應用程式,以及這篇網誌文章中發布的範例應用程式
- Google Slides API Codelab 中的範例應用程式
雖然 Slides API 程式碼研究室的範例應用程式也提供 BigQuery 和 Slides,但與本程式碼研究室的範例應用程式有幾項差異:
- Node.js 應用程式與 Apps Script 應用程式的比較
- 使用 REST API,同時使用 Apps Script 服務
- 使用 Google 雲端硬碟,但未使用 Google 試算表;這個應用程式使用 Google 試算表,但未使用 Google 雲端硬碟
在本程式碼研究室中,我們希望將盡可能多的技術整合到單一應用程式中,同時展示 Google Cloud 的各項功能和 API,讓您更貼近實際使用情境。我們希望藉此激發您的想像力,並考慮運用 GCP 和 G Suite 解決貴機構或客戶的難題。
課程內容
- 如何搭配多項 Google (GCP 和 G Suite) 服務使用 Google Apps Script
- 如何使用 Google BigQuery 執行大數據分析
- 如何建立 Google 試算表並填入資料
- 如何在 Google 試算表中建立新圖表
- 如何將 Google 試算表的圖表和資料轉移到 Google 簡報
軟硬體需求
- 網路連線和網路瀏覽器
- Google 帳戶 (G Suite 帳戶可能需要管理員核准)
- 具備基本 JavaScript 技能
- 具備 Apps Script 開發知識會有幫助,但並非必要條件
您會如何使用這個程式碼研究室/教學課程?
您對 G Suite 開發人員工具和 API 的體驗滿意嗎?
您對 Apps Script 的體驗滿意嗎?
您對 GCP 開發人員工具和 API 的體驗滿意嗎?
現在您已瞭解本程式碼研究室的主題,接下來要具體做些什麼呢?
- 使用現有的 Apps Script-BigQuery 範例並使其正常運作
- 從該範例瞭解如何將查詢傳送至 BigQuery 並取得結果
- 建立 Google 試算表,並將 BigQuery 的結果填入其中
- 稍微修改程式碼,稍微變更傳回並新增至試算表的資料
- 使用 Apps Script 中的試算表服務,為 BigQuery 資料建立圖表
- 使用 Google 簡報服務建立新的投影片簡報
- 為所有新投影片組自動建立的預設標題投影片新增標題和副標題
- 建立含有資料表的新投影片,然後將 Google 試算表的資料格匯入其中
- 新增另一張投影片,並在其中加入試算表圖表
首先,請先瞭解 Apps Script、BigQuery、試算表和簡報的背景資訊。
Google Apps Script 和 BigQuery
Google Apps Script 是 G Suite 開發平台,運作層級高於 Google REST API。這個無伺服器開發和應用程式代管環境適用於各種程度的開發人員。簡單來說,「Apps Script 是無伺服器 JavaScript 執行階段,可自動化、擴充及整合 G Suite。」
這項技術與 Node.js 類似,都是伺服器端 JavaScript,但著重於與 G Suite 和其他 Google 服務緊密整合,而非快速的非同步事件驅動應用程式代管。此外,開發環境可能與您習慣的環境完全不同。使用 Apps Script,您可以:
- 在網頁式程式碼編輯器中開發,但如果使用
clasp
(Apps Script 的指令列部署工具),則可選擇在本機開發 - 以專門版本的 JavaScript 編寫程式碼,存取 G Suite 和其他 Google 或外部服務 (透過 Apps Script
URLfetch
或Jdbc
服務) - 不必編寫授權程式碼,因為 Apps Script 會為您處理
- 不必代管應用程式,應用程式會存放在雲端中的 Google 伺服器上並在該處執行
注意:本程式碼研究室主要不會教導您 Apps Script,網路上有許多資源可協助您完成這項作業。官方說明文件也提供快速入門導覽課程總覽、教學課程和影片。最後,別忘了先完成 Apps Script 簡介程式碼研究室,再開始進行本程式碼研究室。
Apps Script 與其他 Google 技術的介面互動方式有兩種:
- 內建/原生服務
- 進階服務
內建服務提供高階方法,可用於存取 G Suite 或 Google 產品資料,或存取其他實用公用程式方法。進階服務只是 G Suite 或 Google REST API 的精簡包裝函式。進階服務可完整涵蓋 REST API,通常比內建服務的功能更多,但需要較複雜的程式碼 (不過仍比 REST API 本身更容易使用)。使用進階服務前,也必須為指令碼專案啟用進階服務。
如果可以,開發人員應優先使用內建服務,因為內建服務比進階服務更容易使用,且能處理更多繁重的工作。不過,部分 Google API 沒有內建服務,因此進階服務可能是唯一選擇。Google BigQuery 就是其中一例,雖然沒有內建服務,但有 BigQuery 進階服務。(總比沒有服務好,對吧?) 如果您是 BigQuery 新手,這項 GCP 服務可讓您對非常龐大的資料集 (例如數 TB 的資料) 執行簡單 (或複雜) 的查詢,並在幾秒內提供結果。
透過 Apps Script 存取 Google 試算表和簡報
與 BigQuery 不同,Google 試算表和簡報都有內建服務 (以及進階服務,您只會使用進階服務存取 API 專屬功能)。請先參閱內建的 試算表和簡報服務說明文件,再開始編寫程式碼。當然,進階服務也有相關文件,請分別參閱 Google 試算表和 Google 簡報的文件。
簡介
我們將透過第一個工作,在本程式碼研究室中深入探討這個主題。事實上,完成這個步驟後,您就差不多完成整個程式碼研究室的一半內容。這項作業會分成幾個小節,您將完成下列所有事項:
- 建立新的 Google Apps Script 專案
- 啟用 BigQuery 進階服務存取權
- 前往開發編輯器,輸入應用程式原始碼
- 完成應用程式授權程序 (OAuth2)
- 執行會將要求傳送至 BigQuery 的應用程式
- 查看使用 BigQuery 結果建立的全新 Google 試算表
設定
- a) 前往
script.google.com
建立新的 Apps Script 專案。G Suite 產品線有許多不同版本,建立新專案的方式可能因版本而異。如果您只是使用 Gmail 帳戶,且是專案開發新手,畫面上會顯示空白畫面,以及建立第一個專案的按鈕:
b) 否則,您可能會在左上角看到所有專案和大型「+New」 按鈕,請點選該按鈕。
c) 如果上述兩種情況都不符合,畫面可能如下所示。如果是,請在左上角尋找漢堡選單圖示,然後選取「+ 新指令碼」。
d) 如果您偏好使用指令列,您要使用的工具是 clasp
,具體來說,您將執行 clasp create
指令。
e) 建立新指令碼專案的最後一種方式,就是前往捷徑連結:https://script.google.com/create。
- 無論您使用哪種技術啟動新專案,最終都應該會進入 Apps Script 程式碼編輯器,畫面如下所示:
- 依序點選「File」>「Save」,然後為專案命名。
- 接著,您需要建立 Google Cloud 控制台專案,才能執行 BigQuery 查詢。
- 建立新專案、命名、選取帳單帳戶,然後按一下「建立」。
- 專案建立完成後,頁面右上角會顯示通知。按一下「建立專案:<專案名稱>」項目,開啟專案。
- 按一下左上方的選單圖示
,然後前往「API 和服務」>「憑證」。按一下「OAuth 同意畫面」分頁 (直接連結)。
- 在「Application name」(應用程式名稱) 欄位中輸入「Big Data Codelab」,然後按一下底部的「Save」(儲存) 按鈕。
- 按一下右上角的三點圖示
展開選單,然後選取「專案設定」 (直接連結)。
- 複製「專案編號」下方列出的值。(我們會在程式碼研究室的後續步驟中,使用另一個「產品 ID」欄位)。
- 返回 App Script 編輯器,然後依序點選「Resources」>「Cloud Platform project」。
- 在文字方塊中輸入專案編號,然後按一下「設定專案」。系統提示時,按一下「確認」。
- 完成後,按一下「關閉」按鈕即可關閉對話方塊。
- 現在您已設定新專案,需要啟用 BigQuery 進階服務,因此請下拉「資源」->「進階 Google 服務」,然後將 BigQuery API 的位元開啟。
- 底部的附註會顯示「必須在『Google Cloud Platform API 資訊主頁』中一併啟用這些服務」,因此請點選該連結,在另一個瀏覽器分頁中開啟開發人員控制台 (簡稱「devconsole」)。
- 在開發人員控制台中,按一下頂端的「+ 啟用 API 和服務」按鈕,搜尋「bigquery」,選取 BigQuery API (不是 BigQuery Data Transfer API),然後按一下「啟用」開啟。請保持開啟這個瀏覽器分頁。
注意:啟用 API 後,您可能會在這個頁面上看到類似「如要使用這個 API,您必須建立憑證...」的附註,但請暫時不必擔心,Apps Script 會為您處理這個步驟。 - 返回程式碼編輯器瀏覽器分頁,您仍處於「進階 Google 服務」選單,因此請按一下「確定」關閉對話方塊,然後留在程式碼編輯器中。按一下頂端的專案名稱,然後將專案命名為「BigQuery 試用」或類似名稱 (我們將專案命名為「final mile」)。
現在您已準備好輸入應用程式程式碼、完成授權程序,並讓這個應用程式的第一個版本運作。
上傳並執行應用程式
- 複製下方方塊中的程式碼,然後貼到程式碼編輯器中,覆寫所有內容:
// 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 公開資料集的一部分),並產生他所有作品中最常出現的 10 個字詞,依熱門程度降序排序。想像一下手動執行這項作業有多麼無趣,您應該就能瞭解 BigQuery 的實用性。
- 我們即將準備好試試這項功能,如這個程式碼片段頂端附近所示,您必須提供有效的專案 ID,因此請將您的專案 ID 新增至應用程式程式碼。如要取得這項資訊,請返回開發人員主控台頁面的瀏覽器視窗或分頁。(我們請你保持開啟狀態,還記得嗎?)
- 在 Google 帳戶顯示圖片左側的頂端,有一個下拉式選單選取器 (
)。按一下並選取「專案設定」。畫面上會顯示專案名稱、ID 和編號。複製專案 ID,並將
bq-sheets-slides.js
頂端的PROJECT_ID
變數設為您從開發人員控制台取得的值。注意:如果選單選取器無法移動且無法操作,請重新載入頁面。 if
陳述式可防止應用程式在沒有專案 ID 的情況下繼續執行。新增完成後,請儲存檔案,然後依序選取選單列中的「Run」>「Run function」>「runQuery」,點按「Review Permissions」對話方塊中的「This app is unverified」,下方的 GIF 動畫 (適用於其他應用程式) 會說明接下來的幾個步驟:- 要求審查權限後,系統會顯示新的對話方塊,如上圖所示。選擇要執行指令碼的正確 Google 帳戶,選取「進階」,向下捲動,然後按一下「前往 <您的專案名稱> (不安全)」,即可進入 OAuth2 應用程式授權畫面。(請參閱驗證程序一文,進一步瞭解為何這個畫面會出現在您和下方的 OAuth2 授權對話方塊之間。)
注意:授權應用程式後,您就不必在每次執行時重複這個程序。在本教學課程的「工作 3」之前,您不會再次看到這個對話方塊,要求使用者授權建立及管理 Google 簡報。 - 在 OAuth2 對話方塊中按一下「允許」後,指令碼就會開始執行,畫面頂端會顯示淡黃色對話方塊。這項作業的執行速度相當快,因此您可能不會注意到作業正在執行或已完成。
- 完成後,該對話方塊就會消失。如果沒有看到,表示作業可能已完成,請前往 Google 雲端硬碟 (
drive.google.com
),尋找名為「Most common words in all of Shakespeare's works」(莎士比亞所有作品中最常見的字詞) 的新 Google 試算表,或您指派給QUERY_NAME
變數的名稱: - 開啟試算表,您應該會看到 10 列字詞,以及依遞減順序排序的總計次數:
工作 1 摘要
您剛才執行了一些程式碼,查詢了所有莎士比亞作品 (資料量不算龐大,但肯定比您自己逐字掃描每部戲劇、管理這些字詞的計數,然後依出現次數遞減排序還要多)。您不僅要求 BigQuery 代表您執行這項操作,還能使用 Google 試算表的 Apps Script 內建服務,將資料放入試算表,方便您使用。
您在上方貼上的 bq-sheets-slides.js
程式碼 (我們選擇的檔案名稱) (除了 PROJECT_ID
應具有實際專案 ID 之外),也可以在 github.com/googlecodelabs/bigquery-sheets-slides 的本程式碼研究室 GitHub 存放區中,找到 step1
資料夾。這段程式碼的靈感來自 BigQuery 進階服務頁面中的原始範例,該範例執行的查詢略有不同,目的是找出莎士比亞最常使用的字詞 (長度為 10 個字元以上)。您也可以在 GitHub 存放區中查看該範例。
如要查詢莎士比亞作品或其他公開資料表,請參閱這個網頁和這個網頁。無論使用哪種查詢,您一律可以在 BigQuery 控制台中測試查詢,再於 Apps Script 中執行。開發人員可透過 bigquery.cloud.google.com 使用 BigQuery 的使用者介面。舉例來說,以下是使用 BigQuery UI 查詢的樣子:
上述步驟使用 Apps Script 的程式碼編輯器,您也可以選擇透過指令列在本機開發。您也可以建立名為 bq-sheets-slides.js
的指令碼,將上述程式碼貼入其中,然後使用 clasp push
指令上傳至 Google。(如果您先前錯過,這裡再次提供 clasp
的連結和使用方式)。
runQuery()
的用途是與 BigQuery 通訊,並將結果傳送至試算表。現在我們需要使用資料製作圖表。讓我們建立名為 createColumnChart()
的新函式,呼叫 Sheet 的 newChart()
方法來執行這項操作。
- 建立圖表。在
runQuery()
後方新增下方顯示的createColumnChart()
主體。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);
}
- 返回試算表。如上所示,
createColumnChart()
需要試算表物件,因此我們需要更新runQuery()
以傳回spreadsheet
物件,以便傳遞至createColumnChart()
。成功建立 Google 試算表並記錄後,請在runQuery()
結尾處 (記錄行之後) 傳回spreadsheet
物件:
Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());
// NEW: Return the spreadsheet object for later use.
return spreadsheet;
}
- 駕駛
createBigQueryPresentation()
功能。從邏輯上區隔 BigQuery 和圖表建立功能是個好主意。現在,請建立createBigQueryPresentation()
函式來驅動應用程式,並呼叫runQuery()
和createColumnChart()
。您新增的程式碼應如下所示:
/**
* Runs a BigQuery query, adds data and a chart in a Sheet.
*/
function createBigQueryPresentation() {
var spreadsheet = runQuery();
createColumnChart(spreadsheet);
}
- 讓程式碼更易於重複使用。您已完成上述 2 個重要步驟:傳回試算表物件,以及建立驅動函式。如果同事想重複使用
runQuery()
,但不希望系統記錄網址,該怎麼辦?為了讓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);
}
儲存檔案,然後前往程式碼編輯器頂端,切換為執行 createBigQueryPresentation()
,而非 runQuery()
。執行後,您會取得另一個 Google 試算表,但這次試算表中的資料旁會顯示圖表:
本程式碼研究室的最後一部分,是建立新的 Google 簡報,在標題投影片上填入標題和副標題,然後新增 2 張投影片,分別用於資料儲存格和圖表。
- 製作簡報。投影片組的所有作業都會在
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');
- 新增資料表。
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]));
}
}
- 匯入圖表。
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;
}
- 退貨圖表。現在最終函式已完成,請再次查看其簽章。是,
createSlidePresentation()
需要試算表和圖表物件。我們已調整runQuery()
,傳回Spreadsheet
物件,但現在需要對createColumnChart()
進行類似變更,傳回圖表 (EmbeddedChart
) 物件。返回應用程式的程式碼,在createColumnChart()
結尾新增最後一行程式碼:
// NEW: Return chart object for later use
return chart;
}
- 更新
createBigQueryPresentation()
。由於createColumnChart()
會傳回圖表,因此我們需要將該圖表儲存至變數,然後將試算表和圖表一併傳遞至createSlidePresentation()
。由於我們已記錄新建立的試算表網址,現在也來記錄新投影片簡報的網址。更新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
}
- 儲存並再次執行
createBigQueryPresentation()
。不過,在執行這項操作之前,請注意,您的應用程式現在需要使用者授予另一組權限,才能檢視及管理 Google 簡報。授予這項權限後,應用程式就會照常運作。 - 現在除了建立的試算表外,您也應該會取得新的 Google 簡報,其中包含 3 張投影片 (標題、資料表、資料圖表),如下所示:
恭喜!您現在已建立應用程式,透過執行 Google BigQuery 要求 (查詢其中一個公開資料集)、建立新 Google 試算表來儲存結果、根據剛擷取的資料新增圖表,以及建立 Google 簡報來呈現結果和試算表中的圖表,充分運用 Google Cloud 的兩端功能。
這就是您在技術上所做的。廣義來說,您已從大數據分析轉為可向利害關係人呈現的內容,而且全都是以程式碼自動完成。希望這個範例能激發您的靈感,並根據自己的專案進行調整。本程式碼研究室結束時,我們會提供一些建議,說明如何進一步強化這個範例應用程式。
完成上述變更後 (再次排除 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());
}
在本程式碼研究室中,「第二個檔案」是 Apps Script 資訊清單檔案 appsscript.json
,但不會扮演任何角色。如要存取,請前往程式碼編輯器瀏覽器分頁,然後從頂端選單依序選取「View」>「Show manifest file」。內容應如下所示:
appsscript.json
{
"timeZone": "America/Los_Angeles",
"dependencies": {
"enabledAdvancedServices": [{
"userSymbol": "BigQuery",
"serviceId": "bigquery",
"version": "v2"
}]
},
"exceptionLogging": "STACKDRIVER"
}
資訊清單檔案是系統層級的設定檔,Apps Script 會根據這個檔案,判斷應用程式可用的執行環境。本程式碼研究室不會涵蓋資訊清單檔案的內容,但您可以瞭解其用途。
下方提供其他資源,協助您深入瞭解本程式碼研究室涵蓋的內容,並探索以程式輔助方式存取 Google 開發人員工具的其他方法。我們會盡量讓本程式碼研究室與存放區保持同步。
這個應用程式的資源
- 本程式碼研究室的連結:g.co/codelabs/bigquery-sheets-slides
- 原始碼repo
- 開發人員影片和網誌文章
- 2018 年 Google Cloud NEXT 大會講座
說明文件
- Google Apps Script 說明文件網站
- Apps Script 試算表服務
- Apps Script Slides 服務
- Apps Script BigQuery 進階服務
相關影片和一般影片
- 其他 Google (Apps) 密鑰?(Apps Script 簡介影片)
- 從試算表存取 Google 地圖?(影片)
- Google Apps Script 影片庫
- Launchpad 線上影片系列 (前身為...)
- G Suite 開發人員節目影片系列
相關和一般新聞與最新消息
- BigQuery 適用的 Google 試算表資料連接器 (公告)
- Google BigQuery 與 Google 雲端硬碟整合 (link1、link2)
- Google 開發人員網誌
- Google Cloud Platform 網誌
- Google Cloud 大數據和機器學習網誌
- Google Developers Twitter 帳戶 (@GoogleDevs)
- G Suite 開發人員網誌
- G Suite 開發人員 Twitter (@googleworkspace)
- G Suite 開發人員每月電子報
其他程式碼研究室
入門
- [REST API] G Suite 和 Google API (Drive API)
- [應用程式製作工具] 在應用程式製作工具中建構資料庫網頁應用程式
中級
- [Apps Script] CLASP Apps Script 指令列工具
- [Apps Script] Gmail 外掛程式
- [Apps Script] 文件外掛程式和 GCP Natural Language API
- [Apps Script] Hangouts Chat 機器人架構
- [REST API] 自訂報表工具 (Sheets API)
- [REST API] Github 授權 BigQuery 分析器專用的自訂投影片產生器 (Slides+BigQuery API)
參考應用程式
- Markdown 轉 Google 簡報轉換器 (Slides API)
以下是各種「程式碼挑戰」,您可以透過不同方式,強化或擴增我們在本程式碼研究室中建構的範例。這份清單並非詳盡無遺,但應該能提供一些靈感,協助您採取下一步行動。
- 應用程式。不想受限於 JavaScript 或 Apps Script 施加的限制嗎?將這個應用程式移植到您慣用的程式設計語言,並使用 Google BigQuery、試算表和簡報的 REST API。
- BigQuery:請嘗試對莎士比亞資料集使用其他查詢,或許能找到您感興趣的查詢。如需其他查詢範例,請參閱原始的 Apps Script BigQuery 範例應用程式。
- BigQuery:試用其他 BigQuery 公開資料集...或許能找到對您更有意義的資料集。
- BigQuery:我們稍早提到,您可以嘗試查詢莎士比亞的作品或其他公開資料表,現在想再次分享這個網頁和這個網頁。
- 試算表。嘗試其他圖表類型。
- Google 試算表和 BigQuery。反過來想,您可能在某個試算表中擁有大型資料集。2016 年,BigQuery 團隊推出這項功能,讓開發人員能使用試算表做為資料來源 (詳情請參閱第一篇和第二篇網誌文章)。
- 簡報。在生成的簡報中新增其他投影片,例如與大數據分析相關的圖片或其他資產。請參閱這份指南,瞭解如何開始使用簡報內建服務。
- G Suite。透過 Apps Script 尋找其他 G Suite 或 Google 內建服務的用途,例如 Gmail、Google 雲端硬碟、日曆、文件、地圖、Analytics、YouTube 等,以及其他進階服務。如要瞭解內建和進階服務,請參閱參考資料總覽。