SparkR初體驗

突然有個想法,R只能處理百萬級別的數據,如果R能運行在spark上多好!搜了下發現13年SparkR這個項目就啓動了,感謝美帝!

1.你肯定得先裝個spark吧。看這:Spark本地模式與Spark Standalone僞分佈模式

2.你肯定得會R吧。看這:R語言入門

3.啓動SparkR就可以了

3.1啓動於本地(單機)

Spark also provides an experimental R API since 1.4 (only DataFrames APIs included).To run Spark interactively in a R interpreter, usebin/sparkR:

./bin/sparkR --master local[2]

guo@drguo:/opt/spark-1.6.1-bin-hadoop2.6$ ./bin/sparkR #這樣直接運行默認在本地運行,相當於sparkR --master local[2]
R version 3.2.3 (2015-12-10) -- "Wooden Christmas-Tree"
Copyright (C) 2015 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R是自由軟件,不帶任何擔保。
在某些條件下你可以將其自由散佈。
用'license()'或'licence()'來看散佈的詳細條件。

R是個合作計劃,有許多人爲之做出了貢獻.
用'contributors()'來看合作者的詳細情況
用'citation()'會告訴你如何在出版物中正確地引用R或R程序包。

用'demo()'來看一些示範程序,用'help()'來閱讀在線幫助文件,或
用'help.start()'通過HTML瀏覽器來看幫助文件。
用'q()'退出R.

Launching java with spark-submit command /opt/spark-1.6.1-bin-hadoop2.6/bin/spark-submit   "sparkr-shell" /tmp/RtmpmkEgRV/backend_port21583a90cfc4 
16/05/12 03:30:35 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

 Welcome to
    ____              __ 
   / __/__  ___ _____/ /__ 
  _\ \/ _ \/ _ `/ __/  '_/ 
 /___/ .__/\_,_/_/ /_/\_\   version  1.6.1 
    /_/ 


 Spark context is available as sc, SQL context is available as sqlContext

3.2啓動於Spark Standalone集羣,別忘了先啓動集羣。

guo@drguo:/opt/spark-1.6.1-bin-hadoop2.6$ bin/sparkR --master spark://drguo:7077

Launching java with spark-submit command /opt/spark-1.6.1-bin-hadoop2.6/bin/spark-submit   "--master" "spark://drguo:7077" "sparkr-shell" /tmp/RtmpXmU5lQ/backend_port23516636af0a 
16/05/12 11:08:26 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

 Welcome to
    ____              __ 
   / __/__  ___ _____/ /__ 
  _\ \/ _ \/ _ `/ __/  '_/ 
 /___/ .__/\_,_/_/ /_/\_\   version  1.6.1 
    /_/ 


 Spark context is available as sc, SQL context is available as sqlContext
3.3啓動於yarn,別忘了先啓動yarn和hdfs
guo@drguo:/opt/spark-1.6.1-bin-hadoop2.6$ bin/sparkR --master yarn-client

