Fehlende Werte aus Datumsanfragen eingeben

Nick Mihailovski, Google Analytics-API-Team – Oktober 2009

In diesem Artikel wird beschrieben, wie Sie fehlende Zeitachsenwerte in Daten, die von der Google Analytics API für den Datenexport zurückgegeben werden, erkennen und Backfills ausführen können.


Vorbereitung

In diesem Artikel wird davon ausgegangen, dass Sie mit der Funktionsweise der Google Analytics-API für den Datenexport vertraut sind. Der Beispielcode ist in Java, Sie können die Konzepte jedoch in Ihrer bevorzugten Sprache verwenden. Der Code für diesen Artikel wird als Open Source bereitgestellt und kann über Project Hosting heruntergeladen werden.

In diesem Artikel erfahren Sie:

  • So werden Datumsdimensionen in der Google Analytics-API für den Datenexport behandelt.
  • So strukturieren Sie Ihre Abfragen, um Ergebnisse zu gruppieren und fehlende Datumsangaben zu erkennen.
  • So ergänzen Sie fehlende Werte mit Java.

Einleitung

Der Vergleich von Daten über einen Zeitraum bietet Kontext. Die Angabe, dass eine Website einen Umsatz von 1 Million US-Dollar generiert hat, ist beispielsweise nichts so bedeutend. Aber zu sagen, dass mit einer Website der Umsatz im Quartals- oder Jahresvergleich um das 10-Fache gesteigert wurde, ist dies in der Tat beeindruckend. Mit der Google Analytics API lassen sich Daten mithilfe der Dimensionen ga:date, ga:day und ga:month ganz einfach über einen längeren Zeitraum grafisch darstellen.

Wenn in der Abfrage nur eine Datumsdimension verwendet wird und an Tagen im Zeitraum keine Daten erfasst wurden, werden Datumsangaben und 0-Werte für Messwerte von der Google Analytics API aufgefüllt.

ga:datega:sessions
2010-03-01101
2010-03-020
2010-03-0369

Es wird jedoch schwierig, wenn Sie das Datum zusammen mit anderen Dimensionen abfragen. Wenn für einen der Datumsangaben keine Daten vorhanden sind, gibt die API KEINEN Eintrag für dieses Datum zurück. Es wird einfach zum nächsten verfügbaren Datum springen, das Daten enthält.

ga:keywordga:datega:sessions
Stuhl2010-03-0155
Stuhl2010-03-0348

Im Idealfall möchten Fachkräfte für Datenanalyse die fehlenden Daten für ein bestimmtes Keyword wie im ersten Beispiel oben ausfüllen lassen

In diesem Artikel werden einige Best Practices für das pragmatische Backfill von Daten beschrieben.

Hintergrund

Sehen wir uns zunächst an, warum dieses Problem vorliegt. Dafür gibt es zwei Gründe.

  1. In Google Analytics werden nur erhobene Daten verarbeitet. Wenn niemand an einem bestimmten Tag eine Website besucht hat, müssen keine Daten verarbeitet und somit auch nicht zurückgegeben werden.
  2. Es ist sehr schwierig zu bestimmen, wie viele zusätzliche Dimensionen und welche Werte für Zeiträume ohne Daten verwendet werden sollen.

Anstatt also einen Prozess für alle Regeln zu definieren, überlässt die Google Analytics API das Ausfüllen von Daten für Abfragen mit mehreren Dimensionen dem Entwickler. Du hast Glück :)

Programmübersicht

Führen Sie die folgenden Schritte aus, um die Daten im obigen Diagramm aufzufüllen.

  1. Ändern Sie die Abfrage, damit Dimensionen opportunistisch sortiert werden.
  2. Bestimmen Sie die erwarteten Daten aus dem Zeitraum.
  3. Iterieren Sie fehlende Daten und ergänzen Sie sie.
  4. Geben Sie alle verbleibenden fehlenden Werte ein.

