İstek Tarihinden İtibaren Eksik Değerleri Doldurma

Nick Mihailovski, Google Analytics API Ekibi – Ekim 2009

Bu makalede, Google Analytics Data Export API'den döndürülen verilerdeki eksik zaman serisi değerlerini nasıl tespit edip dolduracağınız açıklanmaktadır.


Başlamadan Önce

Makalede, Google Analytics Dışa Veri Aktarma API'sinin işleyiş şeklini bildiğiniz varsayılmaktadır. Örnek kod Java'dadır ancak kavramları dilediğiniz dilde kullanabilirsiniz. Bu makalenin kodu açık kaynak olarak sağlanır ve proje barındırmadan indirilebilir.

Bu makaleyi okuduktan sonra şunları öğreneceksiniz:

  • Google Analytics Dışa Veri Aktarma API'sının tarih boyutlarını nasıl ele aldığı.
  • Sonuçları gruplandırmak ve eksik tarihleri algılamak için sorgularınızı nasıl yapılandırabilirsiniz?
  • Java kullanılarak eksik değerleri doldurma.

Giriş

Belirli bir zaman aralığına ait verilerin karşılaştırılması bağlam sağlar. Örneğin, bir web sitesinin 1 milyon dolar gelir kazandırdığını belirtmek pek bir şey ifade etmez. Ancak bir web sitesinin gelirini çeyrek veya yıldan yıla 10 kat artırdığını belirtmek gerçekten etkileyici. Google Analytics API ile ga:date, ga:day ve ga:month boyutlarını kullanarak zaman içindeki verileri kolayca görüntüleyebilirsiniz.

Sorgunuz yalnızca tarih boyutu kullanıyorsa, tarih aralığındaki herhangi bir gün hiç veri toplamıyorsa Google Analytics API, metrikler için tarihleri ve 0 değerlerini doldurur.

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

Ancak, tarihi diğer boyutlarla birlikte sorgularsanız karmaşık hale gelir. Tarihlerden birinde veri yoksa API, söz konusu tarih için bir giriş DÖNMEZ. Yalnızca veri içeren bir sonraki kullanılabilir tarihe atlanır.

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

Analistler, ideal olarak yukarıdaki ilk örnekte olduğu gibi, belirli bir anahtar kelime için eksik tarihlerin doldurulmasını ister.

Bu makalede, verileri pragmatik şekilde doldurmayla ilgili bazı en iyi uygulamalar açıklanmaktadır.

Arka plan

Öncelikle bu sorunun neden var olduğuna bakalım. Bunun 2 nedeni vardır.

  1. Google Analytics yalnızca toplanan verileri işler. Belirli bir günde bir siteye kimse gelmediyse işlenecek veri olmaz, dolayısıyla hiçbir veri döndürülmez.
  2. Veri içermeyen tarihler için kaç ek boyutun ve hangi değerlerin kullanılması gerektiğini belirlemek çok zordur.

Böylece Google Analytics API'si, tüm kuralları yönetecek tek bir süreç tanımlamaya çalışmak yerine, birden çok boyutu olan sorgular için veri doldurma görevini geliştiriciye bırakır. Şanslısınız :)

Programa genel bakış

Yukarıdaki grafikte verileri doldurma adımlarını aşağıda bulabilirsiniz.

  1. Boyutların uygun şekilde sıralandığından emin olmak için sorguyu değiştirin.
  2. Tarih aralığından beklenen tarihleri belirler.
  3. Eksik tarihleri yineleyin ve doldurun.
  4. Kalan eksik değerleri doldurun.

Sorguyu Değiştirme

Tarihleri doldurmak için API'den döndürülen verilerin, eksik tarih olduğunda bunu kolayca tespit etmeyi kolaylaştıran bir biçimde olduğundan emin olmamız gerekir. Aşağıda, Mart ayındaki ilk 5 gün için hem ga:keyword hem de ga:date değerinin alınmasıyla ilgili örnek bir sorgu verilmiştir:

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

Sorgu API'ye gönderildikten sonra sonuçlar DataEntry nesnelerinin bir listesini içerir. Her giriş nesnesi bir veri satırını temsil eder ve boyutlar/metrikler için adlar ve değerler içerir. Herhangi bir sıralama parametresi kullanılmadığından sonuçlar rastgele bir sırayla döndürülür.

ga:keywordga:datega:entrances
sandalye2010-03-0414
sandalye2010-03-0123
masa2010-03-0418
masa2010-03-0224
sandalye2010-03-0313

Hangi tarihlerin eksik olduğunu belirlemeyi kolaylaştırmak için öncelikle tüm boyutları birlikte gruplandırmamız gerekir. Bu, sorgunun sıralama parametresini orijinal sorguda kullanılan boyutlara ayarlayarak yapılabilir.

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

Sıralama parametresi eklendiğinde API, sonuçları istenen sırada döndürür.

ga:keywordga:datega:entrances
sandalye2010-03-0123
sandalye2010-03-0313
sandalye2010-03-0414
masa2010-03-0224
masa2010-03-0418

