基礎
初始化spark
val conf = new SparkConf().setAppName("wordcount")
val sc = new SparkContext(conf)
轉化操作和行動操作的區別在於spark計算rdd的方式不同,只有在第一次在一個行動操作中用到轉化操作中的rdd時,纔會真正計算這些rdd。
創建rdd
// 驅動器程序對一個集合進行並行化
val lines = sc.parallelize(List("pandas","i like pandas"))
//讀取外部數據集
val lines = sc.textFile("/path/to/README.md")
rdd操作
-
轉化操作 例如filter()
filter不會改變已有的inputRDD的數據val errorsRDD = inputRDD.filter(line => line.contains(“error”))
-
行動操作 例如count()
println("Input had " + badLinesRDD.count() + “concerning lines”)
println(“Here are 10 examples:”)
badLinesRDD.take(10).foreach(println)
向spark傳遞函數
我們可以把定義的內聯函數,方法的引用或者靜態方法傳遞給Spark
class SearchFunctions(val query: String){
def isMatch(s: String):Boolean = {
s.contains(query)
}
}
//傳遞整個對象
def getMatchesFunctionReference(rdd: RDD[String]) :RDD[String] = {
rdd.map(isMatch)
}
//傳遞整個對象
def getMatchesFieldReference(rdd: RDD[String]): RDD[String]= {
rdd.map( x => x.split(query))
}
//傳遞局部變量
def getMatchesNoReference(rdd: RDD[String]: RDD[String] ) = {
val query_ = this.query
rdd.map(x => x.split(query_))
常見轉化操作和行動操作
轉化操作
-
map(): 接收一個函數,把這個函數作用於RDD中的每一個元素,將函數的返回結果作爲結果RDD中對應的值
val result = input.map( x => x*x)
-
filter():接收一個函數,並將RDD中滿足該函數的元素放入新的RDD中返回
val result = input.filter( x => x.contains(“a”))
-
flatMap():將接收到的函數分別應用到輸入RDD中的每一個元素中,返回一個返回值序列的迭代器
val words = input.flatMap(line => line.spilt(" "))
-
僞集合操作
distinct() : RDD中最常缺失的是集合的唯一性,常常有重複的元素,RDD.distinct()轉化操作可以生成一個只包含不同元素的新RDD,但是此操作開銷很大,需要將所有數據通過網絡shuffle。
union(): 返回一個包含兩個RDD中所有元素的RDD,含有重複元素
intersection():只返回兩個RDD中所共有的元素,運行時會去掉所有重複的元素,單個RDD中的重複元素也會去掉,需要shuffle,性能差很多。
subtract():需要數據混洗,接收一個RDD,並去掉第一個RDD中與接收RDD相同的元素
cartesian():求笛卡爾積,所有可能的組合
行動操作
- reduce():接收一個函數作爲參數,這個函數要操作兩個相同元素類型的RDD數據並返回一個同樣類型的新元素
val sum = rdd.reduce((x,y) => x + y) - fold(): 和reduce一樣,但是需要提供初始值
- aggregate():返回值類型可以與所操作的RDD類型不同
計算RDD的平均值 通過一個函數將RDD中的元素合併起來放入累加器,然後用第二個函數將累加器兩兩合併
val result = input.aggregate((0,0))(
(acc , value) => (acc._1 + value , acc._2 + 1),
(acc1, acc2) => (acc._1 +acc2._1, acc1._2 + acc2._2))
val avg = result._1/result._2.toDouble
- collect()
collect()將整個RDD的內容返回,將數據複製到驅動器進程中,要求所有數據都能一同放入單臺機器的內存中,通常在單元測試中使用 - take(n)
返回RDD中的n個元素,不均衡 - top(n) 如果爲數據定義了順序,可以使用top()從RDD中獲取前幾個元素,也可以使用自己的比較函數
- takeSample(withReplacement,num,[seed]) 從RDD返回任意一些元素
- foreach()
- count()
- countByValue()
不同類型RDD之間轉化
mean(),variance()只能用在數值RDD,join()只能用在鍵值對RDD
在scala中,將RDD轉爲特定函數的RDD是由隱式轉換來自動處理的
import org.apache.spark.SparkContext._
持久化
RDD都是惰性求值的
有時需要多次使用同一個RDD
persist()默認會把數據以序列化的形式緩存在JVM的堆空間中
5個級別:MEMORY_ONLY,MEMORY_ONLY_SER,MEMORY_AND_DISK,MEMORY_AND_DISK_SER,DISK_ONLY
import org.apache.spark.storage.StorageLevel
rdd.persist(StorageLevel.DISK_ONLY)
unpersist()手動釋放持久化的RDD