PySpark 核心概念和操作(詞頻統計)

1. Spark核心概念

1.1 Spark簡介

Apache Spark是新興的一種快速通用的大規模數據處理引擎。它的優勢有三個方面:

  • 通用計算引擎 能夠運行MapReduce、數據挖掘、圖運算、流式計算、SQL等多種框架
  • 基于內存 數據可緩存在內存中,特別適用于需要迭代多次運算的場景
  • 與Hadoop集成 能夠直接讀寫HDFS中的數據,并能運行在YARN之上

Spark是用Scala語言編寫的,所提供的API也很好地利用了這門語言的特性,當然作為數據科學的一環,它也可以使用Java和Python編寫應用。這里我們將用Python給大家做講解。

1.2 Spark核心

Spark支持多種運行模式。單機部署下,既可以用本地(Local)模式運行,也可以使用偽分布式模式來運行;當以分布式集群部署的時候,可以根據實際情況選擇Spark自帶的獨立(Standalone)運行模式、YARN運行模式或者Mesos模式。雖然模式多,但是Spark的運行架構基本由三部分組成,包括SparkContext(驅動程序)、ClusterManager(集群資源管理器)Executor(任務執行進程)。 

  • SparkContext提交作業,向ClusterManager申請資源;
  • ClusterManager會根據當前集群的資源使用情況,進行有條件的FIFO策略:先分配的應用程序盡可能多地獲取資源,后分配的應用程序則在剩余資源中篩選,沒有合適資源的應用程序只能等待其他應用程序釋放資源;
  • ClusterManager默認情況下會將應用程序分布在盡可能多的Worker上,這種分配算法有利于充分利用集群資源,適合內存使用多的場景,以便更好地做到數據處理的本地性;另一種則是分布在盡可能少的Worker上,這種適合CPU密集型且內存使用較少的場景;
  • Excutor創建后與SparkContext保持通訊,SparkContext分配任務集給Excutor,Excutor按照一定的調度策略執行任務集。

Spark包含1個driver(筆記本電腦或者集群網關機器上)和若干個executor(在各個節點上),通過SparkContext(簡稱sc)連接Spark集群創建RDD累加器(accumlator)廣播變量(broadcast variables),簡單可以認為SparkContext(驅動程序)是Spark程序的根本。

Driver會把計算任務分成一系列小的task,然后送到executor執行。executor之間可以通信,在每個executor完成自己的task以后,所有的信息會被傳回。

1.3 RDD(彈性分布式數據集)介紹

在Spark里,所有的處理和計算任務都會被組織成一系列Resilient Distributed Dataset(彈性分布式數據集,簡稱RDD)上的transformations(轉換)actions(動作)。

RDD是一個包含諸多元素、被劃分到不同節點上進行并行處理的數據集合,可以將RDD持久化到內存中,這樣就可以有效地在并行操作中復用(在機器學習這種需要反復迭代的任務中非常有效)。在節點發生錯誤時RDD也可以自動恢復。

說起來,RDD就像一個NumPy array或者一個Pandas Series,可以視作一個有序的item集合。

只不過這些item并不存在driver端的內存里,而是被分割成很多個partitions,每個partition的數據存在集群的executor的內存中。

1.4 RDD transformations和actions

大家還對python的list comprehension有印象嗎,RDDs可以進行一系列的變換得到新的RDD,有點類似那個過程,我們先給大家提一下RDD上最最常用到的transformation:

  • map() 對RDD的每一個item都執行同一個操作
  • flatMap() 對RDD中的item執行同一個操作以后得到一個list,然后以平鋪的方式把這些list里所有的結果組成新的list
  • filter() 篩選出來滿足條件的item
  • distinct() 對RDD中的item去重
  • sample() 從RDD中的item中采樣一部分出來,有放回或者無放回
  • sortBy() 對RDD中的item進行排序

特別注意:Spark的一個核心概念是惰性計算。當你把一個RDD轉換成另一個的時候,這個轉換不會立即生效執行?。。park會把它先記在心里,等到真的需要拿到轉換結果的時候,才會重新組織你的transformations(因為可能有一連串的變換)
這樣可以避免不必要的中間結果存儲和通信。記住哦,transformation屬于多行計算

剛才提到了惰性計算,那么什么東西能讓它真的執行轉換與運算呢?
是的,就是我們馬上提到的Actions,下面是常見的action,當他們出現的時候,表明我們需要執行剛才定義的transform了:

  • collect(): 計算所有的items并返回所有的結果到driver端,接著 collect()會以Python list的形式返回結果
  • first(): 和上面是類似的,不過只返回第1個item
  • take(n): 類似,但是返回n個item
  • count(): 計算RDD中item的個數
  • top(n): 返回頭n個items,按照自然結果排序
  • reduce(): 對RDD中的items做聚合

1.5 針對更復雜的transformations和actions

咱們剛才已經見識到了Spark中最常見的transform和action,但是有時候我們會遇到更復雜的結構,比如非常非常經典的是以元組形式組織的k-v對(key, value)

我們把它叫做pair RDDs,而Sark中針對這種item結構的數據,定義了一些transformation和action:

  • reduceByKey(): 對所有有著相同key的items執行reduce操作
  • groupByKey(): 返回類似(key, listOfValues)元組的RDD,后面的value List 是同一個key下面的
  • sortByKey(): 按照key排序
  • countByKey(): 按照key去對item個數進行統計
  • collectAsMap(): 和collect有些類似,但是返回的是k-v的字典

2. PySpark之詞頻統計

首先,我們導入pyspark的包,創建SparkContext,建立RDD

import pyspark
from pyspark import SparkContext
from pyspark import SparkConf
conf=SparkConf().setAppName("miniProject").setMaster("local[*]")
sc=SparkContext.getOrCreate(conf)

然后讀取文本文件
textFile = sc.textFile("file:///usr/local/spark/mycode/wordcount/word.txt")
textFile是一個方法,可以用來加載文本數據,默認是從HDFS上加載,如果要加載本地文件,就必須使用file:///加路徑的形式
從文本中讀取數據后就要開始進行詞頻統計了

wordCount = textFile.flatMap(lambda line:line.split(" ")).\
                  map(lambda word:(word, 1)).reduceByKey(lambda x,y:x+y)

flatMap會逐行遍歷文本內容,然后對每行內容進行lambda函數的操作,即line:line.split(" "),該操作會把每一行內容賦值給line,然后對每一個line進行split(" ")操作,即對每一行用空格分隔成單獨的單詞,這樣每一行都是一個由單詞組成的集合,因為有很多行,所以就有很多歌這樣的單詞集合,執行完 textFile.flatMap(lambda line:line.split(" "))后會把這些單詞集合組成一個大的單詞集合

map(lambda word:(word, 1))中的map對上述產生的單詞集合進行遍歷,對于每一個單詞進行map函數內的操作,即lambda word:(word,1),該操作會把每個單詞賦值給word,然后組成一個鍵值對,這個鍵值對的key是這個單詞,而value是1,這樣就把每個單詞變成了這個單詞的鍵值對形式。執行完這個map后就會獲得一個RDD,這個RDD的每一個元素是很多個鍵值對

reduceByKey(lambda x,y:x+y)會對RDD中的每個元素根據key進行分組,然后對該分組進行括號內的操作,即lambda x,y:x+y,通過對具有相同key的元素進行該操作,reduce操作會把具有相同key的元素的value進行相加,這樣最后變成一個大的鍵值對,key是相同的,value是具有相同key的鍵值對的個數,這樣,詞頻統計就完成了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。