İkinci adım, her boyut için tüm tarihlerin artan düzende döndürülmesini sağlamaktır. Google Analytics API çok sayıda tarih boyutu sağlar, ancak yalnızca ga:date tarih sınırları içinde doğru bir şekilde sıralanabilir (ör. gün, ay, yıl). Bu nedenle, tarihleri doldurmak isterseniz sorgunuzun hem boyutlarda hem de sıralama sorgu parametrelerinde ga:date boyutunu kullandığından emin olun.

Sıralanan sorgu yürütüldüğünde, aynı açılış sayfalarının tümü yan yana döndürülür ve tarihler sıralı olarak gösterilir. Tek bir açılış sayfasındaki tarih listesi, bir zaman serisi olarak düşünülebilir ve sıralı oldukları için eksik tarihleri tespit etmek çok daha kolaydır.

Beklenen Tarihleri Belirleyin

Eksik tarihleri tespit etmek için API'den döndürülen gerçek tarihleri her zaman serisinde beklenen tarihlerle karşılaştırmamız gerekir. Aşağıdakilerden nelerin beklendiğini anlayabiliriz:

  1. Beklenen başlangıç tarihi, API sorgusundan belirleniyor.
  2. Sorgu tarih aralığındaki beklenen gün sayısını sayma.

Her iki değer de tarih aralığındaki her gün için başlangıç tarihini 1 artırarak beklenen her bir tarihi belirlemek için birlikte kullanılabilir.

Beklenen Başlangıç Tarihini Belirleme

start-date sorgu parametresini, dizinin beklenen başlangıç tarihi olarak kullanabiliriz. yyyyMMdd API yanıtında döndürülen tarih biçimi, yyyy-MM-dd sorgu parametresinin biçiminden farklı olduğundan, kullanabilmemiz için önce tarih biçimini dönüştürmemiz gerekir.

setExpectedStartDate yöntemi, tarih biçimlerini dönüştürür.

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

Beklenen Gün Sayısını Sayma

Program, tarih aralığındaki gün sayısını almak için başlangıç ve bitiş tarihlerini Java Date nesnelerine ayrıştırır. Ardından, her iki tarih arasındaki saati anlamak için bir Calendar nesnesi kullanır. Sayıyı dahil etmek için tarihlerdeki farka bir gün eklenir.

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

Artık hangi tarihlerin eksik olduğunu anlamak için ihtiyacımız olan tüm verilere sahibiz.

Sonuçlardaki Her Zaman Serisini Tanımlayın

Sorgu yürütüldüğünde, program API yanıtındaki her bir DataEntry nesnesini inceler. Sorgu başlangıçta sıralandığından, yanıtta her anahtar kelime için kısmi bir zaman serisi olur. Dolayısıyla, her zaman serisinin başlangıcını bulmamız, ardından her tarihin üzerinden geçip API tarafından döndürülmeyen eksik verileri doldurmamız gerekir.

Bu program, her bir dizinin başlangıcını algılamak için dimensionValue ve tmpDimensionValue değişkenlerini kullanır.

Yanıtı işlemek için gereken kodun tamamı aşağıda verilmiştir. Eksik verilerin doldurulması aşağıda açıklanmaktadır.

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

Eksik Tarihleri Doldurun

Program, bir serideki her giriş için metrik değerlerini (girişler) row adlı bir ArrayList içinde depolar. Yeni bir zaman serisi algılandığında yeni bir satır oluşturulur ve beklenen tarih, beklenen başlangıç tarihine ayarlanır.

Program, her bir giriş için, girişteki tarih değerinin beklenen tarihe eşit olup olmadığını kontrol eder. Bunlar eşitse girişteki metrik satıra eklenir. Aksi takdirde, program, doldurulması gereken tarihlerin eksik olduğunu tespit etmiştir.

backfillRow yöntemi, verileri doldurmayı işler. Mevcut satırın yanı sıra beklenen ve bulunan tarihleri parametre olarak kabul eder. Daha sonra, iki tarih arasındaki gün sayısını (dahil olmayan) belirler ve satıra birçok 0 ekler.

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

Yöntem tamamlandığında, satır verilerle doldurulur ve mevcut veriler eklenebilir. Daha sonra, beklenen tarih getNextDate yöntemi kullanılarak, bulunan tarihten bir gün sonrasına artırılır.

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

Kalan Değerleri Doldurun

Seri verileri row olarak işlendikten sonra, serinin sonunda başka eksik tarih olup olmadığını kontrol etmemiz gerekir.

forwardFillRow yöntemi, orijinal sorgudaki gün sayısı ile satırın mevcut boyutu arasındaki farkı hesaplar ve bu sayıyı satırın sonuna ekler.

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

Program bu noktada, zaman serisindeki eksik değerleri doldurmuştur. Artık tüm verilere sahip olduğumuza göre, program, boyut ve metrik değerlerini virgülle ayrılmış bir liste olarak yazdırır.

Sonuç

Bu örneği kullanarak, API tarafından döndürülmeyen tarihlere kolayca veri doldurabilirsiniz. Yukarıda belirtildiği gibi bu çözüm herhangi bir programlama diline uyarlanabilir. Hatta geliştiriciler bu teknikleri uyarlayabilir ve birden fazla boyutu ve metriği yönetmek için uygulayabilir. Google Analytics API tarafından döndürülen zaman serileri üzerinde gelişmiş analiz yapmaya başlamak artık her zamankinden daha kolay.