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

一、两个同类型的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

发布了26 篇原创文章 · 获赞 41 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/circle2015/article/details/102771232