Data Export API से CSV फ़ॉर्मैट में डेटा आउटपुट करना

एलेक्ज़ेंडर लुकास, Google Analytics API टीम – अगस्त 2010


शुरुआती जानकारी

इस लेख में Google Analytics Data Export API में की गई किसी भी क्वेरी से डेटा लेने और नतीजों को लोकप्रिय CSV फ़ॉर्मैट में पाने का तरीका बताया गया है. यह Data Export API से लिए गए Analytics डेटा के ज़रिए किए जाने वाले लोगों के सबसे सामान्य कामों में से एक है. इसलिए, इस प्रोसेस को ऑटोमेट करना, समय-समय पर बहुत सारा समय बचाने का आसान तरीका है. साथ ही, जब आपके पास क्वेरी से CSV दस्तावेज़ों को प्रिंट करने के लिए कुछ कोड होंगे, तब आप उन्हें बड़े प्रोजेक्ट, जैसे अपने-आप रिपोर्ट जनरेट करने वाले टूल, मेलर, और अपने लिखे कस्टम डैशबोर्ड के लिए "एक्सपोर्ट" फ़ंक्शन में इंटिग्रेट कर सकेंगे.

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

अगर आपके पास ये चीज़ें हैं, तो आपको इस लेख से ज़्यादा से ज़्यादा फ़ायदा मिलेगा:

  • Java पर काम करने की जानकारी.
  • Google Analytics पर काम करने की जानकारी, जिसमें डाइमेंशन और मेट्रिक की समझ शामिल होती है.
  • असली डेटा वाले किसी चालू Google Analytics खाते को ऐक्सेस किया जा सकता है.
  • डेटा एक्सपोर्ट एपीआई की Java शुरू करने की गाइड देखें. इस लेख में यह मान लिया गया है कि आपको इस गाइड में शामिल सभी चीज़ों के बारे में पहले से जानकारी है.
  • पूरे सोर्स कोड की एक लोकल कॉपी, जो आपको AnalyticsCvsPrinter.java पर मिल सकती है. इस कोड का इस्तेमाल करने वाला एक सैंपल ऐप्लिकेशन, AnalyticsCsvDemo.java पर देखा जा सकता है.

प्रोग्राम की खास जानकारी

इस लेख में दिए गए कोड का इस्तेमाल करके ये काम किए जा सकते हैं:

  1. रनटाइम के दौरान यह चुनने की सुविधा चालू करें कि कोड, कंसोल पर प्रिंट किया जाता है या फ़ाइल स्ट्रीम पर.
  2. पैरामीटर के तौर पर DataFeed ऑब्जेक्ट दिए जाने पर, डेटा को CSV फ़ॉर्मैट में प्रिंट करें:
    • पंक्ति हेडर प्रिंट करें.
    • डेटा की पंक्तियां प्रिंट करें, जहां हर DataEntry से नतीजे में एक पंक्ति बनेगी.
    • CSV फ़ाइल से सुरक्षित आउटपुट के लिए, हर वैल्यू को सैनिटाइज़ करने के तरीके से चलाएं.
  3. ऐसा "Sanitizer" मेथड लिखें जो सभी इनपुट को CSV-सुरक्षित बनाता हो.
  4. आपको कोई Java क्लास उपलब्ध कराई जाती है, जो किसी भी डेटा एक्सपोर्ट एपीआई क्वेरी को ले सकती है और उसे CSV फ़ाइल में बदल सकती है.

वापस सबसे ऊपर जाएं

कॉन्फ़िगर करने लायक आउटपुट स्ट्रीम की अनुमति दें

इसके लिए सबसे पहले, अपनी क्लास के लिए कॉन्फ़िगर की जा सकने वाली एक आउटपुट स्ट्रीम सेट अप करें, ताकि आप प्रिंट कर सकें. इस तरह आपकी क्लास का इस्तेमाल करने वाला कोई भी कोड यह तय कर सकता है कि आउटपुट स्टैंडर्ड आउट पर जाए या सीधे फ़ाइल पर. आपको यहां बस किसी PrintStream ऑब्जेक्ट के लिए गेटर/सेटर तरीका सेट अप करना है. यह क्लास की सभी प्रिंटिंग का टारगेट होगा.

private PrintStream printStream = System.out;

public PrintStream getPrintStream() {
  return printStream;
}

public void setPrintStream(PrintStream printStream) {
  this.printStream = printStream;
}

आउटपुट को किसी फ़ाइल में सेट करना भी बहुत आसान है. किसी फ़ाइल के लिए PrintStream ऑब्जेक्ट बनाने के लिए, आपको सिर्फ़ फ़ाइल नाम की ज़रूरत होती है.

FileOutputStream fstream = new FileOutputStream(filename);
PrintStream stream = new PrintStream(fstream);
csvprinter.setPrintStream(stream);

