按特定顺序合并多个RDD

时间:2017-08-16 15:36:04

标签: scala apache-spark rdd seq

我正在尝试以特定顺序将多个字符串RDD合并到行的RDD中。我尝试创建Map[String, RDD[Seq[String]]](其中Seq只包含一个元素),然后将它们合并到RDD[Row[String]],但它似乎不起作用(内容为{{ 1}}迷路了......有人有任何想法吗?

RDD[Seq[String]]

编辑: 使用zip函数会导致spark异常,因为我的RDD在每个分区中没有相同数量的元素。我不知道如何确保它们在每个分区中都具有相同数量的元素,因此我只是用索引对它们进行压缩,然后使用val t1: StructType val mapFields: Map[String, RDD[Seq[String]]] var ordRDD: RDD[Seq[String]] = context.emptyRDD t1.foreach(field => ordRDD = ordRDD ++ mapFiels(field.name)) val rdd = ordRDD.map(line => Row.fromSeq(line)) 以良好的顺序将它们连接起来。也许有一个关于ListMap函数的技巧,但我还不了解Spark API。

mapPartitions

1 个答案:

答案 0 :(得分:1)

这里的关键是使用RDD.zip来" zip" RDD在一起(创建一个RDD,其中每个记录是在ell RDD中具有相同索引的记录的组合):

import org.apache.spark.sql._
import org.apache.spark.sql.types._

// INPUT: Map does not preserve order (not the defaul implementation, at least) - using Seq
val rdds: Seq[(String, RDD[String])] = Seq(
  "field1" -> sc.parallelize(Seq("a", "b", "c")),
  "field2" -> sc.parallelize(Seq("1", "2", "3")),
  "field3" -> sc.parallelize(Seq("Q", "W", "E"))
)

// Use RDD.zip to zip all RDDs together, then convert to Rows
val rowRdd: RDD[Row] = rdds
  .map(_._2)
  .map(_.map(s => Seq(s)))
  .reduceLeft((rdd1, rdd2) => rdd1.zip(rdd2).map { case (l1, l2) => l1 ++ l2 })
  .map(Row.fromSeq)

// Create schema using the column names:
val schema: StructType = StructType(rdds.map(_._1).map(name => StructField(name, StringType)))

// Create DataFrame:
val result: DataFrame = spark.createDataFrame(rowRdd, schema)

result.show
// +------+------+------+
// |field1|field2|field3|
// +------+------+------+
// |     a|     1|     Q|
// |     b|     2|     W|
// |     c|     3|     E|
// +------+------+------+