तारीख के अनुरोध में मौजूद मान नहीं भरना

संग्रह की मदद से व्यवस्थित रहें अपनी प्राथमिकताओं के आधार पर, कॉन्टेंट को सेव करें और कैटगरी में बांटें.

निक मिहैलोस्की, Google Analytics API टीम – अक्टूबर 2009

इस लेख में, Google Analytics Data Export API से मिले डेटा में, टाइम सीरीज़ की उन वैल्यू का पता लगाने और उन्हें बैकफ़िल करने का तरीका बताया गया है जो मौजूद नहीं हैं.


शुरू करने से पहले

इस लेख में यह बताया गया है कि Google Analytics Data Export API कैसे काम करता है. सैंपल कोड, Java में है, लेकिन आपके पास अपनी पसंदीदा भाषा में कॉन्सेप्ट का इस्तेमाल करने का विकल्प है. इस लेख का कोड ओपन सोर्स के तौर पर दिया गया है और इसे प्रोजेक्ट होस्टिंग से डाउनलोड किया जा सकता है.

इस लेख को पढ़ने के बाद, आपको ये जानकारी मिलेगी:

  • Google Analytics डेटा एक्सपोर्ट एपीआई, तारीख के डाइमेंशन का इस्तेमाल कैसे करता है.
  • अपनी क्वेरी को व्यवस्थित करने का तरीका, जिससे नतीजे ग्रुप किए जा सकते हैं. साथ ही, ऐसी तारीखों का पता कैसे लगाया जा सकता है जो मौजूद नहीं हैं.
  • Java का इस्तेमाल करके, मौजूद नहीं होने वाली वैल्यू को भरने का तरीका.

इसके बारे में जानकारी

किसी अवधि के डेटा की तुलना करने से संदर्भ मिलता है. उदाहरण के लिए, किसी वेबसाइट को 10 लाख डॉलर की आय देने का यह मतलब नहीं है. हालांकि, साल-दर-साल की तिमाही-दर-साल की आय में 10 गुना बढ़ोतरी हुई है. Google Analytics एपीआई की मदद से, समय के साथ डेटा को आसानी से ट्रैक किया जा सकता है. इसके लिए, ga:date, ga:day, और ga:month डाइमेंशन का इस्तेमाल करें.

अगर आपकी क्वेरी तारीख के डाइमेंशन का इस्तेमाल करती है, तो तारीख की सीमा में किसी भी दिन के लिए अगर शून्य डेटा इकट्ठा किया जाता है, तो Google Analytics API मेट्रिक के लिए तारीख और 0 वैल्यू बैकफ़िल करेगा.

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

हालांकि, अगर दूसरे डाइमेंशन के साथ तारीख की क्वेरी की जाए, तो यह मुश्किल हो जाती है. अगर किसी तारीख में कोई डेटा नहीं है, तो एपीआई उस तारीख के लिए एंट्री नहीं दिखाएगा. यह सिर्फ़ उस अगली तारीख पर जाएगा जिस पर डेटा मौजूद होगा.

ga:keywordga:datega:sessions
कुर्सी2010-03-0155
कुर्सी2010-03-0348

आम तौर पर, ऐनलिस्ट चाहते हैं कि ऊपर दिए गए पहले उदाहरण की तरह ही, किसी खास कीवर्ड के लिए वे तारीखें भी उपलब्ध न हों

इस लेख में, डेटा को सही तरीके से बैकफ़िल करने के कुछ सबसे सही तरीकों के बारे में बताया गया है.

बैकग्राउंड

आइए, सबसे पहले जानें कि यह समस्या क्यों है. इसकी दो वजहें हैं.

  1. Google Analytics सिर्फ़ इकट्ठा किए गए डेटा को प्रोसेस करता है. अगर किसी खास दिन पर कोई साइट नहीं आती है, तो प्रोसेस करने के लिए कोई डेटा नहीं होता है. इसलिए, कोई डेटा नहीं दिखता है.
  2. यह तय करना बहुत मुश्किल है कि जिन तारीखों में कोई डेटा नहीं है उनके लिए, कितने और डाइमेंशन का इस्तेमाल करना चाहिए.