Launching java with spark-submit command /opt/spark-1.6.1-bin-hadoop2.6/bin/spark-submit   "--master" "yarn-client" "sparkr-shell" /tmp/RtmpxF2KAi/backend_port174572d34cd0 
16/05/12 10:54:46 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

 Welcome to
    ____              __ 
   / __/__  ___ _____/ /__ 
  _\ \/ _ \/ _ `/ __/  '_/ 
 /___/ .__/\_,_/_/ /_/\_\   version  1.6.1 
    /_/ 


 Spark context is available as sc, SQL context is available as sqlContext

4.隨便用一下

#讀入本地數據框
> localDF <- data.frame(name=c("John", "Smith", "Sarah"), age=c(19, 23, 18))
> localDF
   name age
1  John  19
2 Smith  23
3 Sarah  18
> df <- createDataFrame(sqlContext, localDF)
> printSchema(df)
root
 |-- name: string (nullable = true)
 |-- age: double (nullable = true)
#從本地文件讀入
> peopleDF<-read.df(sqlContext,"people.json","json")
> peopleDF
DataFrame[age:bigint, name:string]
> head(peopleDF)
  age    name
1  NA Michael
2  30    Andy
3  19  Justin
> peopleC <- collect(peopleDF)
> print(peopleC)
  age    name
1  NA Michael
2  30    Andy
3  19  Justin
> printSchema(peopleDF)
root
 |-- age: long (nullable = true)
 |-- name: string (nullable = true)
> registerTempTable(peopleDF, "people")
#執行sql語句
> teenagers <- sql(sqlContext, "SELECT name FROM people WHERE age >= 13 AND age <= 19")
> teenagersLocalDF <- collect(teenagers)
> head(teenagersLocalDF)
    name
1 Justin
> teenagers
DataFrame[name:string]
> print(teenagersLocalDF)
    name
1 Justin
#還可以用hive sql呢!
 > hiveContext <- sparkRHive.init(sc)
16/05/12 13:16:18 WARN Connection: BoneCP specified but not present in CLASSPATH (or one of dependencies)
16/05/12 13:16:18 WARN Connection: BoneCP specified but not present in CLASSPATH (or one of dependencies)
16/05/12 13:16:25 WARN ObjectStore: Version information not found in metastore. hive.metastore.schema.verification is not enabled so recording the schema version 1.2.0
16/05/12 13:16:25 WARN ObjectStore: Failed to get database default, returning NoSuchObjectException
16/05/12 13:16:28 WARN Connection: BoneCP specified but not present in CLASSPATH (or one of dependencies)
16/05/12 13:16:29 WARN Connection: BoneCP specified but not present in CLASSPATH (or one of dependencies)
> sql(hiveContext, "CREATE TABLE IF NOT EXISTS src (key INT, value STRING)")
DataFrame[result:string]
> sql(hiveContext, "LOAD DATA LOCAL INPATH 'examples/src/main/resources/kv1.txt' INTO TABLE src")
DataFrame[result:string]
> results <- sql(hiveContext, "FROM src SELECT key, value")
> head(results)
  key   value
1 238 val_238
2  86  val_86
3 311 val_311
4  27  val_27
5 165 val_165
6 409 val_409
> print(results)
DataFrame[key:int, value:string]
> print(collect(results))
    key   value
1   238 val_238
2    86  val_86
3   311 val_311

更多操作請看官方文檔:https://spark.apache.org/docs/latest/sparkr.html

看一下drguo:4040,有了八個已完成的job


再看一下最後一個job的詳細信息


> getwd()  
[1] "/opt/spark-1.6.1-bin-hadoop2.6"  
> setwd("/home/guo/RWorkSpaces")  
> getwd()  
[1] "/home/guo/RWorkSpaces"  
> x<-c(1,1,2,2,3,3,3)  
> y<-c("女","男","女","男","女","男","女")  
> z<-c(80,85,92,76,61,95,88)  
> student<-data.frame(class=x,sex=y,score=z)  
> student  
  class sex score  
1     1  女    80  
2     1  男    85  
3     2  女    92  
4     2  男    76  
5     3  女    61  
6     3  男    95  
7     3  女    88  
> row.names(student)<-c("鳳姐","波多","杰倫","畢老爺","波","傑","畢老")#改變行名  
> student  
       class sex score  
鳳姐       1  女    80  
波多       1  男    85  
杰倫       2  女    92  
畢老爺     2  男    76  
波         3  女    61  
傑         3  男    95  
畢老       3  女    88   
> student$score  
[1] 80 85 92 76 61 95 88  
> student[,3]  
[1] 80 85 92 76 61 95 88  
> student[,score]  
Error in `[.data.frame`(student, , score) : 找不到對象'score'  
> student[,"score"]  
[1] 80 85 92 76 61 95 88  
> student[["score"]]  
[1] 80 85 92 76 61 95 88  
> student[[3]]  
[1] 80 85 92 76 61 95 88  
> student[1:2,1:3]  
     class sex score  
鳳姐     1  女    80  
波多     1  男    85  
> student[student$score>80,]  
     class sex score  
波多     1  男    85  
杰倫     2  女    92  
傑       3  男    95  
畢老     3  女    88  
> attach(student)  
> student[score>80,]  
     class sex score  
波多     1  男    85  
杰倫     2  女    92  
傑       3  男    95  
畢老     3  女    88  

5.提交R程序


guo@drguo:/opt/spark-1.6.1-bin-hadoop2.6$ ./bin/spark-submit examples/src/main/r/dataframe.R

dataframe.R

library(SparkR)

# Initialize SparkContext and SQLContext
sc <- sparkR.init(appName="SparkR-DataFrame-example")
sqlContext <- sparkRSQL.init(sc)

# Create a simple local data.frame
localDF <- data.frame(name=c("John", "Smith", "Sarah"), age=c(19, 23, 18))

# Convert local data frame to a SparkR DataFrame
df <- createDataFrame(sqlContext, localDF)

# Print its schema
printSchema(df)
# root
#  |-- name: string (nullable = true)
#  |-- age: double (nullable = true)

# Create a DataFrame from a JSON file
path <- file.path(Sys.getenv("SPARK_HOME"), "examples/src/main/resources/people.json")
peopleDF <- read.json(sqlContext, path)
printSchema(peopleDF)

# Register this DataFrame as a table.
registerTempTable(peopleDF, "people")

# SQL statements can be run by using the sql methods provided by sqlContext
teenagers <- sql(sqlContext, "SELECT name FROM people WHERE age >= 13 AND age <= 19")

# Call collect to get a local data.frame
teenagersLocalDF <- collect(teenagers)

# Print the teenagers in our dataset 
print(teenagersLocalDF)

# Stop the SparkContext now
sparkR.stop()

官方文檔:https://spark.apache.org/docs/latest/api/R/index.html

                    https://spark.apache.org/docs/latest/sparkr.html


下面轉自:http://mt.sohu.com/20151023/n424011438.shtml 作者:孫銳,英特爾大數據團隊工程師,HIVE和Shark項目貢獻者,SparkR主力貢獻者之一。

R和Spark的強強結合應運而生。2013年9月SparkR作爲一個獨立項目啓動於加州大學伯克利分校的大名鼎鼎的AMPLAB實驗室,與Spark源出同門。2014年1月,SparkR項目在github上開源(https://github.com/amplab-extras/SparkR-pkg)。隨後,來自工業界的Alteryx、Databricks、Intel等公司和來自學術界的普渡大學,以及其它開發者積極參與到開發中來,最終在2015年4月成功地合併進Spark代碼庫的主幹分支,並在Spark 1.4版本中作爲重要的新特性之一正式宣佈。

  當前特性SparkR往Spark中增加了R語言API和運行時支持。Spark的 API由Spark Core的API以及各個內置的高層組件(Spark Streaming,Spark SQL,ML Pipelines和MLlib,Graphx)的API組成,目前SparkR只提供了Spark的兩組API的R語言封裝,即Spark Core的RDD API和Spark SQL的DataFrame API。

  需要指出的是,在Spark 1.4版本中,SparkR的RDD API被隱藏起來沒有開放,主要是出於兩點考慮:

  RDD API雖然靈活,但比較底層,R用戶可能更習慣於使用更高層的API;

  RDD API的實現上目前不夠健壯,可能會影響用戶體驗,比如每個分區的數據必須能全部裝入到內存中的限制,對包含複雜數據類型的RDD的處理可能會存在問題等。

  目前社區正在討論是否開放RDD API的部分子集,以及如何在RDD API的基礎上構建一個更符合R用戶習慣的高層API。

  RDD API用戶使用SparkR RDD API在R中創建RDD,並在RDD上執行各種操作。

  目前SparkR RDD實現了Scala RDD API中的大部分方法,可以滿足大多數情況下的使用需求:

  SparkR支持的創建RDD的方式有:

  從R list或vector創建RDD(parallelize())

  從文本文件創建RDD(textFile())

  從object文件載入RDD(objectFile())

  SparkR支持的RDD的操作有:

  數據緩存,持久化控制:cache(),persist(),unpersist()

  數據保存:saveAsTextFile(),saveAsObjectFile()

  常用的數據轉換操作,如map(),flatMap(),mapPartitions()等

  數據分組、聚合操作,如partitionBy(),groupByKey(),reduceByKey()等

  RDD間join操作,如join(), fullOuterJoin(), leftOuterJoin()等

  排序操作,如sortBy(), sortByKey(), top()等

  Zip操作,如zip(), zipWithIndex(), zipWithUniqueId()

  重分區操作,如coalesce(), repartition()

  其它雜項方法

  和Scala RDD API相比,SparkR RDD API有一些適合R的特點:

  SparkR RDD中存儲的元素是R的數據類型。

  SparkR RDD transformation操作應用的是R函數。

  RDD是一組分佈式存儲的元素,而R是用list來表示一組元素的有序集合,因此SparkR將RDD整體上視爲一個分佈式的list。Scala API 中RDD的每個分區的數據由iterator來表示和訪問,而在SparkR RDD中,每個分區的數據用一個list來表示,應用到分區的轉換操作,如mapPartitions(),接收到的分區數據是一個list而不是iterator。

  爲了符合R用戶經常使用lapply()對一個list中的每一個元素應用某個指定的函數的習慣,SparkR在RDD類上提供了SparkR專有的transformation方法:lapply()、lapplyPartition()、lapplyPartitionsWithIndex(),分別對應於Scala API的map()、mapPartitions()、mapPartitionsWithIndex()。

  DataFrame APISpark 1.3版本引入了DataFrame API。相較於RDD API,DataFrame API更受社區的推崇,這是因爲:

  DataFrame的執行過程由Catalyst優化器在內部進行智能的優化,比如過濾器下推,表達式直接生成字節碼。

  基於Spark SQL的外部數據源(external data sources) API訪問(裝載,保存)廣泛的第三方數據源。

  使用R或Python的DataFrame API能獲得和Scala近乎相同的性能。而使用R或Python的RDD API的性能比起Scala RDD API來有較大的性能差距。

  Spark的DataFrame API是從R的 Data Frame數據類型和Python的pandas庫借鑑而來,因而對於R用戶而言,SparkR的DataFrame API是很自然的。更重要的是,SparkR DataFrame API性能和Scala DataFrame API幾乎相同,所以推薦儘量用SparkR DataFrame來編程。

  目前SparkR的DataFrame API已經比較完善,支持的創建DataFrame的方式有:

  從R原生data.frame和list創建

  從SparkR RDD創建

  從特定的數據源(JSON和Parquet格式的文件)創建

  從通用的數據源創建

  將指定位置的數據源保存爲外部SQL表,並返回相應的DataFrame

  從Spark SQL表創建

  從一個SQL查詢的結果創建

  支持的主要的DataFrame操作有:

  ·數據緩存,持久化控制:cache(),persist(),unpersist()

  數據保存:saveAsParquetFile(), saveDF() (將DataFrame的內容保存到一個數據源),saveAsTable() (將DataFrame的內容保存存爲數據源的一張表)

  集合運算:unionAll(),intersect(), except()

  Join操作:join(),支持inner、full outer、left/right outer和semi join。

  數據過濾:filter(), where()

  排序:sortDF(), orderBy()

  列操作:增加列- withColumn(),列名更改- withColumnRenamed(),選擇若干列 -select()、selectExpr()。爲了更符合R用戶的習慣,SparkR還支持用$、[]、[[]]操作符選擇列,可以用$<列名> <- 的語法來增加、修改和刪除列

  RDD map類操作:lapply()/map(),flatMap(),lapplyPartition()/mapPartitions(),foreach(),foreachPartition()

  數據聚合:groupBy(),agg()

  轉換爲RDD:toRDD(),toJSON()

  轉換爲表:registerTempTable(),insertInto()

  取部分數據:limit(),take(),first(),head()

  編程示例總體上看,SparkR程序和Spark程序結構很相似。

  基於RDD API的示例

  要基於RDD API編寫SparkR程序,首先調用sparkR.init()函數來創建SparkContext。然後用SparkContext作爲參數,調用parallelize()或者textFile()來創建RDD。有了RDD對象之後,就可以對它們進行各種transformation和action操作。下面的代碼是用SparkR編寫的Word Count示例:

  library(SparkR) #初始化SparkContext sc <- sparkR.init("local", "RWordCount") #從HDFS上的一個文本文件創建RDD lines <- textFile(sc, "hdfs://localhost:9000/my_text_file") #調用RDD的transformation和action方法來計算word count #transformation用的函數是R代碼 words <- flatMap(lines, function(line) { strsplit(line, " ")[[1]] }) wordCount <- lapply(words, function(word) { list(word, 1L) }) counts <- reduceByKey(wordCount, "+", 2L) output <- collect(counts)

  基於DataFrame API的示例

  基於DataFrame API的SparkR程序首先創建SparkContext,然後創建SQLContext,用SQLContext來創建DataFrame,再操作DataFrame裏的數據。下面是用SparkR DataFrame API計算平均年齡的示例:library(SparkR) #初始化SparkContext和SQLContext sc <- sparkR.init("local", "AverageAge") sqlCtx <- sparkRSQL.init(sc) #從當前目錄的一個JSON文件創建DataFrame df <- jsonFile(sqlCtx, "person.json") #調用DataFrame的操作來計算平均年齡 df2 <- agg(df, age="avg") averageAge <- collect(df2)[1, 1]

  對於上面兩個示例要注意的一點是SparkR RDD和DataFrame API的調用形式和Java/Scala API有些不同。假設rdd爲一個RDD對象,在Java/Scala API中,調用rdd的map()方法的形式爲:rdd.map(…),而在SparkR中,調用的形式爲:map(rdd, …)。這是因爲SparkR使用了R的S4對象系統來實現RDD和DataFrame類。

  架構SparkR主要由兩部分組成:SparkR包和JVM後端。SparkR包是一個R擴展包,安裝到R中之後,在R的運行時環境裏提供了RDD和DataFrame API。

  

  圖1 SparkR軟件棧

  SparkR的整體架構如圖2所示。

  

  圖2 SparkR架構

  R JVM後端SparkR API運行在R解釋器中,而Spark Core運行在JVM中,因此必須有一種機制能讓SparkR API調用Spark Core的服務。R JVM後端是Spark Core中的一個組件,提供了R解釋器和JVM虛擬機之間的橋接功能,能夠讓R代碼創建Java類的實例、調用Java對象的實例方法或者Java類的靜態方法。JVM後端基於Netty實現,和R解釋器之間用TCP socket連接,用自定義的簡單高效的二進制協議通信。

  R Worker

  SparkR RDD API和Scala RDD API相比有兩大不同:SparkR RDD是R對象的分佈式數據集,SparkR RDD transformation操作應用的是R函數。SparkR RDD API的執行依賴於Spark Core但運行在JVM上的Spark Core既無法識別R對象的類型和格式,又不能執行R的函數,因此如何在Spark的分佈式計算核心的基礎上實現SparkR RDD API是SparkR架構設計的關鍵。

  SparkR設計了Scala RRDD類,除了從數據源創建的SparkR RDD外,每個SparkR RDD對象概念上在JVM端有一個對應的RRDD對象。RRDD派生自RDD類,改寫了RDD的compute()方法,在執行時會啓動一個R worker進程,通過socket連接將父RDD的分區數據、序列化後的R函數以及其它信息傳給R worker進程。R worker進程反序列化接收到的分區數據和R函數,將R函數應到到分區數據上,再把結果數據序列化成字節數組傳回JVM端。

  從這裏可以看出,與Scala RDD API相比,SparkR RDD API的實現多了幾項開銷:啓動R worker進程,將分區數據傳給R worker和R worker將結果返回,分區數據的序列化和反序列化。這也是SparkR RDD API相比Scala RDD API有較大性能差距的原因。

  DataFrame API的實現

  由於SparkR DataFrame API不需要傳入R語言的函數(UDF()方法和RDD相關方法除外),而且DataFrame中的數據全部是以JVM的數據類型存儲,所以和SparkR RDD API的實現相比,SparkR DataFrame API的實現簡單很多。R端的DataFrame對象就是對應的JVM端DataFrame對象的wrapper,一個DataFrame方法的實現基本上就是簡單地調用JVM端DataFrame的相應方法。這種情況下,R Worker就不需要了。這是使用SparkR DataFrame API能獲得和ScalaAPI近乎相同的性能的原因。

  當然,DataFrame API還包含了一些RDD API,這些RDD API方法的實現是先將DataFrame轉換成RDD,然後調用RDD 的相關方法。

  展望SparkR目前來說還不是非常成熟,一方面RDD API在對複雜的R數據類型的支持、穩定性和性能方面還有較大的提升空間,另一方面DataFrame API在功能完備性上還有一些缺失,比如對用R代碼編寫UDF的支持、序列化/反序列化對嵌套類型的支持,這些問題相信會在後續的開發中得到改善和解決。如何讓DataFrame API對熟悉R原生Data Frame和流行的R package如dplyr的用戶更友好是一個有意思的方向。此外,下一步的開發計劃包含幾個大的特性,比如普渡大學正在做的在SparkR中支持Spark Streaming,還有Databricks正在做的在SparkR中支持ML pipeline等。SparkR已經成爲Spark的一部分,相信社區中會有越來越多的人關注並使用SparkR,也會有更多的開發者參與對SparkR的貢獻,其功能和使用性將會越來越強。

  總結Spark將正式支持R API對熟悉R語言的數據科學家是一個福音,他們可以在R中無縫地使用RDD和Data Frame API,藉助Spark內存計算、統一軟件棧上支持多種計算模型的優勢,高效地進行分佈式數據計算和分析,解決大規模數據集帶來的挑戰。工欲善其事,必先利其器,SparkR必將成爲數據科學家在大數據時代的又一門新利器。

發佈了134 篇原創文章 · 獲贊 249 · 訪問量 81萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章