Scala: 資料的輸入與處理

以一個 parser 比較 c code 和 Scala 的差別

真的開始用 Spark 之後,才發現和原本的程式概念差很多。其中,最重要的一點,就是 Spark 是從資料 (RDD) 出發,而不是從時序運算出發。我們以以下的程式為例:

一般來說,當我們寫程式時,就是按照時序將要做的事情一行一行完成。舉例來說,我們簡單寫一個 parser,將字串切割成許多小塊來處理:

void get_tokens(char *line, char **tokens, size_t number_of_tokens)
{
    static const char *delimiter = ",";
    for (size_t i = 0; i < number_of_tokens; ++i) {
        tokens[i] = strtok(line, delimiter);
        line = NULL;
    }
}

簡單來說,上述程式就是把一個個字串依序拿進來 (藉由呼叫此函式),按照 "," 切開,之後再按照其長度放到一個叫做 tokens 的陣列中。看起來十分簡單易懂,此時的資料就像是一堆記憶體碎片般,我們可以任意地宣告、處理、 搬移。但是,在 Spark 中則不太一樣,我們以以下的程式表示:

 val readFile = sc.textFile("/home/.../file.csv")
 val tokenArray = readFile.flatMap(s => s.split(",")).map(s => s.toDouble)
 val tokenIndex = tokenArray.zipWithIndex().map(s=>(s._2,s._1))

在上述程式中,我們可發現在 Spark 中,是對資料的整體 (由 file.csv 轉出來的 RDD) 進行操作,而不是像是之前的 c code 一樣,對於每一個字串分別操作。往好處想,在 Spark 中 3 行程式碼就可以完成 parser 的功能,但是,在程式背後的邏輯,卻和原本的 c code 完全不同。

在 Spark 中,所有操作都以 RDD 為中心。第一個 RDD (readFile) 是 string array 的形式,接輸入的文字檔分行存下,第二個 RDD (tokenArray) 則是對 readFile 拆分 (split), 展開 (flatMap),轉值 (toDouble) 的結果, 我們可以看到, 以上操作,都是對整體 RDD 產生,而非單獨動作。最後,tokenIndex 則是根據 index 賦予 key 數值,並調換 (key, value) 順序。 (key, value) 的概念對 Spark 而言非常重要,之後要進行 RDD 操作時,必須依賴 (key, value) 的設定,也因此,當在進行 Spark 程式編寫時,必須預先考慮資料結構的設定,否則會難以完成。

Last updated