spark開發問題彙總 (持續更新)

Spark官方文檔:http://spark.apache.org/docs/2.1.0/index.html
Spark2.0新特性介紹:http://www.slideshare.net/databricks/apache-spark-20-faster-easier-and-smarter
Spark2.0和Spark1.6性能對比:https://databricks.com/blog/2016/05/11/apache-spark-2-0-technical-preview-easier-faster-and-smarter.html

下面這個博客介紹的基本算子比較全面且帶有例子,故不重複撰寫
spark算子詳解------spark算子分類
spark算子詳解------Transformation算子介紹
spark算子詳解------Action算子介紹

文章目錄

一、兩個同類型的rdd合併

union(ortherDataset):將兩個RDD中的數據集進行合併,最終返回兩個RDD的並集,若RDD中存在相同的元素也不會去重

//省略sc
   val rdd1 = sc.parallelize(1 to 3)
   val rdd2 = sc.parallelize(3 to 5)
   val unionRDD = rdd1.union(rdd2)
   unionRDD.collect.foreach(x => print(x + " "))
   sc.stop 

輸出:

1 2 3 3 4 5

Spark函數詳解系列之RDD基本轉換

二、spark streaming從某一時間戳消費

粗粒度的方式(誤差約±15分鐘)
在這裏插入圖片描述
記得改回接上次,否則重啓後又回溯舊數據了

三、使用pyspark時,機器上沒裝 numpy

archives=viewfs:///user/hadoop-test/hdp-sample/numpy_env.zipspark.yarn.appMasterEnv.PYSPARK_PYTHON=./numpy_env.zip/numpy_env/bin/python

將以上設置加到配置裏面

四、spark中創建指定格式的RDD

val rdd:RDD[(String,Int)] = sc.makeRDD(List(("k01",3),("k02",6),("k03",2),("k01",26)))
val rdd:RDD[(String,Int)] = sc.parallelize(List(("k01",3),("k02",6),("k03",2),("k01",26)))

Spark筆記:RDD基本操作(上)

Spark筆記:RDD基本操作(下)

五、寫入HDFS時報錯目錄已經存在

可以指定覆蓋寫入

conf.set("spark.hadoop.validateOutputSpecs","false")

六、spark streaming 使用fastjson

在spark-steaming中,使用fast-json更加穩定,json-lib經常出現莫名問題,而且fastjson的解析速度更快.

import com.alibaba.fastjson.JSON

