我可能错过了一些基本的Spark概念。我试图将整数的RDD转换为逗号分隔的字符串。目前我正在通过将RDD收集为List并使用其Iterator来实现。但是,在对JVM进行概要分析时,似乎它将所有工作都放在一个看起来效率不高的单个线程中。因此,我试图在RDD本身上调用forEach方法,但它表现得很奇怪。以下是我的单元测试
JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1,2,3));
StringBuilder sb = new StringBuilder("");
rdd.foreach(t->{
System.out.println(String.valueOf(t));
if(sb.length() > 0)
sb.append(",");
sb.append(String.valueOf(t));
System.out.println(sb);
});
System.out.println(sb.length());
输出:
1
3
2
2
3
1
0
显然,StringBuilder在每次调用时都会重新实例化。还有另一种方法吗?
答案 0 :(得分:1)
您也可以使用mapPartitions来完成。因此,对于每个分区,您将并行工作,然后在最后收集它们。
val rdd1 = sc.parallelize(Seq(1, 2, 3, 4, 5, 6, 7),5) // This will have six number of partitions
val rdd3 = rdd1.mapPartitions(x => {
val str = x.mkString(",")
List(str).iterator
}) // Here we are creating a comma separated string for each partitions only if it has some elements in it
val test1 = rdd3.collect.filterNot(x => {
x.equals("")
}) // filterNot is required as the number of partitions can be more than the number of elements in the sequence( based on spark.default.parallelism property). So some partitions with no elements will generate "" strings.
对于Java,您可以尝试以下代码 -
JavaRDD<Integer> rdd1 = jsc.parallelize(list);
JavaRDD<String> collection = rdd1.mapPartitions((Iterator<Integer> iter) -> {
ArrayList<String> out = new ArrayList<String>();
StringBuffer strbf = new StringBuffer("");
while(iter.hasNext()) {
Integer current = iter.next();
strbf.append(current);
}
out.add(strbf.toString());
return out.iterator();
});
StringBuffer strbfFinal = new StringBuffer("");
collection.collect().forEach(item -> {
if(!"".equals(item)){
strbfFinal.append(item);
}
});
StringBuffer有你附加的数字列表。
答案 1 :(得分:0)
由于forEach
确实在spark中返回Unit/void
,因此您需要在某些集中式事物上进行转发。在这种情况下,我们可以想到accumulators
。累加器用于数值,因此我们需要构建自己的累加器String
。
import org.apache.spark.AccumulatorParam
object StringAccumulator extends AccumulatorParam[String] {
def addInPlace(accum: String, current: String): String = {
s"accum $current"
}
def zero(initialValue: String): String = {
""
}
}
然后使用累加器来合成你的价值。
val sc = prepareConfig()
val acc = sc.accumulator("")(StringAccumulator)
val baseRDD = sc.parallelize(Seq(1, 2, 3))
baseRDD.foreach { x => acc.++=(x.toString()) }
println(acc.value)
结果: 1 2 3
Scala中的解决方案。