RDD的函数传递
主要是序列化的问题,对象在JVM中表示的方式是字节
序列化的产生是为了分布式的程序,现在需要将这个对象从Driver传递给Executor,那么传递的过程中需要的是010101这样的字节,那么对面接收的字节如何获取,那么就需要使用序列化
那么说一个场景:
spark是一个分布式的计算框架,当从Driver端将数据传递到Executor的时候就需要进行序列化
//定义了一个类这里的有一个query的参数并进行了序列化
class SearchFunctions(val query: String) extends Serializable{
//第一个方法是判断输入的字符串是否存在query 存在返回true,不存在返回false
def isMatch(s: String): Boolean = {
s.contains(query)
}
def getMatchesFunctionReference(rdd: org.apache.spark.rdd.RDD[String]):
org.apache.spark.rdd.RDD[String] = {
// 问题:"isMatch"表示"this.isMatch",因此我们要传递整个"this"
rdd.filter(isMatch)
}
def getMatchesFieldReference(rdd: org.apache.spark.rdd.RDD[String]): org.apache.spark.rdd.RDD[String] = {
// 问题:"query"表示"this.query",因此我们要传递整个"this"
rdd.filter(x => x.contains(query))
}
def getMatchesNoReference(rdd: org.apache.spark.rdd.RDD[String]):
org.apache.spark.rdd.RDD[String] = {
// 安全:只把我们需要的字段拿出来放入局部变量中
val query_ = this.query
rdd.filter(x => x.contains(query_))
}
}
object SearchFunctions {
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf()
conf.setAppName("SearchFunctions")
conf.setMaster("local[2]")
val sc: SparkContext = new SparkContext(conf)
val rdd = sc.parallelize(List("hello java", "hello scala hello", "hello hello"))
val sf = new SearchFunctions("hello")
// sf.getMatchesFunctionReference(rdd)
// sf.getMatchesFieldReference(rdd)
sf.getMatchesNoReference(rdd)
}
}
总结:
1.如果DRR的转换操作中使用到了class的方法或者变量,那么该class需要支持序列化
2.如果通过局部变量的方式将class中的变量赋值为局部变量,那么不需要传递传递对象,比如最后一个方法
3.使用过程中尽量使用局部变量传递的方式,可以减少网络io
RDD的运行
我们在以前书写代码的时候会发现,将每一个算子单独拿出来使用的,而spark使用的是scala的语言,那么必然可以使用链式编程,那么这个rdd为什么可以这样写如何执行的呢?
sc.textFile(“xx”).flatMap(.split("")).map((,1)).reduceByKey(+).saveAsTextFile(“xx”)
RDD的依赖关系
RDD和它依赖的父RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency)。
窄依赖
窄依赖指的是每一个父RDD的Partition最多被子RDD的一个Partition使用
总结:窄依赖我们形象的比喻为独生子女
款依赖
宽依赖指的是多个子RDD的Partition会依赖同一个父RDD的Partition
总结:宽依赖我们形象的比喻为超生
ps:宽依赖就会发生shuffle过程
下图是原码中的一张图:可以发现一个问题Dependency(依赖)的意思
可以发现ShuffleDependency是其子类(即宽依赖)
NarrowDependency是其子类(即窄依赖)