我想使用ID对数据进行分区,并在每个分区中使用
- 应用一组操作
-take distinct
在每个分区中执行不同操作将避免混乱。
val rowRDD = sc.textFile("flatten_test_data")
.filter(_.nonEmpty)
.map { l =>
val arr = l.split("\u0001")
val id = arr(0)
val value = arr(1)
(id,value)
}.partitionBy(new HashPartitioner(4))
.persist()
现在做类似的事情 -
rowRDD.foreachPartition {records => applyOpers(records)}
applyOpers(dataset)应该执行类似 -
的操作dataset.withColumn(udf1).withColumn(udf2).distinct
答案 0 :(得分:0)
forEachPartition
在执行程序上执行。因此,您无法在forEachPartition中访问SparkContext / SparkSession。
您可以使用mapPartitions()
替代map()
& foreach()
。每个分区都会调用mapPartitions()
一次map()
& {为{RDD中的每个元素调用foreach()
。主要的优点是,我们可以在每个分区的基础上进行初始化,而不是按元素进行初始化。
我们得到Iterator
作为mapPartition
的参数,通过它我们可以迭代分区中的所有元素。
例如:(示例在java中,但这应该给你一个想法。)
JavaRDD<Integer> rdd = sc.parallelize(
Arrays.asList(1, 2, 3, 4, 5));
FlatMapFunction<Iterator<Integer>, AvgCount> setup = new FlatMapFunction<Iterator<Integer>, AvgCount>() {
@Override
public Iterable<AvgCount> call(Iterator<Integer> input) {
AvgCount a = new AvgCount(0, 0);
while (input.hasNext()) {
a.total_ += input.next();
a.num_ += 1;
}
ArrayList<AvgCount> ret = new ArrayList<AvgCount>();
ret.add(a);
return ret;
}
};
Function2<AvgCount, AvgCount, AvgCount> combine = new Function2<AvgCount, AvgCount, AvgCount>() {
@Override
public AvgCount call(AvgCount a, AvgCount b) {
a.total_ += b.total_;
a.num_ += b.num_;
return a;
}
};
AvgCount result = rdd.mapPartitions(setup).reduce(combine);