इसलिए, Google Analytics API उन सभी क्वेरी के लिए डेटा भरने की प्रक्रिया को छोड़ देता है जिनमें डेवलपर के लिए एक से ज़्यादा डाइमेंशन होते हैं. इससे उन सभी पर नियम बनाने की कोशिश नहीं की जा सकती. आपकी किस्मत :)

कार्यक्रम का संक्षिप्त विवरण

ऊपर दिए गए चार्ट में डेटा को बैकफ़िल करने का तरीका यहां दिया गया है.

  1. क्वेरी को बदलकर यह पक्का करें कि डाइमेंशन, अवसर के हिसाब से क्रम में लगाए गए हैं.
  2. तारीख की सीमा से अनुमानित तारीख तय करें.
  3. ऐसी किसी भी तारीख को इटरेट और बैकफ़िल करना जो मौजूद नहीं है.
  4. बचे हुए किसी भी मान को भरें.

क्वेरी में बदलाव करें

तारीखों को बैकफ़िल करने के लिए, हमें यह पक्का करना होगा कि एपीआई से मिला डेटा उस फ़ॉर्मैट में हो जो तारीख के न मिलने पर आसानी से उसका पता लगा ले. यहां उदाहरण के तौर पर, मार्च में पहले पांच दिनों के लिए, 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");

एपीआई को क्वेरी भेजे जाने के बाद, नतीजों में DataEntry ऑब्जेक्ट की सूची दिखेगी. हर एंट्री ऑब्जेक्ट, डेटा की एक लाइन दिखाता है. साथ ही, इसमें डाइमेंशन/मेट्रिक के नाम और वैल्यू भी शामिल होती हैं. किसी भी क्रम वाले पैरामीटर का इस्तेमाल नहीं किया गया है, इसलिए नतीजों को आर्बिट्ररी क्रम में दिखाया जाता है.

ga:keywordga:datega:entrances
कुर्सी2010-03-0414
कुर्सी2010-03-0123
टेबल2010-03-0418
टेबल2010-03-0224
कुर्सी2010-03-0313

कौनसी तारीख मौजूद नहीं हैं, यह पता लगाने का काम आसान बनाने के लिए, हमें सबसे पहले सभी डाइमेंशन को एक साथ ग्रुप करना होगा. ऐसा करने के लिए, क्वेरी को क्रम से लगाने के पैरामीटर को मूल क्वेरी में इस्तेमाल किए गए डाइमेंशन पर सेट करें.

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

क्रम से लगाने वाला पैरामीटर जोड़ने से एपीआई, मनचाहे क्रम में नतीजे देगा.

ga:keywordga:datega:entrances
कुर्सी2010-03-0123
कुर्सी2010-03-0313
कुर्सी2010-03-0414
टेबल2010-03-0224
टेबल2010-03-0418

दूसरा कदम यह पक्का करना है कि हर डाइमेंशन के लिए, सभी तारीखें बढ़ते क्रम में दिखाई जाती हैं. Google Analytics API, तारीख के कई डाइमेंशन उपलब्ध कराता है. हालांकि, तारीख की सीमाओं (जैसे कि दिन, महीने, साल) में सिर्फ़ ga:date को सही तरीके से क्रम में लगाया जा सकता है. इसलिए, अगर आपको तारीख बैकफ़िल करनी हैं, तो पक्का करें कि आपकी क्वेरी, डाइमेंशन और क्वेरी पैरामीटर को दोनों में ga:date डाइमेंशन का इस्तेमाल करे.

क्रम से लगाई गई क्वेरी का इस्तेमाल होने पर, सभी लैंडिंग पेज एक-दूसरे के बगल में दिखने लगेंगे और तारीख क्रम में होंगी. किसी एक लैंडिंग पेज के लिए तारीखों की सूची को एक टाइम सीरीज़ के तौर पर देखा जा सकता है. ऐसा इसलिए होता है, क्योंकि वे क्रम में होती हैं. इसलिए, उन तारीखों की पहचान करना आसान होता है जो मौजूद नहीं हैं.

