Spark编程进阶

共享变量:

        累加器广播变量

累加器:    对数据进行聚合

广播变量:  高效分发较大的对象



#在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())



你可能感兴趣的:(个人日记)