共享变量:
累加器和广播变量
累加器: 对数据进行聚合
广播变量: 高效分发较大的对象
#在python中累加空行
file = sc.textFile(inputFile)
#创建Accumulator[Int]并初始化
blankLines = sc.accumulator(0)
def extractCallsigns(line):
#访问全局变量
global blankLines
if(line ==""):
blankLines += 1
return line.split(" ")
callSigns = file.flatMap(extractCallsigns)
callSigns.saveAsTextFile(outputDir+"/callSigns")
print("Blank lines: %d" % blankLines.value)
scala编写累加器
统计累加空行
#在scala 中累加空行
val sc = new SparkContext(...)
val file = sc.textFile("file.txt")
//创建Accmulator[Int]并初始化为0
val blanLines = sc.accmulator(0)
val callSigns = file.flatMap(
line => {
if(line ==""){
//累加器加1
blankLines += 1
}
line.split(" ")
})
callSigns.savsAsTextFilr("output.txt")
println("Blank lines:" + blankLines.value)
Java 中累加空行
#在Java 中累加空行
JavaRDD rdd = sc.textFile(args[1])
final Accmulator blankLines = sc.accumulator(0)
JavaRDD callSigns = rdd.flatMap(
new FlatMapFunction(){
public Iterable call(String line){
if(line.equals(""))
blankLines.add(1)
}
return Arrays.asList(line.split(" "))
}
);
callSigns.saveAsTextFile("output.txt");
System.out.println("Blank lines:" + blankLines.value());
在python中,使用累加器进行错误
#创建用来验证呼号的累加器
validSignCount = sc.accumulator(0)
invalidSignCount = sc.accumulator(0)
def validateSign(sign):
global validSignCount ,invalidSignCount
if re.match(r"\A\d?[a-zA-Z]{1,2}\d{1,4}[a-zA-Z]{1,3}\Z",sign):
validSignCount +=1
return True
else:
invalidSignCount +=1
return False
#对每个呼号的联系次数进行计数
validSigns = callSigns.filter(validateSign)
contactCount = validSigns.map(lambda sign:(sign,1)).reduceByKey(lambda(x,y):x +y)
#强制求值计算计数
contactCount.count()
if invalidSignCount.VALUE < 0.1 * validSignCount.VALUE:
contactCount.saveAsTextFile(outputDir+"/contactCount")
else:
print("Too many errors : %d in % d"(invalidSignCount.value,validSignCount.value))
自定义累加器:
http://spark/apache.org/docs/latest/api/scala/index.html#package
使用任意值来代替数值加法。
#在python中查询国家
#查询RDD contactCounts中的呼号的对应位置。
#将呼号前缀读为国家代码来进行查询
signPrefixes = loadCallSignTable()
def proxessSignCount(sign_count,signPrefixes):
country = lookupCountry(sign_count[0],signPrefixes)
count = sign_count[1]
return (country,count)
countryContactCounts =(contactCount.map(proxessSignCount).reduceByKey((lambda x,y: x+y)))
未用广播变量,signPrefixes 需要每次加载,并且从主节点为每个任务发送一个这样的数组,代价很大。
#在python中查询国家
#查询RDD contactCounts中的呼号的对应位置。
#将呼号前缀读为国家代码来进行查询 #使用广播变量 !!!!!!!!!!!!
signPrefixes = sc.broadcast(loadCallSignTable())
def proxessSignCount(sign_count,signPrefixes):
country = lookupCountry(sign_count[0],signPrefixes)
count = sign_count[1]
return (country,count)
countryContactCounts =(contactCount.map(proxessSignCount).reduceByKey((lambda x,y: x+y)))
广播优化:
java选择 spark.seriallizer Kryo这种更快的序列化库或者对java对象使用 java.io.Externalizable
或者reduce( )方法为Python 的pickle库定义自定义的序列化。
#在python中使用共享连接池
def processCallSigns(signs):
"""使用连接池查询呼号"""
#创建一个连接池
http = urllib3.PoolManager()
#与每条呼号记录相关联的URL
urls = map(lambda x : "http://73s.com/qsos/%s.json" % x,signs)
#创建请求(非阻塞)
requests = map(lambda x:(x,http.request('GET',x)),urls)
#获取结果
result = map(lambda x:(x[0],json.loads(x[1].data)),requests)
#删除空的结果并返回
return filter(lambda x: x[1] is not None, result)
def fetchCallSigns(input):
"""获取呼号"""
#json 解析器
return input.mapPartitions(lambda callSigns : processCallSigns(callSigns))
contactsContactList = fetchCallSigns(validSigns)
数值RDD操作
#用python异常异常值
#要把String类型RDD 转化为数字数据,这样才能实用统计函数并移除异常值
distanceNumberics = distances.map(lambda string : float(string))
stats = distanceNumberics.stats()
stddev = stdts.stdev()
mean = stats.mean()
reasonableDistances = distanceNumberics.filter(
lambda x : math.fabs(x - mean) < 3 * stddev)
print(reasonableDistances.collect())