वापस सबसे ऊपर जाएं

डेटा का इस्तेमाल करना

CSV फ़ाइल की पहली पंक्ति, कॉलम के नामों की लाइन होती है. हर कॉलम डेटा फ़ीड से एक डाइमेंशन या मेट्रिक दिखाता है, इसलिए इस पहली पंक्ति को प्रिंट करने के लिए, नीचे दिया गया तरीका अपनाएं.

  1. फ़ीड से पहली एंट्री चुनें.
  2. उस एंट्री के getDimensions तरीके का इस्तेमाल करके, डाइमेंशन की सूची से फिर से दोहराएं.
  3. Dimension.getName() तरीके का इस्तेमाल करके, हर डाइमेंशन का नाम प्रिंट करें और उसके बाद कॉमा लगाएं.
  4. getMetrics() तरीके का इस्तेमाल करके, मेट्रिक के लिए भी यही करें. आखिरी मेट्रिक को छोड़कर, कॉमा को प्रिंट करें.

यहां पंक्ति हेडर को प्रिंट करने के लिए एक तरीका बताया गया है. ध्यान दें कि यह कोड पूरी लाइन को दिखाने वाली स्ट्रिंग नहीं दिखाता है: यह वैल्यू को प्रोसेस करने वाले आउटपुट स्ट्रीम में प्रिंट करता है.

public void printRowHeaders(DataFeed feed) {
    if(feed.getEntries().size() == 0) {
      return;
    }

    DataEntry firstEntry = feed.getEntries().get(0);

    Iterator<Dimension> dimensions = firstEntry.getDimensions().iterator();
    while (dimensions.hasNext()) {
      printStream.print(sanitizeForCsv(dimensions.next().getName()));
      printStream.print(",");
    }

    Iterator<Metric> metrics = firstEntry.getMetrics().iterator();
    while (metrics.hasNext()) {
      printStream.print(sanitizeForCsv(metrics.next().getName()));
      if (metrics.hasNext()) {
        printStream.print(",");
      }
    }
    printStream.println();
  }

CSV फ़ाइल के "मुख्य हिस्से" को प्रिंट करना (कॉलम के नामों की पंक्ति के नीचे सभी चीज़ें) प्रिंट करने का तरीका काफ़ी मिलता-जुलता है. इसमें सिर्फ़ दो मुख्य अंतर हैं. पहली बात, यह सिर्फ़ पहली एंट्री का आकलन नहीं है. फ़ीड ऑब्जेक्ट में कोड को सभी एंट्री के ज़रिए लूप में होना चाहिए. दूसरा, वैल्यू को सैनिटाइज़ और प्रिंट करने के लिए, getName() तरीके का इस्तेमाल करने के बजाय, getValue() का इस्तेमाल करें.

public void printBody(DataFeed feed) {
    if(feed.getEntries().size() == 0) {
      return;
    }

    for (DataEntry entry : feed.getEntries()) {
      printEntry(entry);
    }
  }

  public void printEntry(DataEntry entry) {
    Iterator<Dimension> dimensions = entry.getDimensions().iterator();
    while (dimensions.hasNext()) {
      printStream.print(sanitizeForCsv(dimensions.next().getValue()));
      printStream.print(",");
    }

    Iterator<Metric> metrics = entry.getMetrics().iterator();
    while (metrics.hasNext()) {
      printStream.print(sanitizeForCsv(metrics.next().getValue()));
      if (metrics.hasNext()) {
        printStream.print(",");
      }
    }
    printStream.println();
  }

यह कोड आपके फ़ीड को एंट्री में बांट देता है और आपकी एंट्री, आउटपुट में प्रिंट की जाने वाली वैल्यू में बदल जाता है. लेकिन हम उन वैल्यू को CSV-फ़्रेंडली कैसे बनाते हैं? अगर "कॉमा-सेपरेटेड-वैल्यू" फ़ाइल की किसी वैल्यू में कॉमा हो, तो क्या होगा? उन वैल्यू को साफ़ करना ज़रूरी है.

वापस सबसे ऊपर जाएं

CSV के साथ काम करने के लिए, डेटा को सैनिटाइज़ करने का तरीका

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