object Json {
  def main(args: Array[String]): Unit = {
    val str2 = "{\"et\":\"kanqiu_client_join\",\"vtm\":1435898329434,\"body\":{\"client\":\"866963024862254\",\"client_type\":\"android\",\"room\":\"NBA_HOME\",\"gid\":\"\",\"type\":\"\",\"roomid\":\"\"},\"time\":1435898329}"
       val json=JSON.parseObject(str2)
       //獲取成員
       val fet=json.get("et")
       //返回字符串成員
       val etString=json.getString("et")
       //返回整形成員
       val vtm=json.getInteger("vtm")
       println(vtm)
       //返回多級成員
       val client=json.getJSONObject("body").get("client")
       println(client)

https://blog.csdn.net/qq_36330643/article/details/77152430

七、spark中創建空的RDD

val emptyRDD = new SparkContext(new SparkConf()).emptyRDD[T]

https://blog.csdn.net/chen20111/article/details/80943849

八、HDFS上傳文件

hadoop fs -mkdir  ./test/
hadoop  fs -put testv3  ./test/

注意上面的 /

九、spark中filter操作使用全局變量提示沒有初始化問題

該操作默認使用了全局變量,期間如果改動該變量值,會造成無法使用最新的數值;

最佳方案:filter操作等裏面使用傳入值的變量,比較穩定

十、Caused by: org.apache.spark.SparkException: A master URL must be set in your

在spark運行日誌中(運行模式是yarn)會有三個yarn.client出現,說明每個子類任務都會有一個相對應的driver,這個說明每個子類的任務開始都會實例化自身的sparkSession,但是一個spark 應用對應了一個main函數,放在一個driver裏,driver裏有一個對應的實例(spark context).driver 負責向各個節點分發資源以及數據。那麼如果你把創建實例放在了main函數的外面,driver就沒法分發了。所以如果這樣寫在local模式下是可以成功的,在分佈式就會報錯

改變代碼結構把抽象類中的公有的資源,在main函數中創建

https://blog.csdn.net/sinat_33761963/article/details/51723175
https://www.cnblogs.com/ldsggv/p/9258865.html

十一、spark中[Ljava.lang.String;@7700b3c2

在spark上面跑下面代碼時,即讀取hdfs上面保存的list類型string,直接collect.toString後是一個string[], 所以直接打印的話是一個數組地址

讀取的文本是按照換行符轉換的,所以應該mkString將一個Array[String] 轉換成一個stringk
val modelString2 = modelString.mkString("")



 val rddModelJson = sc.parallelize(List(modelJson))
    rddModelJson.repartition(1).saveAsTextFile(modelPath)
    println(s"保存完畢")
    
println(s"從hdfs上面加載txt並轉換成模型")
    val modelText = sc.textFile(modelPath)
    val modelString = modelText.collect().toString
    println(s"讀取到的模型字符串:${modelString}")

https://my.oschina.net/nenusoul/blog/662410?p=1

https://www.imooc.com/qadetail/173418

十二、Spark中將對象序列化存儲到hdfs

該代碼保存的爲object形式

import org.apache.spark.storage.StorageLevel
import scala.collection.JavaConverters._
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.net.URI
import java.util.Date
import org.ansj.library.UserDefineLibrary
import org.ansj.splitWord.analysis.NlpAnalysis
import org.ansj.splitWord.analysis.ToAnalysis
import org.apache.hadoop.fs.FSDataInputStream
import org.apache.hadoop.fs.FSDataOutputStream
import org.apache.hadoop.fs.FileSystem
import org.apache.hadoop.fs.FileUtil
import org.apache.hadoop.fs.Path
import org.apache.hadoop.hbase.client._
import org.apache.hadoop.hbase.{HBaseConfiguration, HTableDescriptor, TableName}
import org.apache.hadoop.hbase.filter.FilterList
import org.apache.hadoop.hbase.filter.PageFilter
import org.apache.hadoop.hbase.filter.RegexStringComparator
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp
import org.apache.hadoop.hbase.mapreduce.TableInputFormat
import org.apache.hadoop.hbase.protobuf.ProtobufUtil
import org.apache.hadoop.hbase.util.{Base64, Bytes}
import com.feheadline.fespark.db.Neo4jManager
import com.feheadline.fespark.util.Env
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.rdd._
import org.apache.spark.mllib.feature.{Word2Vec, Word2VecModel}
import scala.math.log
import scala.io.Source

object Word2VecDemo {

  def convertScanToString(scan: Scan) = {
    val proto = ProtobufUtil.toScan(scan)
    Base64.encodeBytes(proto.toByteArray)
  }

  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setAppName("Word2Vec Demo")
    sparkConf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
    sparkConf.set("spark.kryoserializer.buffer", "256m")
    sparkConf.set("spark.kryoserializer.buffer.max","2046m")
    sparkConf.set("spark.akka.frameSize", "500")
    sparkConf.set("spark.rpc.askTimeout", "30")
    

    val sc = new SparkContext(sparkConf)
    val hbaseConf = HBaseConfiguration.create()
    hbaseConf.set("hbase.zookeeper.quorum", "myzookeeper")

    hbaseConf.set(TableInputFormat.INPUT_TABLE, "crawled")

    val scan = new Scan()
    val filterList:FilterList = new FilterList(FilterList.Operator.MUST_PASS_ALL)
    
    val comp:RegexStringComparator = new RegexStringComparator(""".{1500,}""")
    
    val articleFilter:SingleColumnValueFilter = new SingleColumnValueFilter(
    "data".getBytes,
    "article".getBytes,
    CompareOp.EQUAL,
    comp
    )
    
    filterList.addFilter(articleFilter)
    filterList.addFilter(new PageFilter(100))
    
    scan.setFilter(filterList)
    scan.setCaching(50)
    scan.setCacheBlocks(false)
    hbaseConf.set(TableInputFormat.SCAN,convertScanToString(scan))

    val crawledRDD = sc.newAPIHadoopRDD(
      hbaseConf,
      classOf[TableInputFormat],
      classOf[org.apache.hadoop.hbase.io.ImmutableBytesWritable],
      classOf[org.apache.hadoop.hbase.client.Result]
    )
 
    val articlesRDD = crawledRDD.filter{
      case (_,result) => {
          val content = Bytes.toString(result.getValue("data".getBytes,"article".getBytes))
          content != null
      }
    }

    val wordsInDoc = articlesRDD.map{
      case (_,result) => {
          val content = Bytes.toString(result.getValue("data".getBytes,"article".getBytes))
          if(content!=null)ToAnalysis.parse(content).asScala.map(_.getName).toSeq
          else Seq("")
      }
    }
    
    val fitleredWordsInDoc = wordsInDoc.filter(_.nonEmpty)
    
    val word2vec = new Word2Vec()
    val model = word2vec.fit(fitleredWordsInDoc)
   
    //---------------------------------------重點看這裏-------------------------------------------------------------
    //將上面的模型存儲到hdfs
    val hadoopConf = sc.hadoopConfiguration
    hadoopConf.set("fs.defaultFS", "hdfs://myhadoop:9000/")
    val fileSystem = FileSystem.get(hadoopConf)
    val path = new Path("/user/hadoop/data/mllib/word2vec-object")
    val oos = new ObjectOutputStream(new FSDataOutputStream(fileSystem.create(path)))
    oos.writeObject(model)
    oos.close
    
    //這裏示例另外一個程序直接從hdfs讀取序列化對象使用模型
    val ois = new ObjectInputStream(new FSDataInputStream(fileSystem.open(path)))
    val sample_model = ois.readObject.asInstanceOf[Word2VecModel]
   
    /*
    * //你還可以將序列化文件從hdfs放到本地, scala程序使用模型
    * import java.io._
    * import org.apache.spark.mllib.feature.{Word2Vec, Word2VecModel}
    * val ois = new ObjectInputStream(new FileInputStream("/home/cherokee/tmp/word2vec-object"))
    * val sample_model = ois.readObject.asInstanceOf[Word2VecModel]
    * ois.close
    */
    //--------------------------------------------------------------------------------------------------------------
  }
}

https://my.oschina.net/waterbear/blog/525347

十三、hdfsTotal size of serialized results of 16 tasks (1048.5 MB) is bigger than spark.driver.maxResultSize (1024.0 MB)

當操作data.take(5).foreach(println)時發生上述報錯

conf.set("spark.driver.maxResultSize", "4g")

https://stackoverflow.com/questions/47996396/total-size-of-serialized-results-of-16-tasks-1048-5-mb-is-bigger-than-spark-dr

十四、spark海量數據去重策

採用分區排序去重

DataFrame.drop_duplicates(subset=None, keep=‘first’, inplace=False)

https://blog.csdn.net/MsSpark/article/details/83451491
https://blog.csdn.net/abc50319/article/details/80353808

十五、spark解決group by造成的數據傾斜問題

主要是將傾斜的數據加上隨機前綴,二次處理,逐漸降低處理壓力

https://blog.csdn.net/iilegend/article/details/97676109
https://blog.csdn.net/qq_38799155/article/details/80178022

十六、spark2.2與spark1.6變動部分

spark2.2使用了dataSet的封裝格式,因此1.6版本中的從DataFrame提取到的rdd在2.2中會變成dataSet,需要使用 .rdd 操作進行轉換,前提是沒有使用各種高級api,建議自己寫各種方法

https://blog.csdn.net/iilegend/article/details/97676109
https://blog.csdn.net/qq_38799155/article/details/80178022

十七、spark2.2報錯java.io.InvalidClassException: org.apache.spark.sql.catalyst.expressions.GenericRow; local class incompatible: stream classdesc serialVersionUID = -1935478142066148712, local class serialVersionUID = -17966769693457883

注意下面的.cache和.rdd順序

 dataRdd.write.parquet(path)
val dataAll = sqlContext.read.parquet(allDataFiles).na.drop().cache().rdd

val dataAll = sqlContext.read.parquet(allDataFiles).na.drop().rdd.cache()   
//該寫法會報上面的錯!!

內部函數傳參時,尤其使用mapValues時,不要傳參SparkContext上,該類沒有序列化

https://blog.csdn.net/u010770919/article/details/41441149

十八、spark2.2報錯 InvalidClassException: no valid constructor或者Caused by: java.io.NotSerializableException: org.apache.mahout.math.DenseMatrix

在使用序列化和反序列化時,如果使用的類沒有空的構造函數,就會報這個錯誤;需要注意的是父類如果既沒有繼承序列化也沒有空的構造函數,則子類此時無法寫空的構造函數;解決方法是提取父類方法到子類中,子類直接繼承序列化接口;

十九、spark2.2如何對rdd median 中位數求解

通過帶索引的rdd進行lookup操作

import org.apache.spark.SparkContext._

  val rdd: RDD[Int] = ???

  val sorted = rdd.sortBy(identity).zipWithIndex().map {
    case (v, idx) => (idx, v)
  }

  val count = sorted.count()

  val median: Double = if (count % 2 == 0) {
    val l = count / 2 - 1
    val r = l + 1
    (sorted.lookup(l).head + sorted.lookup(r).head).toDouble / 2
  } else sorted.lookup(count / 2).head.toDouble

https://www.cnblogs.com/bonelee/p/7154234.html

二十、spark2.2中的DataSet和SparkSession

1.主要接口變化
1.1 SparkSession
Spark2.0向前兼容了之前的SparkContext以及HiveContext,同時新增了一個統一的入口:SparkSession,可以簡單的認爲SparkSession集成了SparkContext和HiveContext。

使用enableHiveSupport就能夠支持hive,相當於hiveContext,如:

// 創建一個支持Hive的SparkSession
val sparkSession = SparkSession.builder().enableHiveSupport().getOrCreate()
 
// sql查詢
sparkSession.sql("select * from xxx limit 10")

2.2 RDD/DataFrame/Dataset
區別和聯繫:

RDD:類型安全,面向對象編程風格,接口靈活

DataFrame:提供了查詢優化器,分區剪枝,自動判斷是否使用broadcast join等功能,對rdd進行了大量的優化。對spark瞭解不深的編程/分析人員非常友好。可以視爲Row類型的Dataset (Dataset[Row]),非類型安全。

DataSet:繼承了DataFrame的優點,強類型安全,面向對象編程風格。

在官方的描述中RDD以後將會逐步作爲spark內部的底層接口,鼓勵開發者儘量使用DataSet接口編程。

DataSet創建:Dataset 結合了 rdd 和 DataFrame 上大多數的API,可以從rdd,dataFrame轉化,也可以從原始數據直接生成。

//創建RDD
scala> val rdd1 = sc.textFile("README.md")
rdd1: org.apache.spark.rdd.RDD[String] = README.md MapPartitionsRDD[3] at textFile at <console>:24

//創建DataFrame
scala> val df = spark.read.text("README.md")
df: org.apache.spark.sql.DataFrame = [value: string]

//創建DataSet
scala> val ds1 = spark.read.textFile("README.md")
ds1: org.apache.spark.sql.Dataset[String] = [value: string]

//RDD轉換爲DataSet
scala> val ds2 = rdd1.toDF().as[String]
ds2: org.apache.spark.sql.Dataset[String] = [value: string]

//DataFrame轉換爲DataSet
scala> val ds3 = df.as[String]
ds3: org.apache.spark.sql.Dataset[String] = [value: string] 

二十一、Spark Session用法DataSet與DataFrame轉換成RDD

https://www.cnblogs.com/leboop/p/9455437.html

dataFrame的用法

二十二、requirement failed: Column features must be of type org.apache.spark.ml.linalg.VectorUDT@3bfc3ba7

問題解決:

導入jar包出錯:
如果您的Spark> 2.x導入
org.apache.spark.ml.linalg.Vector
並不是
org.apache.spark.mllib.linalg.Vector
https://blog.csdn.net/qq_33286695/article/details/86573446

二十三、spark中DenseMatrix和array的轉換

注意下面的:val dm = DenseMatrix(e.toArray:_*)

import scala.collection.mutable.ArrayBuffer

val rows: Array[Row] = df2.collect()
//rows: Array[org.apache.spark.sql.Row] = Array([-1.35980713367,...

var e = ArrayBuffer[Array[Double]]()

for(row <- rows){
  val x = row.toSeq.toArray
  val y = x.map(_.toString.toDouble)
  e += y
}
val dm = DenseMatrix(e.toArray:_*)

https://stackoverflow.com/questions/48277673/convert-an-arrayorg-apache-spark-sql-row-to-a-densematrixdouble-in-scala

二十四、java.lang.NoSuchMethodError: com.google.common.base.Splitter.splitToList(Ljava/lang/CharSequence;)Ljava/util/List;

原因是本地的jar包被SPARK_HOME/lib中的jar覆蓋。spark程序在提交到yarn時,除了上傳用戶程序的jar,還會上傳SPARK_HOME的lib目錄下的所有jar包(參考附錄2 )。如果你程序用到的jar與SPARK_HOME/lib下的jar發生衝突,那麼默認會優先加載SPARK_HOME/lib下的jar,而不是你程序的jar,所以會發生“ NoSuchMethodError”。

程序的jar用的是guava18版本(mvn dependency:tree可查出版本),但是SPARK_HOME/lib下用的是guava14版本。lib下的guava14覆蓋了用戶的guava18,而guava14中並沒有splitToList()方法, 所以報錯

由於默認情況下,優先級SPARK_HOME/lib/jar包 > 用戶程序中的jar包, 如果想讓用戶程序jar優先執行,那麼要使用 spark.yarn.user.classpath.first (spark1.3以前)或者 spark.executor.userClassPathFirst 和spark.driver.userClassPathFirst 參數。
這些參數能讓用戶的jar覆蓋SPARK_HOME/lib的jar。在spark conf中將他們設置爲"true"即可。

    val conf = new SparkConf().setAppName("test")
        conf.set("spark.driver.userClassPathFirst", "true")

https://www.jianshu.com/p/0fe48bc43a8c

二十五、Spark 鍵值對RDD操作

最實用的是mapValues
https://www.cnblogs.com/yongjian/p/6425772.html

二十六、java.lang.NoClassDefFoundError: Could not initialize class org.nd4j.linalg.factory.Nd4j

deeplearning4j包需要使用ND4J的本地實現作爲CPU後端:採用如下帶platform的依賴項

 <dependency>
            <groupId>org.nd4j</groupId>
            <artifactId>nd4j-native-platform</artifactId>
            <version>1.0.0-beta6</version>
        </dependency>

https://blog.csdn.net/bewithme/article/details/83449116
http://www.voidcn.com/article/p-ewkarike-brx.html
https://deeplearning4j.org/cn/quickstart

二十七、使用spark mllib進行隨機森林和GBDT模型訓練

  1. https://blog.csdn.net/weixin_34277853/article/details/93726894
  2. https://blog.csdn.net/redhatforyou/article/details/75912262?utm_source=blogxgwz1
  3. https://blog.csdn.net/oppo62258801/article/details/79279429
  4. https://www.csdn.net/gather_20/MtTaYg4sODQwNS1ibG9n.html
  5. https://baijiahao.baidu.com/s?id=1629307366316201484&wfr=spider&for=pc GBDT

二十八、Job aborted due to stage failure ExecutorLostFailure (executor 2101 exited caused by one of the running tasks) Reason: Container marked as failed: container_1491814332016_46280_01_009179 on host

  1. 移除RDD緩存操作,增加該JOB的spark.storage.memoryFraction係數值,增加該job的spark.yarn.executor.memoryOverhead值
  2. 增大分區數,使用 set spark.sql.shuffle.partitions=1000(或更大)
  3. 調整代碼,減少數據讀取量

https://www.cnblogs.com/cstzhou/p/6437270.html
https://blog.csdn.net/xwc35047/article/details/53933265

二十九、spark cartesian優化與加速

cartesian操作非常耗時,可以通過將其中一個broadcast,另外一個與之進行flatmap操作,即產生了笛卡爾積的交集數據

https://www.dazhuanlan.com/2019/11/17/5dd0448cc8794/?cf_chl_jschl_tk=c0f38fa619a279dc1b4624cdac9b3cf4f35c46fd-1589967586-0-Ad7WuC8GKTaQFfVIsyZ7dzpDVJARVGbVCKzn8WtIBn8ef2TZnqO2s9u1WY8O7HzsIFip2EE6HcGzgGhppsA3nN9ts5GpGVggOcwWpF46SXKv16ML4Eb2tjHBw4d87NkaXnZnPduYXZqrho70u4UA1UyfKA89V1sHVkYUPnCyHq61_D-nUET-2RgbRr0eVwtAKBBmgxyplCTKdrIKEYkw-YK3tALiBWyLKyAzw9UAsmeXGeSqn-mfJkaD9hVTrwHKXt65CncJigmcHX98J8Mk7EUPRrJFEnL7zECoYQ89Hd6Mpzu8gai7Eear2qSapy9LBw

三十、spark進行倒排索引

其實就是先進行key, value倒置,再進行reduceByKey操作
https://blog.csdn.net/u013560925/article/details/80329288

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