从Driver关联数据
一.创建一个Object的单例对象
知识点:Driver初始化一个object,这个单例对象要伴随着Task发送到Executor,但是一个Executor中只有一份,必须实现序列化接口, 有可能会出现线程安全问题.
- 创建一个单列对象代码如下:
package day05
/**
* 必须序列化数据,因为是在Driver初始化,
* 因为数据要伴随着Task的运算都是在Excutor端进行的,如果不序列化,会报错
*/
object RulesMapObj extends Serializable {
val rules = Map("ln" -> "辽宁省", "bj" -> "北京市", "sd" -> "山东省")
}
- 关联Driver数据代码如下:
package day05
import java.net.{InetAddress, InetSocketAddress}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext, TaskContext}
object SerTest01 {
def main(args: Array[String]): Unit = {
val isLocal = args(0).toBoolean
val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
val sc: SparkContext = new SparkContext(conf)
//--------在Driver端初始化---------
val rulesMap = RulesMapObj
val lines: RDD[String] = sc.textFile(args(1))
//对数据进行Map关联中文名称
val wordAndProvince: RDD[(String, String, String, Int, Long, RulesMapObj.type)] = lines.map(word => {
/**
* 在Excutor端关联外部Driver端的数据,需要被序列化的数据才可以被调用
*/
val province: String = rulesMap.rules(word)
val partitionId = TaskContext.get().partitionId()
val hostname = InetAddress.getLocalHost.getHostName
val threadId = Thread.currentThread().getId
(word, province, hostname, partitionId, threadId, rulesMap)
})
wordAndProvince.saveAsTextFile(args(2))
sc.stop()
}
}
二.实例化一个类的实例
知识点:Driver实例化一个类的实例,在函数内中引用了这个实例,伴随着Task发送到Executor,每个Task都独有一个单独的实例,必须实现序列化接口
- 实例化一个类的实例代码如下:
package day05
class RulesMapClass extends Serializable {
val rules = Map("ln" -> "辽宁省", "bj" -> "北京市", "sd" -> "山东省")
}
- 关联Driver端数据代码如下:
package day05
import java.net.InetAddress
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext, TaskContext}
object SerTest02 {
def main(args: Array[String]): Unit = {
val isLocal = args(0).toBoolean
//创建SparkConf,然后创建SparkContext
val conf = new SparkConf().setAppName(this.getClass.getSimpleName)
if (isLocal) {
conf.setMaster("local[*]")
}
val sc = new SparkContext(conf)
//在Driver端初始化【new一个类的实例】
val rulesMap = new RulesMapClass
//sh
val lines: RDD[String] = sc.textFile(args(1))
//对数据进行map关联中文名称
val wordAndProvince = lines.map(word => {
//关联外部的规则
//存在闭包:函数内部用到了一个函数外部的引用类型,函数式在Executor中被调用的
//在Driver端引用的数据要伴随着Task一起发送到Executor中
val province = rulesMap.rules(word)
val partitionId = TaskContext.get().partitionId()
val hostname = InetAddress.getLocalHost.getHostName
val threadId = Thread.currentThread().getId
(word, province, hostname, partitionId, threadId, rulesMap)
})
//将处理好的数据写回到HDFS
wordAndProvince.saveAsTextFile(args(2))
sc.stop()
}
}
三:总结
- 关联Driver端数据,不管是Object和Class,都需要实现序列化接口.
- 如果关联数据是一个单列对象,那么一个Excutor中只有一个单列对象,如果关联数据是一个类的实列,那么Excutor端中,每一个Task对应一个单独的实列
从Excutor中关联数据
一.创建一个Object的单例对象
知识点:在Excutor使用一个Object,这个Object不用实现序列化,这个Object在Executor中初始化的,并且一个Executor中只有一份,有可能会出现线程安全问题
- 创建一个单列对象代码如下:
package day05
import java.net.InetAddress
object RulesMapObjNoSer {
{
val hostName = InetAddress.getLocalHost.getHostName
}
val rules = Map("ln" -> "辽宁省", "bj" -> "北京市", "sd" -> "山东省")
}
- 关联Excutor数据代码如下:
package day05
import java.net.InetAddress
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext, TaskContext}
object SerTest03 {
def main(args: Array[String]): Unit = {
val isLocal = args(0).toBoolean
//创建SparkConf,然后创建SparkContext
val conf = new SparkConf().setAppName(this.getClass.getSimpleName)
if (isLocal) {
conf.setMaster("local[*]")
}
val sc = new SparkContext(conf)
val lines: RDD[String] = sc.textFile(args(1))
//对数据进行map关联中文名称
val wordAndProvince = lines.map(word => {
//关联外部的规则
//RulesMapObjNoSer是在Executor端初始化的
val province = RulesMapObjNoSer.rules(word)
val partitionId = TaskContext.get().partitionId()
val hostname = InetAddress.getLocalHost.getHostName
val threadId = Thread.currentThread().getId
(word, province, hostname, partitionId, threadId, RulesMapObjNoSer)
})
//将处理好的数据写回到HDFS
wordAndProvince.saveAsTextFile(args(2))
sc.stop()
}
}
二.实例化一个类的实例
知识点:在Excutor使用一个类的实例,这个实列对象不用实现序列化,这个实列类的对象在Executor中初始化的,并且一个Executor中每一个Task都单独有一份.
- 实例化一个类的实例代码如下:
package day05
class RulesMapClassNoSer {
val rules = Map("ln" -> "辽宁省", "bj" -> "北京市", "sd" -> "山东省")
}
- 关联Excutor端数据代码如下:
package day05
import java.net.InetAddress
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext, TaskContext}
object SerTest04 {
def main(args: Array[String]): Unit = {
val isLocal = args(0).toBoolean
//创建SparkConf,然后创建SparkContext
val conf = new SparkConf().setAppName(this.getClass.getSimpleName)
if (isLocal) {
conf.setMaster("local[*]")
}
val sc = new SparkContext(conf)
//sh
val lines: RDD[String] = sc.textFile(args(1))
//对数据进行map关联中文名称
val wordAndProvince = lines.map(word => {
//关联外部的规则
//在Executor端创建的RulesMapClassNoSer
val rulesMap = new RulesMapClassNoSer
val province = rulesMap.rules(word)
val partitionId = TaskContext.get().partitionId()
val hostname = InetAddress.getLocalHost.getHostName
val threadId = Thread.currentThread().getId
(word, province, hostname, partitionId, threadId, rulesMap)
})
//将处理好的数据写回到HDFS
wordAndProvince.saveAsTextFile(args(2))
sc.stop()
}
}
三:总结
- 关联Excutor端数据,不管是Object和Class,都不需要实现序列化接口.
- 如果关联数据是一个单列对象,那么一个Excutor中只有一个单列对象,如果管数据是一个类的实列,那么Excutor端中,每一个Task对应一个单独的实列