अफ़सोस की बात यह है कि इस आसान फ़ॉर्मैट की मदद से, गलत डेटा का इस्तेमाल करके धोखा देना बहुत आसान हो जाता है. अगर आपकी वैल्यू में कॉमा है, तो क्या होगा? अगर आपकी किसी वैल्यू में लाइन ब्रेक हैं, तो क्या होगा? कॉमा और वैल्यू के बीच स्पेस होने पर क्या होना चाहिए? इन सभी स्थितियों को समझने के लिए, कुछ आसान नियमों का इस्तेमाल किया जा सकता है.

  • अगर स्ट्रिंग में डबलकोट वर्ण है, तो उसे एक दूसरे डबलकोट वर्ण से एस्केप करें.
  • अगर स्ट्रिंग में कॉमा है, तो पूरी स्ट्रिंग को डबल कोट में रखें (अगर आपने पहले से ऐसा न किया हो).
  • अगर स्ट्रिंग में लाइन ब्रेक है, तो पूरी स्ट्रिंग को डबल कोट में रखें (अगर आपने पहले से ऐसा न किया हो).
  • अगर स्ट्रिंग की शुरुआत या अंत में किसी तरह की खाली जगह है, तो पूरी स्ट्रिंग को डबल कोट में रखें (अगर आपके पास पहले से कोई खाली जगह न हो).

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

पहले बाद में
अपरिवर्तित अपरिवर्तित
रैंडम " डबलकोट रैंडम "" डबलकोट
कॉमा,अलग किए गए "कॉमा,अलग किए गए"
दो
लाइन
"दो
लाइन"
_लीडिंग स्पेस और एक कॉमा "_लीडिंग स्पेस और एक कॉमा"
"सबसे पहले कोट, कॉमा """मुख्य उद्धरण, कॉमा"
_space, कॉमा
, और डबल कोट"
"_space, कॉमा
, और डबल कोट""

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

private String sanitizeForCsv(String cellData) {
  StringBuilder resultBuilder = new StringBuilder(cellData);

  // Look for doublequotes, escape as necessary.
  int lastIndex = 0;
  while (resultBuilder.indexOf("\"", lastIndex) >= 0) {
    int quoteIndex = resultBuilder.indexOf("\"", lastIndex);
    resultBuilder.replace(quoteIndex, quoteIndex + 1, "\"\"");
    lastIndex = quoteIndex + 2;
  }

  char firstChar = cellData.charAt(0);
  char lastChar = cellData.charAt(cellData.length() - 1);

  if (cellData.contains(",") || // Check for commas
      cellData.contains("\n") ||  // Check for line breaks
      Character.isWhitespace(firstChar) || // Check for leading whitespace.
      Character.isWhitespace(lastChar)) { // Check for trailing whitespace
      resultBuilder.insert(0, "\"").append("\""); // Wrap in doublequotes.
  }
    return resultBuilder.toString();
}

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

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

ध्यान दें कि ऊपर दिया गया यूआरएल, StringBuilder ऑब्जेक्ट का इस्तेमाल करता है. इसमें कभी भी रॉ स्ट्रिंग में सीधे तौर पर बदलाव नहीं किया जाता. ऐसा इसलिए होता है, क्योंकि StringBuilder की मदद से, मेमोरी में अंतरिम कॉपी बनाए बिना, स्ट्रिंग में आसानी से बदलाव किया जा सकता है. Java की स्ट्रिंग में बदलाव नहीं किया जा सकता, इसलिए आपके हर छोटे से ट्वीक से एक बिलकुल नई स्ट्रिंग बन जाएगी. स्प्रेडशीट से डेटा फ़ेच करने पर, यह डेटा बहुत तेज़ी से इकट्ठा होता है.

पंक्तियों की संख्या x पंक्ति प्रति मान x वैल्यू में बदलाव = बनाई गई कुल नई स्ट्रिंग
10,000 10 3 3,00,000

वापस सबसे ऊपर जाएं

आगे क्या करें?

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

  • ऐप्लिकेशन सोर्स कोड का सैंपल देखें, जो इस क्लास का इस्तेमाल करके, किसी सैंपल क्वेरी के आधार पर CSV फ़ाइल को प्रिंट करता है. यह आउटपुट फ़ाइल नाम को कमांड लाइन पैरामीटर के तौर पर लेता है और डिफ़ॉल्ट रूप से स्टैंडर्ड फ़ॉर्मैट में प्रिंट करता है. इसका इस्तेमाल शुरुआत करने के लिए करें और कुछ बेहतरीन बनाएं!
  • CSV कई लोकप्रिय फ़ॉर्मैट में से एक है. आउटपुट के लिए, क्लास को TSV, YAML, JSON या एक्सएमएल जैसे किसी दूसरे फ़ॉर्मैट में ट्वीक करें.
  • एक ऐसा ऐप्लिकेशन लिखें जो CSV जनरेट करता हो और पूरा हो जाने पर उन्हें मेल करता हो. हर महीने अपने-आप होने वाली रिपोर्टिंग की सुविधा!
  • अपने डेटा को बेहतर तरीके से समझने के लिए, एक ऐसा ऐप्लिकेशन लिखें जो आपको इंटरैक्टिव तरीके से क्वेरी डालने की सुविधा देता हो.