Google Analytics (分析) API 團隊 Nick Mihailovski - 2009 年 10 月
本文說明如何偵測及補充 Google Analytics (分析) Data Export API 傳回的資料中缺少的時間序列值。
事前準備
本文假設您瞭解 Google Analytics (分析) 資料匯出 API 的運作方式。程式碼範例是以 Java 編寫,但您可以使用所選語言中的概念。本文的程式碼是以開放原始碼形式提供,並 從專案代管位置下載。
閱讀本文後,您將會瞭解:
- Google Analytics (分析) 資料匯出 API 如何處理日期維度。
- 如何建立查詢結構,將結果分組及偵測遺漏的日期。
- 如何使用 Java 填入遺漏的值。
簡介
比較一段時間內的資料可提供背景資訊。舉例來說,假設網站收益創造了 $100 萬美元的收益,並沒有任何意義。不過,假如網站收益逐季或年增率提高 10 倍,確實的成效確實相當出色。有了 Google Analytics API,您可以輕鬆使用 ga:date
、ga:day
和 ga:month
維度繪製長期資料。
如果查詢只使用日期維度,如果日期範圍內有任何日期收集零資料,Google Analytics (分析) API 就會補充指標的日期和 0
值。
ga:date | ga:sessions |
---|---|
2010-03-01 | 101 |
2010-03-02 | 0 |
2010-03-03 | 69 |
不過,如果您查詢日期和其他維度,資料就會變得棘手。如果其中一個日期沒有資料,API 就「不會」傳回該日期的項目。只會跳到下一個含有資料的可用日期。
ga:keyword | ga:date | ga:sessions |
---|---|---|
椅子 | 2010-03-01 | 55 |
椅子 | 2010-03-03 | 48 |
在理想的情況下,分析人員會希望特定關鍵字缺少日期填入 (如上方第一個範例所示)
本文說明實際補充資料的最佳做法。
背景
首先,我們來瞭解一下這個問題的發生原因。原因有 2 個:
- Google Analytics (分析) 只會處理收集到的資料。只要沒有人在特定日期造訪網站,就不會有可處理的資料,因此也不會傳回任何資料。
- 很難判斷在沒有資料的日期裡應使用多少額外的維度,以及該使用哪些值。
因此,Google Analytics (分析) API 不會對開發人員來說,為包含多個維度的查詢填入資料,而非嘗試定義一個程序來全部管理。Lucky You :)
計畫總覽
請按照下列步驟補充上圖中的資料。
- 修改查詢,確保維度按機會排序。
- 從日期範圍內決定預期日期。
- 反覆疊代並補充所有遺漏的日期。
- 填入所有遺漏的值。
修改查詢
如要補充日期,我們必須確保 API 傳回的資料採用易於偵測的日期格式。以下查詢範例說明如何同時擷取 3 月前 5 天的 ga:keyword
和 ga:date
:
DataQuery dataQuery = new DataQuery(new URL(BASE_URL)); dataQuery.setIds(TABLE_ID); dataQuery.setStartDate("2010-03-01"); dataQuery.setEndDate("2010-03-05"); dataQuery.setDimensions("ga:keyword,ga:date"); dataQuery.setMetrics("ga:entrances");
查詢傳送至 API 後,結果就會包含 DataEntry
物件清單。每個項目物件都代表一列資料,其中包含維度/指標的名稱和值。由於未使用排序參數,因此結果會以任意順序傳回。
ga:keyword | ga:date | ga:entrances |
---|---|---|
椅子 | 2010-03-04 | 14 |
椅子 | 2010-03-01 | 23 |
資料表 | 2010-03-04 | 18 |
資料表 | 2010-03-02 | 24 |
椅子 | 2010-03-03 | 13 |
為了輕鬆找出遺漏的日期,您必須先將所有維度分組。方法是將查詢的排序參數設為原始查詢中使用的維度。
dataQuery.setSort("ga:keyword,ga:date");
新增排序參數會讓 API 以所需順序傳回結果。
ga:keyword | ga:date | ga:entrances |
---|---|---|
椅子 | 2010-03-01 | 23 |
椅子 | 2010-03-03 | 13 |
椅子 | 2010-03-04 | 14 |
資料表 | 2010-03-02 | 24 |
資料表 | 2010-03-04 | 18 |
第二步是確保每個維度都會以遞增順序傳回所有日期。雖然 Google Analytics (分析) API 提供多種日期維度,但只有 ga:date
能在日期邊界 (即日、月、年) 中準確排序。如要補充日期,請確保查詢在維度和排序查詢參數中都使用 ga:date
維度。
執行排序後的查詢,系統會將所有相同的到達網頁並排傳回, 日期會依序傳回。單一到達網頁的日期清單可以視為時間序列,且由於按照順序排序,要辨別遺漏的日期會比較容易。
決定預期日期
為了偵測遺漏的日期,我們需要比較 API 傳回的實際日期與每個時間序列中的預期日期。我們可以透過下列方式找出預期結果:
- 從 API 查詢確定預期的開始日期。
- 計算查詢日期範圍內的預期天數。
可以在日期範圍內,將開始日期每天遞增 1,用來判斷每個預期的日期。
決定預計開始日期
我們可以使用 start-date
查詢參數,做為系列的預期開始日期。由於 API 回應 yyyyMMdd
中傳回的日期格式與查詢參數 yyyy-MM-dd
的格式不同,因此我們需要先轉換日期格式才能使用。
setExpectedStartDate
方法會轉換日期格式。
private static SimpleDateFormat queryDateFormat = new SimpleDateFormat("yyyy-MM-dd"); private static SimpleDateFormat resultDateFormat = new SimpleDateFormat("yyyyMMdd"); public void setExpectedStartDate(String startDate) { try { calendar.setTime(queryDateFormat.parse(startDate)); expectedStartDate = resultDateFormat.format(calendar.getTime()); } catch (ParseException e) { handleException(e); } }
計算預期天數
如要取得日期範圍內的天數,程式會將開始和結束日期剖析為 Java Date
物件。接著,使用 Calendar
物件判斷兩個日期之間的時間。將日期相差後的一天,讓計數包含在內。
private static final long millisInDay = 24 * 60 * 60 * 1000; public void setNumberOfDays(DataQuery dataQuery) { long startDay = 0; long endDay = 0; try { calendar.setTime(queryDateFormat.parse(dataQuery.getStartDate())); startDay = calendar.getTimeInMillis() / millisInDay; calendar.setTime(queryDateFormat.parse(dataQuery.getEndDate())); endDay = calendar.getTimeInMillis() / millisInDay; } catch (ParseException e) { handleException(e); } numberOfDays = (int) (endDay - startDay + 1); }
現在,我們已取得所有資料,因此無法判斷遺漏的日期。
找出結果中的各個時間序列
執行查詢後,程式會經歷 API 回應中的每個 DataEntry
物件。由於查詢最初是排序,因此每個關鍵字的回應都有部分時間序列。因此,我們需要找出每個時間序列的開始時間,然後逐一查看每個日期,並填入 API 未傳回的資料。
此程式會使用 dimensionValue
和 tmpDimensionValue
變數來偵測每個序列的開頭。
以下是用來處理回應的完整程式碼。以下將說明如何填寫遺漏的資料。
public void printBackfilledResults(DataFeed dataFeed) { String expectedDate = ""; String dimensionValue = ""; List<Integer> row = null; for (DataEntry entry : dataFeed.getEntries()) { String tmpDimValue = entry.getDimensions().get(0).getValue(); // Detect beginning of a series. if (!tmpDimValue.equals(dimensionValue)) { if (row != null) { forwardFillRow(row); printRow(dimensionValue, row); } // Create a new row. row = new ArrayList<Integer>(numberOfDays); dimensionValue = tmpDimValue; expectedDate = expectedStartDate; } // Backfill row. String foundDate = entry.getDimension("ga:date").getValue(); if (!foundDate.equals(expectedDate)) { backFillRow(expectedDate, foundDate, row); } // Handle the data. Metric metric = entry.getMetrics().get(0); row.add(new Integer(metric.getValue())); expectedDate = getNextDate(foundDate); } // Handle the last row. if (row != null) { forwardFillRow(row); printRow(dimensionValue, row); } }
補回任何遺漏的日期
對於系列中的每個項目,程式會將指標值 (進入) 儲存在名為 row
的 ArrayList
中。偵測到新的時間序列時,系統會建立新的資料列,並將預期日期設為預期的開始日期。
然後,程式會檢查每個項目的日期值是否等於預期日期。如果兩者相等,系統會將項目中的指標新增至資料列。否則,程式偵測到遺漏需要補充的日期。
backfillRow
方法會處理補充資料。可接受當做預期、找到日期和目前資料列的參數。接著判斷兩個日期之間的天數 (不含頭尾),並將數字 0 加到資料列中。
public void backFillRow(String startDate, String endDate, List<Integer> row) { long d1 = 0; long d2 = 0; try { calendar.setTime(resultDateFormat.parse(startDate)); d1 = calendar.getTimeInMillis() / millisInDay; calendar.setTime(resultDateFormat.parse(endDate)); d2 = calendar.getTimeInMillis() / millisInDay; } catch (ParseException e) { handleException(e); } long differenceInDays = d2 - d1; if (differenceInDays > 0) { for (int i = 0; i < differenceInDays; i++) { row.add(0); } } }
方法完成後,該資料列就會以資料補充作業,您還可以新增目前的資料。接著,預期日期會使用 getNextDate
方法,在找到日期後增加為一天。
public String getNextDate(String initialDate) { try { calendar.setTime(resultDateFormat.parse(initialDate)); calendar.add(Calendar.DATE, 1); return resultDateFormat.format(calendar.getTime()); } catch (ParseException e) { handleException(e); } return ""; }
填入所有剩餘值
將系列叢書資料處理成 row
後,我們必須檢查系列叢書末端是否沒有遺漏的日期。
forwardFillRow
方法只會計算原始查詢中天數與目前資料列大小的差距,然後將這麼多 0 秒相加至資料列末端。
public void forwardFillRow(List<Integer> row) { int remainingElements = numberOfDays - row.size(); if (remainingElements > 0) { for (int i = 0; i < remainingElements; i++) { row.add(0); } } }
此時,程式已在時間序列中填入任何遺漏的值。現在已經擁有所有資料,程式會把維度和指標值輸出為以半形逗號分隔的清單。
結論
透過這個範例,您可以輕鬆補充 API 未傳回的日期資料。如前所述,這項解決方案可以適應任何程式設計語言。開發人員甚至可以調整這些技巧,並應用這些技術來處理多個維度和多個指標。現在,您可以更輕鬆地針對 Google Analytics (分析) API 傳回的時間序列進行進階分析。