Abfrage ändern

Für einen Backfill müssen die von der API zurückgegebenen Daten in einem Format vorliegen, mit dem leicht erkannt werden kann, wenn ein Datum fehlt. Hier ist eine Beispielabfrage zum Abrufen von ga:keyword und ga:date für die ersten 5 Tage im März:

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");

Sobald die Abfrage an die API gesendet wurde, enthalten die Ergebnisse eine Liste von DataEntry-Objekten. Jedes Eintragsobjekt stellt eine Datenzeile dar und enthält Namen und Werte für Dimensionen/Messwerte. Da kein Sortierparameter verwendet wurde, werden die Ergebnisse in einer beliebigen Reihenfolge zurückgegeben.

ga:keywordga:datega:entrances
Stuhl2010-03-0414
Stuhl2010-03-0123
table2010-03-0418
table2010-03-0224
Stuhl2010-03-0313

Damit Sie leichter erkennen können, welche Daten fehlen, müssen wir zuerst alle Dimensionen gruppieren. Dazu setzen Sie den Sortierparameter der Abfrage auf die Dimensionen, die in der ursprünglichen Abfrage verwendet wurden.

dataQuery.setSort("ga:keyword,ga:date");

Wenn Sie den Sortierparameter hinzufügen, gibt die API die Ergebnisse in der gewünschten Reihenfolge zurück.

ga:keywordga:datega:entrances
Stuhl2010-03-0123
Stuhl2010-03-0313
Stuhl2010-03-0414
table2010-03-0224
table2010-03-0418

Im zweiten Schritt wird sichergestellt, dass für jede Dimension alle Daten in aufsteigender Reihenfolge zurückgegeben werden. Die Google Analytics API bietet eine Reihe von Datumsdimensionen, aber nur ga:date kann über Datumsgrenzen hinweg (Tage, Monate oder Jahre) genau sortiert werden. Wenn Sie also Datumsangaben für Backfills verwenden möchten, muss in der Abfrage die Dimension ga:date sowohl in den Dimensionen als auch in den Abfrageparametern für die Sortierung verwendet werden.

Sobald die sortierte Abfrage ausgeführt wurde, werden alle gleichen Landingpages nebeneinander zurückgegeben und die Datumsangaben werden in der entsprechenden Reihenfolge angezeigt. Die Liste der Datumsangaben für eine einzelne Landingpage kann als Zeitreihe betrachtet werden. Da sie geordnet sind, ist es viel einfacher, fehlende Datumsangaben zu identifizieren.

Erwartete Termine bestimmen

Um fehlende Datumsangaben zu erkennen, müssen die von der API zurückgegebenen Datumsangaben mit den erwarteten Datumsangaben in jeder Zeitreihe verglichen werden. So können wir herausfinden, was erwartet wird:

  1. Das erwartete Startdatum aus der API-Abfrage ermitteln.
  2. Die Anzahl der erwarteten Tage im Abfragezeitraum wird ermittelt.

Beide Werte können zusammen verwendet werden, um jedes erwartete Datum zu ermitteln. Dazu wird das Startdatum für jeden Tag im Zeitraum um 1 erhöht.

Voraussichtliches Startdatum festlegen

Wir können den Abfrageparameter start-date als erwartetes Startdatum der Reihe verwenden. Da sich das in der API-Antwort yyyyMMdd zurückgegebene Datumsformat vom Format des Abfrageparameters yyyy-MM-dd unterscheidet, muss zuerst das Datumsformat konvertiert werden, bevor wir es verwenden können.

Die Methode setExpectedStartDate konvertiert die Datumsangaben.

  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);
    }
  }

Anzahl der erwarteten Tage zählen

Das Programm parst das Start- und Enddatum in Java-Date-Objekte, um die Anzahl der Tage im Zeitraum zu ermitteln. Dann wird ein Calendar-Objekt verwendet, um die Zeit zwischen beiden Datumsangaben zu ermitteln. Zur Differenz der Datumsangaben wird ein Tag addiert, damit die Anzahl berücksichtigt wird.

  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);
  }

