spark學習筆記--RDD基礎


RDD是一個不可變的分佈式集合,每個RDD有多個分區,它們分佈在集羣不同的節點上轉化操作不會立刻計算,只有當第一個行動操作發生時spark纔會進行計算,如果需要對同一個RDD進行反覆行動操作,最好先將其持久化一下 RDD.persist()

RDD 之所以成爲“彈性”是因爲在任何適合時候如果哪個分區掛掉了,它都能根據之前的操作步驟重算一下得到那個分區的數據,這個操作對用戶是透明的

創建RDD

spark 提供了兩種創建RDD的方式

  1. 從文件讀取

python

lines = sc.textFile("README.md") 

scala

val lines = sc.textFile("README.md") 
  1. 對內存中的集合並行化
lines = sc.parallelize(["pandas", "i like pandas"]) #python
val lines = sc.parallelize(List("pandas", "i like pandas")) //scala

RDD操作

轉化操作

惰性計算,碰到第一個行動操作才真正開始計算,返回RDD

map(func)

傳入一個函數,並對RDD中每個元素執行這個函數,由函數運行結果組成新的RDD返回,返回的RDD與原來RDD的元素是一一對應的關係
python

nums = sc.parallelize([1, 2, 3, 4])
squared = nums.map(lambda x: x * x).collect()
for num in squared:
    print "%i " % (num)

scala

val input = sc.parallelize(List(1, 2, 3, 4))
val result = input.map(x => x * x)
println(result.collect().mkString(","))

flatMap(func)

傳入一個函數,並對RDD中每個元素執行這個函數,由函數運行的結果組成新的RDD,與map的區別是,如果函數返回多個結果,不會組成list,而是成爲RDD中的多個元素

filter (func)

傳入一個函數,返回布爾值,RDD中元素帶入這個函數後運行結果爲True的元素組成新的RDD返回

python

inputRDD = sc.textFile("log.txt")
errorsRDD = inputRDD.filter(lambda x: "error" in x)

scala

val inputRDD = sc.textFile("log.txt")
val errorsRDD = inputRDD.filter(line => line.contains("error"))

在python 中向spark傳遞函數時,如果傳遞的是某個對象的的函數或者函數內部引用了對象,python會把整個對象序列化一起傳過去,最好換個方式,將所需的字段放入一個局部變量中。scala也差不多

class SearchFunctions(object):
  def __init__(self, query):
      self.query = query
  def isMatch(self, s):
      return self.query in s
  def getMatchesFunctionReference(self, rdd):
      # 問題:在"self.isMatch"中引用了整個self
      return rdd.filter(self.isMatch)
  def getMatchesMemberReference(self, rdd):
      # 問題:在"self.query"中引用了整個self
      return rdd.filter(lambda x: self.query in x)
  def getMatchesNoReference(self, rdd):
      # 安全:只把需要的字段提取到局部變量中
      query = self.query
      return rdd.filter(lambda x: query in x)

sample

rdd.sample(withReplacement=False, fraction=0.x, [seed])

withReplacement 表示是否又放回的抽樣
fraction 表示抽樣的比例,實際返回的數量不一定完全按這個比例,可能有點偏差,比如10個元素比例0.5 返回可能3、4、5、6個數據

集合操作union、intersection、subtract、cartesian

並集、交集、差集、笛卡爾積
用法相同 rdd3 = rdd1.union(rdd2)
笛卡爾積開銷很大

errorsRDD = inputRDD.filter(lambda x: "error" in x)
warningsRDD = inputRDD.filter(lambda x: "warning" in x)
badLinesRDD = errorsRDD.union(warningsRDD)

spark 會用譜系圖(lineage graph) 記錄各個RDD之間的依賴關係,用來計算每個RDD,還可以用來恢復數據
譜系圖

去重distinct()

用法rdd.distinct() 開銷很大

行動操作

行動操作會使spark計算需要依賴的轉化操作,並且它的返回結果一般不是RDD。

reduce、fold、aggregate

reduce把一個函數作用在一個序列[x1, x2, x3, …]上,這個函數必須接收兩個參數,reduce把結果繼續和序列的下一個元素做累積計算。
python 求累加和

sum = rdd.reduce(lambda x, y: x + y)

scala

val sum = rdd.reduce((x, y) => x + y)

fold 接受和reduce一樣形式的函數,但是fold需要你提供一個第一次調用你所提供函數的初始值,可以理解爲比reduce多調用了一次你的函數(實際沒有調用,直接用了你給的初始值,一般加法0乘法1)

sum = rdd.fold(0,lambda x, y: x + y)

aggregate 和fold類似,但是你提供的第一個函數僅僅在每個分區被使用,最後每個分區都有一個最終的結果,還要提供一個函數將這些結果再合併起來

sum = rdd.aggregate(0,lambda x,y:x+y,lambda x,y:x+y)

count()

統計RDD 的元素個數

num = rdd.count()

take(n)、top(n)

獲取一定量的元素,take無序,top採前n個

res = rdd.take(10)

collect()

獲取所有元素,需要內存夠大,數據集小可以用,慎用

res = rdd.collect()

foreach(func)

對rdd每個元素都執行操作,不需要返回值

持久化

當rdd或者dataframe 要被多次行動操作時,先持久化下

persist

persist(storageLevel=StorageLevel(True, True, False, False, 1))

persist可以傳入的級別很多,默認MEMORY_AND_DISK,具體級別可以參考這裏

cache

cache只有一個默認級別 MEMORY_AND_DISK

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章