Spark教程(三)—— 安裝與使用

        Spark可以獨立安裝使用,也可以和Hadoop一起安裝使用。本教程中,我們採用和Hadoop一起安裝使用,這樣,就可以讓Spark使用HDFS存取數據。需要說明的是,當安裝好Spark以後,裏面就自帶了scala環境,不需要額外安裝scala,因此,“Spark安裝”這個部分的教程,假設讀者的計算機上,沒有安裝Scala,也沒有安裝Java(當然了,如果已經安裝Java和Scala,也沒有關係,依然可以繼續按照本教程進行安裝),也就是說,你的計算機目前只有Linux系統,其他的軟件和環境都沒有安裝(沒有Java,沒有Scala,沒有Hadoop,沒有Spark),需要從零開始安裝所有大數據相關軟件。下面,需要你在自己的Linux系統上(筆者採用的Linux系統是Ubuntu16.04),首先安裝Java和Hadoop,然後再安裝Spark(Spark安裝好以後,裏面就默認包含了Scala解釋器)。由於Ubuntu 16.04已經自帶了Python 3.5版本,所以你的系統如果是Ubuntu 16.04,那麼就不需要重新安裝Python了。本教程也將以python3語法進行教學。
本教程的具體運行環境如下:

  • Ubuntu16.04以上
  • Hadoop 2.7.1以上
  • Java JDK 1.8以上
  • Spark 2.1.0 以上
  • Python 3.4以上

一. 安裝Hadoop

        如果你的計算機上已經安裝了Hadoop,本步驟可以略過。這裏假設沒有安裝。如果沒有安裝Hadoop,請訪問鏈接. 注意,在這個Hadoop安裝教程中,就包含了Java的安裝,所以,按照這個教程,就可以完成JDK和Hadoop這二者的安裝. 此外安裝Hadoop主要是爲了使用HDFS. 下面會就HDFS如何使用做一些說明.

        首先啓動HDFS組件

cd /usr/local/hadoop
./sbin/start-dfs.sh

        啓動結束後,HDFS開始進入可用狀態。如果你在HDFS文件系統中,還沒有爲當前Linux登錄用戶創建目錄(本教程統一使用用戶名hadoop登錄Linux系統),請使用下面命令創建:

./bin/hdfs dfs -mkdir -p /user/hadoop

        也就是說,HDFS文件系統爲Linux登錄用戶開闢的默認目錄是“/user/用戶名”(注意:是user,不是usr),本教程統一使用用戶名hadoop登錄Linux系統,所以,上面創建了“/user/hadoop”目錄,再次強調,這個目錄是在HDFS文件系統中,不在本地文件系統中。創建好以後,下面我們使用命令查看一下HDFS文件系統中的目錄和文件:

./bin/hdfs dfs -ls .

        上面命令中,最後一個點號“.”,表示要查看Linux當前登錄用戶hadoop在HDFS文件系統中與hadoop對應的目錄下的文件,也就是查看HDFS文件系統中“/user/hadoop/”目錄下的文件,所以,下面兩條命令是等價的:

./bin/hdfs dfs -ls .
./bin/hdfs dfs -ls /user/hadoop

        如果要查看HDFS文件系統根目錄下的內容,需要使用下面命令:

./bin/hdfs dfs -ls /

        下面,我們把本地文件系統中的“/usr/local/spark/mycode/wordcount/word.txt”上傳到分佈式文件系統HDFS中(放到hadoop用戶目錄下):

./bin/hdfs dfs -put /usr/local/spark/mycode/wordcount/word.txt .

        然後,用命令查看一下HDFS的hadoop用戶目錄下是否多了word.txt文件,可以使用下面命令列出hadoop目錄下的內容:

./bin/hdfs dfs -ls .

        可以看到,確實多了一個word.txt文件,我們使用cat命令查看一個HDFS中的word.txt文件的內容,命令如下:

./bin/hdfs dfs -cat ./word.txt

        上面命令執行後,就會看到HDFS中word.txt的內容了。

