Compilazione dei valori mancanti dalle richieste di date

Nick Mihailovski, Team API di Google Analytics – Ottobre 2009

Questo articolo illustra come rilevare e eseguire il backfill dei valori delle serie temporali mancanti nei dati restituiti dall' API di esportazione dei dati di Google Analytics.


Prima di iniziare

L'articolo presuppone che tu sappia come funziona l'API di esportazione dei dati di Google Analytics. Il codice campione è in Java, ma puoi utilizzare i concetti nel linguaggio che preferisci. Il codice di questo articolo è fornito in formato open source e può essere scaricato dall'hosting del progetto.

Dopo aver letto questo articolo, imparerai a:

  • Il trattamento delle dimensioni di data da parte dell'API Data Export di Google Analytics.
  • Come strutturare le query in modo da raggruppare i risultati e rilevare le date mancanti.
  • Come inserire i valori mancanti utilizzando Java.

Introduzione

Il confronto dei dati in un periodo di tempo fornisce un contesto. Ad esempio, affermare che un sito web ha generato entrate da 1 milione di dollari non significa molto. Tuttavia, dichiarare che le entrate di un sito web sono aumentate di 10 volte su base trimestrale o su base annua è davvero impressionante. Con l'API Google Analytics, è facile tracciare i dati nel tempo utilizzando le dimensioni ga:date, ga:day e ga:month.

Se la query utilizza solo una dimensione di data, se qualche giorno dell'intervallo di date non ha raccolto dati, l'API Google Analytics eseguirà il backfill delle date e dei valori 0 per le metriche.

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

Tuttavia, diventa difficile se esegui query sulla data insieme ad altre dimensioni. Se una delle date non contiene dati, l'API NON restituirà una voce per quella data. Passerà semplicemente alla data successiva disponibile contenente i dati.

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

Idealmente, gli analisti vorrebbero che le date mancanti di una determinata parola chiave vengano compilate come nel primo esempio sopra

Questo articolo descrive alcune best practice per il backfill pragmatico dei dati.

Contesto

Vediamo innanzitutto perché esiste questo problema. I motivi sono due.

  1. Google Analytics elabora solo i dati raccolti. Se nessuno ha visitato un sito in un determinato giorno, non ci sono dati da elaborare e non vengono restituiti.
  2. È molto difficile determinare quante dimensioni aggiuntive e quali valori devono essere utilizzati per le date senza dati.

Quindi, invece di cercare di definire un processo per regolarle tutte, l'API Google Analytics lascia l'esercizio di inserire i dati per le query che hanno più dimensioni fino allo sviluppatore. Che fortunata :)

Panoramica del programma

Ecco i passaggi per eseguire il backfill dei dati nel grafico riportato sopra.

  1. Modifica la query per assicurarti che le dimensioni siano ordinate in modo opportuno.
  2. Determinare le date previste a partire dall'intervallo di date.
  3. Ripeti l'iterazione ed esegui il backfill delle date mancanti.
  4. Inserisci i valori mancanti rimanenti.

Modifica la query

Per eseguire il backfill delle date, dobbiamo assicurarci che i dati restituiti dall'API siano in un formato che consenta di rilevare facilmente quando manca una data. Ecco una query di esempio per recuperare sia ga:keyword sia ga:date per i primi 5 giorni di marzo:

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

Una volta inviata la query all'API, i risultati conterranno un elenco di oggetti DataEntry. Ogni oggetto voce rappresenta una riga di dati e include nomi e valori di dimensioni/metriche. Poiché non è stato utilizzato alcun parametro di ordinamento, i risultati vengono restituiti in ordine arbitrario.

ga:keywordga:datega:entrances
sedia2010-03-0414
sedia2010-03-0123
tavolo2010-03-0418
tavolo2010-03-0224
sedia2010-03-0313

Per identificare facilmente le date mancanti, dobbiamo prima raggruppare tutte le dimensioni. A questo scopo, imposta il parametro di ordinamento della query sulle dimensioni utilizzate nella query originale.

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

Se aggiungi il parametro di ordinamento, l'API restituirà i risultati nell'ordine desiderato.

ga:keywordga:datega:entrances
sedia2010-03-0123
sedia2010-03-0313
sedia2010-03-0414
tavolo2010-03-0224
tavolo2010-03-0418

