我有'inRDD'
格式的RDD[(Vector[(Int, Byte)], Vector[(Int, Byte)])]
,PairRDD(key,value)
,其中密钥为Vector[(Int, Byte)]
,值为Vector[(Int, Byte)]
。
对于关键字段向量中的每个元素(Int, Byte)
,以及值字段向量中的每个元素(Int, Byte)
,我想在输出RDD中获得一个新的(键,值)对作为(Int, Int), (Byte, Byte)
。
这应该给我一个RDD[((Int, Int), (Byte, Byte))]
形式的RDD。
例如,inRDD
内容可能类似,
(Vector((3,2)),Vector((4,2))), (Vector((2,3), (3,3)),Vector((3,1))), (Vector((1,3)),Vector((2,1))), (Vector((1,2)),Vector((2,2), (1,2)))
将成为
((3,4),(2,2)), ((2,3),(3,1)), ((3,3),(3,1)), ((1,2),(3,1)), ((1,2),(2,2)), ((1,1),(2,2))
我有以下代码。
val outRDD = inRDD.flatMap {
case (left, right) =>
for ((ll, li) <- left; (rl, ri) <- right) yield {
(ll,rl) -> (li,ri)
}
}
当inRDD
中的向量很小时,它可以正常工作。但是当向量中有很多元素时,我得到out of memory exception
。增加可用内存
火花只能解决较小的输入,并且对于更大的输入再次出现错误。
看起来我正试图在内存中组装一个巨大的结构。我无法以任何其他方式重写此代码。
我已经使用java in hadoop
实现了类似的逻辑,如下所示。
for (String fromValue : fromAssetVals) {
fromEntity = fromValue.split(":")[0];
fromAttr = fromValue.split(":")[1];
for (String toValue : toAssetVals) {
toEntity = toValue.split(":")[0];
toAttr = toValue.split(":")[1];
oKey = new Text(fromEntity.trim() + ":" + toEntity.trim());
oValue = new Text(fromAttr + ":" + toAttr);
outputCollector.collect(oKey, oValue);
}
}
但是当我在spark中尝试类似的东西时,我会得到嵌套的rdd异常。
如何使用spark using scala
高效执行此操作?
答案 0 :(得分:2)
好吧,如果笛卡尔产品是唯一的选择,你至少可以让它变得更加懒惰:
inRDD.flatMap { case (xs, ys) =>
xs.toIterator.flatMap(x => ys.toIterator.map(y => (x, y)))
}
您也可以在Spark级别处理此问题
import org.apache.spark.RangePartitioner
val indexed = inRDD.zipWithUniqueId.map(_.swap)
val partitioner = new RangePartitioner(indexed.partitions.size, indexed)
val partitioned = indexed.partitionBy(partitioner)
val lefts = partitioned.flatMapValues(_._1)
val rights = partitioned.flatMapValues(_._2)
lefts.join(rights).values