二. 安裝Spark

        在Linux系統中打開瀏覽器,訪問Spark官方下載地址, 按照如圖下載.

        由於我們已經自己安裝了Hadoop,所以,在“Choose a package type”後面需要選擇“Pre-build with user-provided Hadoop [can use with most Hadoop distributions]”,然後,點擊“Download Spark”後面的“spark-2.1.0-bin-without-hadoop.tgz”下載即可。下載的文件,默認會被瀏覽器保存在“/home/hadoop/下載”目錄下。需要說明的是,Pre-build with user-provided Hadoop: 屬於“Hadoop free”版,這樣,下載到的Spark,可應用到任意Hadoop 版本。

        Spark部署模式主要有四種:Local模式(單機模式)、Standalone模式(使用Spark自帶的簡單集羣管理器)、YARN模式(使用YARN作爲集羣管理器)和Mesos模式(使用Mesos作爲集羣管理器)。

        這裏介紹Local模式(單機模式)的 Spark安裝。我們選擇Spark 2.1.0版本,並且假設當前使用用戶名hadoop登錄了Linux操作系統。

sudo tar -zxf ~/下載/spark-2.1.0-bin-without-hadoop.tgz -C /usr/local/
cd /usr/local
sudo mv ./spark-2.1.0-bin-without-hadoop/ ./spark
sudo chown -R hadoop:hadoop ./spark          # 此處的 hadoop 爲你的用戶名

        安裝後,還需要修改Spark的配置文件spark-env.sh

cd /usr/local/spark
cp ./conf/spark-env.sh.template ./conf/spark-env.sh

        編輯spark-env.sh文件(vim ./conf/spark-env.sh),在第一行添加以下配置信息:

export SPARK_DIST_CLASSPATH=$(/usr/local/hadoop/bin/hadoop classpath)

        有了上面的配置信息以後,Spark就可以把數據存儲到Hadoop分佈式文件系統HDFS中,也可以從HDFS中讀取數據。如果沒有配置上面信息,Spark就只能讀寫本地數據,無法讀寫HDFS數據。

        然後通過如下命令,修改環境變量.

vim ~/.bashrc

        在.bashrc文件中添加如下內容

export JAVA_HOME=/usr/lib/jvm/default-java
export HADOOP_HOME=/usr/local/hadoop
export SPARK_HOME=/usr/local/spark
export PYTHONPATH=$SPARK_HOME/python:$SPARK_HOME/python/lib/py4j-0.10.4-src.zip:$PYTHONPATH
export PYSPARK_PYTHON=python3
export PATH=$HADOOP_HOME/bin:$SPARK_HOME/bin:$PATH

        PYTHONPATH環境變量主要是爲了在Python3中引入pyspark庫,PYSPARK_PYTHON變量主要是設置pyspark運行的python版本。
        .bashrc中必須包含JAVA_HOME,HADOOP_HOME,SPARK_HOME,PYTHONPATH,PYSPARK_PYTHON,PATH這些環境變量。如果已經設置了這些變量則不需要重新添加設置。
        接着還需要讓該環境變量生效,執行如下代碼:

source ~/.bashrc

        配置完成後就可以直接使用,不需要像Hadoop運行啓動命令。
        通過運行Spark自帶的示例,驗證Spark是否安裝成功。

cd /usr/local/spark
bin/run-example SparkPi

        執行時會輸出非常多的運行信息,輸出結果不容易找到,可以通過 grep 命令進行過濾(命令中的 2>&1 可以將所有的信息都輸出到 stdout 中,否則由於輸出日誌的性質,還是會輸出到屏幕中):

bin/run-example SparkPi 2>&1 | grep "Pi is"

        這裏涉及到Linux Shell中管道的知識,詳情可以參考Linux Shell中的管道命令

        過濾後的運行結果如下圖示,可以得到π 的 5 位小數近似值:

三. Spark的啓動參數以及在pySpark中運行代碼

        啓動spark, 命令如下:

bin/pyspark

        如果沒有設置PYSPARK_PYTHON環境變量,則使用如下命令啓動pyspark:

PYSPARK_PYTHON=python3
./bin/pyspark

        pyspark命令及其常用的參數如下:

./bin/pyspark --master <master-url>

        Spark的運行模式取決於傳遞給SparkContext的Master URL的值。Master URL可以是以下任一種形式:

  • local 使用一個Worker線程本地化運行SPARK(完全不併行)
  • local[*] 使用邏輯CPU個數數量的線程來本地化運行Spark
  • local[K] 使用K個Worker線程本地化運行Spark(理想情況下,K應該根據運行機器的CPU核數設定)
  • spark://HOST:PORT 連接到指定的Spark standalone master。默認端口是7077
  • yarn-client 以客戶端模式連接YARN集羣。集羣的位置可以在HADOOP_CONF_DIR 環境變量中找到
  • yarn-cluster 以集羣模式連接YARN集羣。集羣的位置可以在HADOOP_CONF_DIR 環境變量中找到
  • mesos://HOST:PORT 連接到指定的Mesos集羣。默認接口是5050

        需要強調的是,這裏我們採用“本地模式”(local)運行Spark,關於如何在集羣模式下運行Spark,可以參考後面的“在集羣上運行Spark應用程序”。

        在Spark中採用本地模式啓動pyspark的命令主要包含以下參數:

  • master:這個參數表示當前的pyspark要連接到哪個master,如果是local[*],就是使用本地模式啓動pyspark,其中,中括號內的星號表示需要使用幾個CPU核心(core)
  • jars: 這個參數用於把相關的JAR包添加到CLASSPATH中;如果有多個jar包,可以使用逗號分隔符連接它們

        比如,要採用本地模式,在4個CPU核心上運行pyspark:

cd /usr/local/spark
./bin/pyspark --master local[4]

        或者,可以在CLASSPATH中添加code.jar,命令如下:

cd /usr/local/spark
./bin/pyspark --master local[4] --jars code.jar 

        可以執行“pyspark –help”命令,獲取完整的選項列表,具體如下:

cd /usr/local/spark
./bin/pyspark --help

        上面是命令使用方法介紹,下面正式使用命令進入pyspark環境,可以通過下面命令啓動pyspark環境:

bin/pyspark

        該命令省略了參數,這時,系統默認是“bin/pyspark–master local[*]”,也就是說,是採用本地模式運行,並且使用本地所有的CPU核心。啓動pyspark後,就會進入“>>>”命令提示符狀態,如下圖所示:

        現在,你就可以在裏面輸入python代碼進行調試了。比如,下面在命令提示符後面輸入一個表達式“8 * 2 + 5”,然後回車,就會立即得到結果:

8 * 2 + 5

四. 本地文件統計詞頻

(1) 首先編一些語聊便於統計詞頻

        進入Linux系統,打開“終端”,進入Shell命令提示符狀態,然後,執行如下命令新建目錄:

cd /usr/local/spark
mkdir mycode
cd mycode
mkdir wordcount
cd wordcount

        然後,在“/usr/local/spark/mycode/wordcount”目錄下新建一個包含了一些語句的文本文件word.txt,命令如下:

vim word.txt

        可以在文本文件中隨意輸入一些單詞,用空格隔開,我們會編寫Spark程序對該文件進行單詞詞頻統計。然後,按鍵盤Esc鍵退出vim編輯狀態,輸入“:wq”保存文件並退出vim編輯器。

(2) 借用pyspark進行詞頻統計

from pyspark.sql import SparkSession
from pyspark import SparkContext, SparkConf
from pyspark.sql.types import Row, StructType, StructField, StringType

# spark加載本地文件
sc = SparkContext('local', 'test')
textFile = sc.textFile("file:///usr/local/spark/mycode/wordcount/word.txt")
wordCount = textFile.flatMap(lambda line: line.split(" ")).map(lambda word: (word,1)).reduceByKey(lambda a, b : a + b)
wordCount.foreach(print)

