首先是map和mapPartitions的区别
1. map():每次处理一条数据。
2. mapPartitions():每次处理一个分区的数据,这个分区的数据处理完后,原RDD中分区的数据才能释放,可能导致OOM。
优化场景如下:
map(fun)里每次都传入一个参数,访问一次fun(一个url请求链接),这样因为map算子是并发执行,url的并发请求访问数会非常高;所以需要把并发数降下来;考虑先重分区,然后对每个分区用mapPartitions(fun)来处理,每个分区内遍历循环调用url请求,这样可以大致把访问并发数控制在和重分区数一致。
mapPartitions()代码如下:
1. 原本调用map()
def log_data(qc_id):
list = []
list.append({json串})
return list
quality_log_rdd = log_data_version_df.rdd
-------------------------------------------------------
quality_log_rdd = quality_log_rdd.map(lambda x : log_data(x))
-------------------------------------------------------
quality_log_list = []
for itemArr in quality_log_rdd.collect():
if itemArr is None or len(itemArr) == 0:
continue
for item in itemArr:
quality_log_list.append(item)
quality_log_df = self.sqlContext.createDataFrame(quality_log_list)
2. 优化后调用mapPartitions()
def log_data(qc_id):
list = []
list.append({json串})
return list
quality_log_rdd = log_data_version_df.rdd
-------------------------------------------------------
def ite_log_data(partitionData):
parDataList = []
for pardata in partitionData:
parDataList.append(log_data(pardata))
return parDataList
quality_log_rdd = quality_log_rdd.repartition(20).mapPartitions(ite_log_data)
--------------------------------------------------------
quality_log_list = []
for itemArr in quality_log_rdd.collect():
if itemArr is None or len(itemArr) == 0:
continue
for item in itemArr:
quality_log_list.append(item)
quality_log_df = self.sqlContext.createDataFrame(quality_log_list)
---里就是mapPartitions()的用法,先定义一个函数ite_log_data,然后再在mapPartitions里调用即可;
值得注意的是,最后返回的结果,map()处理和mapPartitions()处理的rdd里的数据解析起来是完全一致的,都是[{json1}], [{json2}], [{json3}]...[{jsonn}]这种数据集。