Il secondo passaggio consiste nell'assicurarti che, per ogni dimensione, tutte le date vengano restituite in ordine crescente. Sebbene l'API Google Analytics fornisca una serie di dimensioni relative alla data, solo ga:date può essere ordinato con precisione oltre i limiti di date (ad esempio giorni, mesi, anni). Pertanto, se vuoi eseguire il backfill delle date, assicurati che la query utilizzi la dimensione ga:date sia nelle dimensioni sia nei parametri di query di ordinamento.

Dopo l'esecuzione della query ordinata, tutte le stesse pagine di destinazione verranno restituite una accanto all'altra e le date saranno in ordine sequenziale. L'elenco di date di una singola pagina di destinazione può essere considerato come una serie temporale e, poiché sono in ordine, è molto più facile identificare le date mancanti.

Determinare le date previste

Per rilevare date mancanti, dobbiamo confrontare le date effettive restituite dall'API con le date previste in ogni serie temporale. Per capire cosa ci si aspetta:

  1. Determinare la data di inizio prevista dalla query API.
  2. Conteggio del numero di giorni previsti nell'intervallo di date della query.

Entrambi i valori possono essere utilizzati insieme per determinare ogni data prevista incrementando la data di inizio di 1 per ogni giorno nell'intervallo di date.

Determinazione della data di inizio prevista

Possiamo utilizzare il parametro di query start-date come data di inizio prevista della serie. Poiché il formato della data restituito nella risposta dell'API yyyyMMdd è diverso da quello del parametro di query yyyy-MM-dd, dobbiamo convertire il formato della data per poterlo utilizzare.

Il metodo setExpectedStartDate converte i formati delle date.

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

Conteggio del numero di giorni previsti

Per ottenere il numero di giorni nell'intervallo di date, il programma analizza le date di inizio e di fine negli oggetti Java Date. Quindi utilizza un oggetto Calendar per calcolare il tempo tra entrambe le date. Viene aggiunto un giorno alla differenza tra le date per includere il conteggio.

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

Ora abbiamo tutti i dati necessari per capire quali date mancano.

Identificare ogni serie temporale nei risultati

Una volta eseguita la query, il programma passa attraverso ogni oggetto DataEntry nella risposta dell'API. Poiché la query è stata inizialmente ordinata, la risposta avrà una serie temporale parziale per ogni parola chiave. Dobbiamo quindi trovare l'inizio di ogni serie temporale, esaminare ogni data e inserire i dati mancanti non restituiti dall'API.

Questo programma utilizza le variabili dimensionValue e tmpDimensionValue per rilevare l'inizio di ogni serie.

Ecco l'intero codice per gestire la risposta. L'inserimento dei dati mancanti è discusso di seguito.

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

Backfill eventuali date mancanti

Per ogni voce di una serie, il programma memorizza i valori delle metriche (entrate) in un ArrayList denominato row. Quando viene rilevata una nuova serie temporale, viene creata una nuova riga e la data prevista viene impostata sulla data di inizio prevista.

Quindi, per ogni voce, il programma controlla se il valore della data nella voce corrisponde alla data prevista. Se sono uguali, la metrica nella voce viene aggiunta alla riga. In caso contrario, il programma ha rilevato date mancanti che devono essere sottoposte a backfill.

Il metodo backfillRow gestisce il backfill dei dati. Accetta come parametri le date previste e trovate, nonché la riga corrente. Quindi, determina il numero di giorni tra le due date (non incluse) e aggiunge molti 0 alla riga.

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

Al termine del metodo, è stato eseguito il backfill della riga con i dati ed è possibile aggiungere i dati attuali. La data prevista viene quindi incrementata a un giorno dopo la data rilevata utilizzando il metodo 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 "";
}

Inserisci i valori rimanenti

Dopo che i dati della serie sono stati elaborati in un row, dobbiamo verificare che alla fine della serie non manchino altre date.

Il metodo forwardFillRow calcola semplicemente la differenza tra il numero di giorni nella query originale e la dimensione corrente della riga, aggiungendo molti 0 alla fine della riga.

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

A questo punto, il programma ha compilato gli eventuali valori mancanti nelle serie temporali. Ora che tutti i dati sono disponibili, il programma stampa i valori delle dimensioni e delle metriche come elenco separato da virgole.

Conclusione

Con questo esempio, puoi eseguire facilmente il backfill dei dati per date non restituite dall'API. Come accennato in precedenza, questa soluzione può essere adattata a qualsiasi linguaggio di programmazione. Gli sviluppatori possono anche adattare queste tecniche e applicarle per gestire più dimensioni e metriche. Ora è ancora più facile iniziare a eseguire analisi avanzate sulle serie temporali restituite dall'API Google Analytics.