अनुमानित तारीखें तय करें

उन तारीखों का पता लगाने के लिए जो एपीआई के उपलब्ध नहीं हैं, हमें एपीआई से मिली तारीखों की तुलना, हर टाइम सीरीज़ की अनुमानित तारीख से करनी होगी. हमें पता है कि किसकी उम्मीद है:

  1. एपीआई क्वेरी से शुरू होने की अनुमानित तारीख तय करना.
  2. क्वेरी की तारीख की सीमा में दिनों की गिनती करना.

दोनों सीमाओं का इस्तेमाल करके, हर तारीख का पता लगाया जा सकता है. इसके लिए, तारीख की सीमा में हर दिन के लिए, शुरू होने की तारीख को 1 तक बढ़ाएं.

शुरू होने की अनुमानित तारीख तय करना

हम start-date क्वेरी पैरामीटर का इस्तेमाल, सीरीज़ की शुरू होने की तारीख के हिसाब से कर सकते हैं. एपीआई का रिस्पॉन्स 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);
  }

अब हमारे पास सभी ज़रूरी डेटा हैं जो हम यह पता करना चाहते हैं कि कौनसी तारीखें मौजूद नहीं हैं.

नतीजों में मौजूद हर टाइम सीरीज़ की पहचान करना

क्वेरी लागू होने के बाद, एपीआई रिस्पॉन्स में प्रोग्राम हर DataEntry ऑब्जेक्ट से गुज़रता है. शुरुआत में क्वेरी को क्रम से लगाया गया था, इसलिए रिस्पॉन्स में हर कीवर्ड के लिए, कुछ समय की सीरीज़ होगी. इसलिए, हमें हर टाइम सीरीज़ की शुरुआत का पता लगाना होगा. इसके बाद, हर तारीख से गुज़रते हुए, वह डेटा डालना होगा जो एपीआई ने नहीं दिया है.

यह कार्यक्रम 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);
  }
}

छूटे हुए तारीख बैकफ़िल करें

सीरीज़ में मौजूद हर एंट्री के लिए, प्रोग्राम ArrayList मेट्रिक (एंट्रेंस) को row नाम से सेव करता है. जब नई टाइम सीरीज़ का पता चलता है, तो एक नई पंक्ति बनाई जाती है और अनुमानित तारीख को शुरू होने की अनुमानित तारीख पर सेट किया जाता है.

फिर हर एंट्री के लिए, प्रोग्राम यह जांच करता है कि एंट्री की तारीख की वैल्यू, अनुमानित तारीख के बराबर है या नहीं. अगर वे बराबर होते हैं, तो एंट्री में मौजूद मेट्रिक को पंक्ति में जोड़ दिया जाता है. अगर ऐसा नहीं होता है, तो इस प्रोग्राम को ऐसी तारीखों का पता चला है जिनमें जानकारी नहीं भरी जानी चाहिए.

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

इस समय, प्रोग्राम ने टाइम सीरीज़ की ऐसी सभी वैल्यू को भर दिया है जो मौजूद नहीं हैं. अब हमारे पास सारा डेटा मौजूद है, इसलिए प्रोग्राम, डाइमेंशन और मेट्रिक की वैल्यू को कॉमा लगाकर अलग की गई सूची के तौर पर प्रिंट करता है.

नतीजा

इस नमूने का इस्तेमाल करके, आप एपीआई के ज़रिए न दी गई तारीखों के डेटा को आसानी से बैकफ़िल कर सकते हैं. जैसा कि ऊपर बताया गया है, इस तरीके का इस्तेमाल किसी भी प्रोग्रामिंग भाषा में किया जा सकता है. डेवलपर इन तकनीकों में बदलाव कर सकते हैं. साथ ही, उन्हें कई डाइमेंशन और मेट्रिक का इस्तेमाल करने के लिए लागू कर सकते हैं. Google Analytics API से मिलने वाली टाइम सीरीज़ का बेहतर विश्लेषण करना अब पहले से भी ज़्यादा आसान हो गया है.