作者:陳華勇
評審人:宋雪菲,孔慶振
近些年來,隨著互聯網技術的高速發展,數據量也在指數級增長,繼而產生了大數據。大數據數據規模巨大,數據類型多樣,產生和處理速度極快,價值巨大但是密度較低。如何使用這些大數據是近些年研究的重要內容。spark就是處理大數據的一個重要的技術。本系列文章主要由淺入深,從基礎到復雜來介紹spark技術的各個方面。
本文簡要介紹spark的基本組件,并從spark對數據的核心抽象——彈性分布式數據集(Resilient Distributed Dataset)簡稱RDD,來開始spark技術的學習。
一、spark及其組件簡介
spark是一個用來實現快速而通用的集群計算的平臺。其擴展了在大數據中廣泛使用的MapReduce計算模型,并且高效地支持更多的計算模式(例如:交互式查詢和流處理)。適用于各種各樣原先需要多種不同的分布式平臺的場景,包括批處理、迭代算法、流處理。此外,spark提供了豐富的接口,除了提供基于python、java、Scala和SQL的api以及內建的豐富的程序庫以外,還能和其他大數據工具配合使用。
總的來說,spark是一個大一統的軟件棧,包含了多個緊密集成的組件。如圖1-1所示。接下里簡單介紹部分重要組件的基本功能。
1、Spark Core
spark core實現了spark的基本功能,包括任務調度、內存管理、錯誤恢復、與存儲系統交互等模塊。
2、Spark SQL
Spark SQL是spark用來操作結構化數據的程序包。通過該組件,我們可以使用SQL或者Apache Hive的SQL方言(HQL)來查詢數據。
3、Spark Streaming
Spark Streaming是用來對實時數據進行流式計算的組件。
4、MLlib
MLlib是spark為機器學習而生成的一個程序庫。提供了多種機器學習的算法,包括分類、回歸、聚類,還提供了模型評估、數據導入等額外的支持功能。
5、GraphX
GraphX是用來處理圖數據的程序庫。
二、RDD編程
RDD(彈性分布式數據集)是spark對數據的抽象核心。在spark中,所有對數據的操作都是通過RDD來實現的。包括創建RDD、轉換已有RDD和調用RDD操作進行求值。在此過程中,用戶不需要考慮數據的集群問題,因為spark會自動地將RDD中的數據分發到集群上,并將操作并行化執行。下面主要以python3的API為例介紹RDD的創建以及基本的操作。
1、RDD創建
RDD的創建有兩種方式:在驅動程序中對一個集合進行并行化;讀取外部數據集。
將一個已有的集合傳給SparkContext的parallelize()方法就可以創建一個簡單的RDD。由于創建方式比較簡單,這種方式在學習spark的時候用的比較多。但是在開發和測試的時候使用的并不是很多。具體創建方式如例2-1所示。
** 例2-1 >>>lines=sc.parallelize(["pandas","i like pandas"])**
開發過程中使用比較多的是從外部存儲中讀取數據來創建RDD。其中讀取文本文件的方法是SparkContext的textFile()方法。創建方式如例2-2所示。
** 例2-2 >>>liens=sc.textFile("/path/example.txt")**
2、RDD操作
RDD支持兩種類型的操作:轉化操作和行動操作。其中,轉化操作是返回一個新的RDD,而行動操作是向驅動器程序返回結果或把結果寫入外部系統的操作,會觸發實際的計算。
轉化操作
轉化操作轉化出來的RDD都是惰性求值的(惰性求值會在后面詳細介紹)。只有在行動操作中的這些轉化操作才會被真正執行。注意的是,許多的轉化操作都是各個元素的,每次只會操作RDD中的一個元素。當然這得看轉化操作的具體實現。比較常見的轉化操作有:map()和filter()。下面以filter()為例介紹轉化操作。
filter()是一種篩選操作,可以將RDD中符合條件的元素提取出來生成一個新的RDD。例2-3中errorsRDD中就是從inputRDD中的篩選出有“error”字符串的行從而生成的新的RDD。注意的是,filter()操作不會改變原有的inputRDD內容,只是重新生成了一個RDD。
例2-3
>>>inputRDD=sc.textFile("log.txt")
>>>errorsRDD=inputRDD.filter(lambda x: "error" in x)
行動操作
行動操作需要生成實際的輸出,它會強制執行那些求值必須用到的RDD的轉化操作。其中比較典型的就是count()方法。在例2-4中,errorsRDD為轉化操作中生成的RDD,調用count()時會返回該RDD中的元素的個數。此時,例2-3中的filter()才會被真正地執行。這就是我們所說的惰性求值。在該例中還使用了take()方法獲取到RDD中的前10個元素,需要注意的是take()返回的結果是一個list。
例2-4
>>>print("errors number is :"+str(errorsRDD.count()))
>>>for line in errorsRDD.take(10):
>>> print(line)
參考文獻
[1] Holden Karau , Andy Konwinski , Patrick Wendell , Matei Zaharia .Spark快速大數據分析[M].北京:人民郵電出版社,2015.9;