- 使用Spark Shell進行互動式分析
- 基礎
- 更多RDD的actions
- 緩存
- 獨立運行的應用程序
- 下一步該做什麼
這個教程提供了一個使用Spark的快速介紹。我們首先會通過Spark的交互式腳本(使用Python或Scala)來介紹API,然後展示如何寫使用Java,Scala和Python去寫應用程序。更多完整的參考請參閱編程指南。
依照這個教程,首先從Spark的官網下載一個Spark的發佈包。因爲我們將不再使用HDFS(Hadoop分佈式文件系統),你可以下載任意一個版本的Hadoop包。
使用Spark Shell進行互動式分析
基礎
Spark的腳本提供了一個簡單的方式去學習API,同時也提供了一個強有力的工具去交互分析數據。無論是Scala(在Java虛擬機上運行現有的Java庫是一個很好的方式)還是Python它都可以使用。在Spark的目錄下使用下述方式開始運行:
./bin/pyspark
Spark基本的抽象是一個稱爲Resilient Distributed Dataset(RDD,彈性分佈式數據集)的分佈式集合。RDDs可以被Hadoop的InputFormats(諸如HDFS的文件等)創建,或者是由其他的RDDs轉換而來。讓我們通過Spark的源目錄裏的README文本文件來創建一個新的RDD:
>>> textFile = sc.textFile("README.md")
RDDs的actions可以返回一些值,並且transformations可以轉換成新的RDDs並返回相應的指針。讓我們開始使用幾個actions:
>>> textFile.count() # Number of items in this RDD
126
>>> textFile.first() # First item in this RDD
u'# Apache Spark'
現在讓我們使用transformation。我們將會使用transformation的filter返回一個新的RDD,這個RDD包含了README文件中的項目的子集。
>>> linesWithSpark = textFile.filter(lambda line: "Spark" in line)
我們可以把transformations和actions連在一起:
>>> textFile.filter(lambda line: "Spark" in line).count() # How many lines contain "Spark"?
15
更多RDD的actions
RDD的actions和transformations可以應用在更復雜的計算中。比如說我們想找到單詞數量最多的一行:
>>> textFile.map(lambda line: len(line.split())).reduce(lambda a, b: a if (a > b) else b)
15
首先將每行都映射到一個整數值上並創建一個新的RDD。在這個新的RDD上調用reduce找到單詞數量最大的那一行對應的那個數。map和reduce的參數是Python的匿名函數(lambdas),但是我們也可以傳遞任何我們想要傳遞的上層的Python函數。例如,我們將會定義一個max函數使代碼更容易被理解:
>>> def max(a, b):
... if a > b:
... return a
... else:
... return b
...
>>> textFile.map(lambda line: len(line.split())).reduce(max)
15
One common data flow pattern is MapReduce, as popularized by Hadoop. Spark can implement MapReduce flows easily:
MapReduce是Hadoop流行的一個通用的數據流模式。Spark可以很容易地實現MapReduce流:
>>> wordCounts = textFile.flatMap(lambda line: line.split()).map(lambda word: (word, 1)).reduceByKey(lambda a, b: a+b)
這裏我們結合了flatMap,map和reduceByKey transformations來計算文件中每個單詞的數量,它返回的RDD是一組(string, int)的鍵值對,我們可以使用collect這個行爲去統計單詞的數量:
>>> wordCounts.collect()
[(u'and', 9), (u'A', 1), (u'webpage', 1), (u'README', 1), (u'Note', 1), (u'"local"', 1), (u'variable', 1), ...]
緩存
Spark同樣支持把數據集拉取到一個集羣的內存緩存中。這在數據數據反覆被訪問的時候非常有用,例如查詢一個小的“熱”數據集或者當運行一個像網頁排名這樣的交互算法。讓我們用一個簡單的例子實現把linesWithSpark數據集標記在緩存中:
>>> linesWithSpark.cache()
>>> linesWithSpark.count()
19
>>> linesWithSpark.count()
19
通過緩存100行的文本文件去研究Spark並且看起來很傻。真正讓人感興趣的部分是這些相同的函數可以被用在一個非常龐大的數據集中,甚至在數十個或上百個節點中交叉計算。你也可以通過bin/pyspark連接到一個集羣來實現編程指南中描述的那些交互式操作。
獨立運行的應用程序
如果說現在我們想使用Spark API寫一個獨立運行的應用程序。我們將通過使用Scala(用SBT),Java(用Maven)和python寫一個簡單的應用程序來進行學習。
現在我們將展示怎麼使用Python API(PySpark)去寫一個應用程序。
這個例子我們將會創建一個簡單的Spark應用程序,SimpleApp.py:
"""SimpleApp.py"""
from pyspark import SparkContext
logFile = "YOUR_SPARK_HOME/README.md" # Should be some file on your system
sc = SparkContext("local", "Simple App")
logData = sc.textFile(logFile).cache()
numAs = logData.filter(lambda s: 'a' in s).count()
numBs = logData.filter(lambda s: 'b' in s).count()
print "Lines with a: %i, lines with b: %i" % (numAs, numBs)
這個程序只是計算文本文件中包含了‘a’和包含了‘b’的行數。你需要注意將 YOUR_SPARK_HOME 替換成你自己安裝的Spark的路徑。就像Scala和Java的例子,我們使用SparkContext去創建RDDs。我們可以傳遞Python的函數給Spark,Spark會自動地序列化任何它們引用的變量。由於應用程序會使用自定義的類或者第三方的庫,我們也可以通過它的–py-files參數將它們打包到一個.zip文件(詳細可參考spark-submit –help)中來添加代碼的一些依賴到spark-submit。SimpleApp很簡單,所以我們並不需要特別的代碼依賴。
我們可以通過bin/spark-submit運行這個應用程序:
# Use spark-submit to run your application
$ YOUR_SPARK_HOME/bin/spark-submit \
--master local[4] \
SimpleApp.py
...
Lines with a: 46, Lines with b: 23
下一步該做什麼
祝賀你的第一個Spark應用程序成功運行!
- 可以從Spark編程指南或者其他的組件開始深入瞭解API。
- 要在集羣上的運行應用程序,可以前往部署概覽
- 最後,Spark在examples目錄包含了幾個例子(Scala,Java,Python,R語言等)。你可以直接運行它們:
# For Scala and Java, use run-example:
./bin/run-example SparkPi
# For Python examples, use spark-submit directly:
./bin/spark-submit examples/src/main/python/pi.py
# For R examples, use spark-submit directly:
./bin/spark-submit examples/src/main/r/dataframe.R