Jetzt haben wir alle Daten, die wir benötigen, um herauszufinden, welche Daten fehlen.

Jede Zeitreihe in den Ergebnissen identifizieren

Sobald die Abfrage ausgeführt wurde, durchläuft das Programm jedes DataEntry-Objekt in der API-Antwort. Da die Abfrage anfänglich sortiert wurde, enthält die Antwort für jedes Schlüsselwort eine partielle Zeitreihe. Wir müssen also den Anfang jeder Zeitreihe finden, jedes Datum durchgehen und fehlende Daten ergänzen, die nicht von der API zurückgegeben werden.

In diesem Programm werden die Variablen dimensionValue und tmpDimensionValue verwendet, um den Beginn jeder Reihe zu erkennen.

Hier ist der gesamte Code für die Verarbeitung der Antwort. Das Ausfüllen fehlender Daten wird nachfolgend erläutert.

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);
  }
}

Fehlende Daten für Backfill

Das Programm speichert für jeden Eintrag in einer Reihe die Messwerte (Eingänge) in einer ArrayList mit dem Namen row. Wenn eine neue Zeitreihe erkannt wird, wird eine neue Zeile erstellt und das erwartete Datum wird auf das erwartete Startdatum festgelegt.

Anschließend prüft das Programm für jeden Eintrag, ob der Datumswert im Eintrag mit dem erwarteten Datum übereinstimmt. Wenn die Werte gleich sind, wird der Messwert im Eintrag der Zeile hinzugefügt. Andernfalls hat das Programm fehlende Datumsangaben gefunden, die aufgefüllt werden müssen.

Der Daten-Backfill wird von der Methode backfillRow verarbeitet. Als Parameter werden das erwartete und das gefundene Datum sowie die aktuelle Zeile akzeptiert. Dann bestimmt sie die Anzahl der Tage zwischen den beiden Datumsangaben (nicht inbegriffen) und addiert diese Anzahl von Nullen in die Zeile.

  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);
      }
    }
  }

Wenn die Methode abgeschlossen ist, wurde die Zeile mit Daten aufgefüllt und die aktuellen Daten können hinzugefügt werden. Das erwartete Datum wird dann mit der Methode getNextDate auf einen Tag nach dem gefundenen Datum erhöht.

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 "";
}

Verbleibende Werte ausfüllen

Sobald die Reihendaten in eine row verarbeitet wurden, müssen wir prüfen, ob am Ende der Reihe keine fehlenden Datumsangaben mehr fehlen.

Die Methode forwardFillRow berechnet einfach die Differenz zwischen der Anzahl der Tage in der ursprünglichen Abfrage und der aktuellen Zeilengröße und addiert diese Anzahl Nullen am Ende der Zeile.

public void forwardFillRow(List<Integer> row) {
  int remainingElements = numberOfDays - row.size();
  if (remainingElements > 0) {
    for (int i = 0; i < remainingElements; i++) {
      row.add(0);
    }
  }
}

An dieser Stelle hat das Programm alle fehlenden Werte in der Zeitreihe ergänzt. Da nun alle Daten vorliegen, gibt das Programm die Dimensions- und Messwerte als durch Kommas getrennte Liste aus.

Fazit

Mit diesem Beispiel können Sie ganz einfach ein Backfill für Daten an Tagen durchführen, die von der API nicht zurückgegeben wurden. Wie bereits erwähnt, kann diese Lösung an jede Programmiersprache angepasst werden. Entwickler können diese Verfahren sogar zur Verarbeitung mehrerer Dimensionen und Messwerte anpassen. Es ist jetzt noch einfacher als je zuvor, eine erweiterte Analyse von Zeitreihen durchzuführen, die von der Google Analytics API zurückgegeben werden.