# 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 程式編寫時，必須預先考慮資料結構的設定，否則會難以完成。