# 將textFile保存到文件中, 是爲了使用saveAsTextFile這個函數
textFile.saveAsTextFile("file:///usr/local/spark/mycode/wordcount/writeback")

        上面代碼中,sc.textFile()中的這個textFile是sc的一個方法名稱,這個方法用來加載文件數據。這兩個textFile不是一個東西,不要混淆。實際上,前面的變量textFile,你完全可以換個變量名稱. 這裏使用相同名稱,就是有意強調二者的區別。
注意,要加載本地文件,必須採用“file:///”開頭的這種格式。執行上上面這條命令以後,並不會馬上顯示結果,因爲,Spark採用惰性機制,只有遇到“行動”類型的操作,纔會從頭到尾執行所有操作。

        上面的saveAsTextFile()括號裏面的參數是保存文件的路徑,不是文件名。saveAsTextFile()是一個“行動”(Action)類型的操作,所以,馬上會執行真正的計算過程,從word.txt中加載數據到變量textFile中,然後,又把textFile中的數據寫回到本地文件目錄“/usr/local/spark/mycode/wordcount/writeback/”下面,現在讓我們切換到Linux Shell命令提示符窗口中,執行下面命令:

cd /usr/local/spark/mycode/wordcount/writeback/
ls

        執行結果類似下面:

part-00000 _SUCCESS

        也就是說,該目錄下包含兩個文件,我們可以使用cat命令查看一下part-00000文件(注意:part-後面是五個零)

cat part-00000

        顯示結果,是和上面word.txt中的內容一樣的。

五. HDFS統計詞頻

from pyspark.sql import SparkSession
from pyspark import SparkContext, SparkConf
from pyspark.sql.types import Row, StructType, StructField, StringType

# spark加載HDFS
sc = sc = SparkContext('local', 'test')
textFile = sc.textFile("hdfs://localhost:9000/user/liuxu/word.txt")
wordCount = textFile.flatMap(lambda line: line.split(" ")).map(lambda word: (word,1)).reduceByKey(lambda a, b : a + b)
wordCount.foreach(print)

        從HDFS中的讀取數據 和 從本地文件中讀取數據的主要區別在於sc.textFile()裏面的文件路徑不一致.

六. 詞頻統計代碼註釋

        textFile.flatMap(labmda line : line.split(” “)) - 會遍歷textFile中的每行文本內容,當遍歷到其中一行文本內容時,會把文本內容賦值給變量line,並執行Lamda表達式line : line.split(” “)。line : line.split(” “)是一個Lamda表達式,左邊表示輸入參數,右邊表示函數裏面執行的處理邏輯,這裏執行line.split(” “),也就是針對line中的一行文本內容,採用空格作爲分隔符進行單詞切分,從一行文本切分得到很多個單詞構成的單詞集合。這樣,對於textFile中的每行文本,都會使用Lamda表達式得到一個單詞集合,最終,多行文本,就得到多個單詞集合。textFile.flatMap()操作就把這多個單詞集合“拍扁”得到一個大的單詞集合。

        map(lambda word : (word, 1)),這個map操作會遍歷這個集合中的每個單詞,當遍歷到其中一個單詞時,就把當前這個單詞賦值給變量word,並執行Lamda表達式word : (word, 1),這個Lamda表達式的含義是,word作爲函數的輸入參數,然後,執行函數處理邏輯,這裏會執行(word, 1),也就是針對輸入的word,構建得到一個tuple,形式爲(word,1),key是word,value是1(表示該單詞出現1次)

        程序執行到這裏,已經得到一個RDD,這個RDD的每個元素是(key,value)形式的tuple。最後,針對這個RDD,執行reduceByKey(labmda a, b : a + b)操作,這個操作會把所有RDD元素按照key進行分組,然後使用給定的函數(這裏就是Lamda表達式:a, b : a + b),對具有相同的key的多個value進行reduce操作,返回reduce後的(key,value),比如(“hadoop”,1)和(“hadoop”,1),具有相同的key,進行reduce以後就得到(“hadoop”,2),這樣就計算得到了這個單詞的詞頻。

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