【spark】6.编程进阶

累加器

提供了将工作节点中的值聚合到启动器程序中的简单语法。常见用途是调试时对作业执行过程中的事件进行计数。

# 例如累加空行
file = sc.textFile(inputFile)
# 创建累加器并初始化为0
blankLines = sc.accumulator(0)
def extractCallSigns(line):
	global blankLines
	if line == '':
		blankLines += 1
	return line.split(' ')

callSigns = file.flatMap(extractCallSigns)
callSigns.saveAsTextFile('')
print(blankLines)

广播变量

可以让程序高效的向所有工作节点发送一个较大的只读值

signPrefixes = sc.broadcast(loadCallSignTable())
def processSignCount(sign_count, signPrefixes):
	country = lookupCountry(sign_count[0], signPrefixes.value)
	count = sign_count[1]
	return(country, count)

countryContactCounts = (contactCounts
						.map(processSignCount)
						.reduceByKey((lambda x,y: x+y)))
	
countryContactCounts.saveAsTextFile(outpuDir + "/countries.txt")
  • 通过sparkcontext.broadcast创建
  • 通过value属性访问
  • 变量只会被发到各个节点各一次

note:可以使用spark.serializer属性选择另外一个序列化库来优化序列化过程

基于分区进行操作

基于分区对数据进行操作可以让我们避免为每个元素进行重复的配置工作,诸如打开数据库连接或创建随机数生成器等操作,都是我们应该避免为每一个元素进行的配置操作。

# 创建共享连接池
def processCallSign(signs):
	# 创建连接池
	http = urllib3.PoolManager()
	# 与每一条呼号记录相关联的URL
	urls = map(lambda x: "http://73s.com/qsos/%s.json"% x, signs)
	# 创建请求(非阻塞)
	request = 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):
	# 获取呼号
	return input.mapPartitions(lambda callSign: processCallSigns(callSigns))

conractsContactList = fetchCallSigns(validSigns)

使用mapPartitions()避免创建对象的开销

# 计算平均值
# 不使用
def combineCtrs(c1, c2):
	return (c1[0] + c2[0], c1[1] + c2[1])

def basicAvg(nums):
	num.map(lambda num: (num, 1)).reduce(combineCtrs)

# 使用
def partitionCtr(nums):
	sumCount = [0,0]
	for num in nums:
		sumCount[0] += num
		sumCount[1] += 1
	return [sumCount]

def fastAvg(nums):
	sumCount = num.mapPartitions(partitionCtr).reduce(combineCtrs)
	return sumCount[0]/float(sumCount[1]) 

与外部程序间的管道

如果spark支持的语言不能实现开发要求,spark提供了一种通用机制,可以将数据通过管道传递给用其他语言编写的程序,比如R语言等等。
spark在RDD上提供了pipe()方法,pipe()方法可以让我们使用任意以重语言实现spark作业的部分逻辑,只要它可以读取linux标准流。

使用pipe()调用R驱动器程序
distScript = './src/R/finddistance.R'
distScriptName = 'finddistance.R'
sc.addFile(distScript)
def hasDistInfo(call):
	'验证一次呼叫是否有计算距离时所必须的字段'
	requiredFields = ['mylat', 'mylot', 'contactlat', 'contactlot']
	return all(map(lambda f: call[f], requiredFilelds))

def formatCall(call):
	'将数据格式重新组织使之可以被R程序解析'
	return '{0},{1},{2},{3}'.format(
		call['mylat'],call['mylot'],
		call['contactlat'],call['contactlot'])

pipeInputs = contactsContactList.values().flatMap(
	lambda calls: map(formatCall, filter(hasDistInfo, calls)))
distances = pipeInputs.pipe(SparkFiles.get(distScriptName))
print distances.collect()

数值RDD操作

count(),max(),min(),sum(),mean(),variance()~~~ 等等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值